Home | History | Annotate | Download | only in EfiDriverLib
      1 /*++
      2 
      3 Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
      4 This program and the accompanying materials
      5 are licensed and made available under the terms and conditions of the BSD License
      6 which accompanies this distribution.  The full text of the license may be found at
      7 http://opensource.org/licenses/bsd-license.php
      8 
      9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     11 
     12 Module Name:
     13 
     14   DevicePath.c
     15 
     16 Abstract:
     17 
     18   Device Path services. The thing to remember is device paths are built out of
     19   nodes. The device path is terminated by an end node that is length
     20   sizeof(EFI_DEVICE_PATH_PROTOCOL). That would be why there is sizeof(EFI_DEVICE_PATH_PROTOCOL)
     21   all over this file.
     22 
     23   The only place where multi-instance device paths are supported is in
     24   environment varibles. Multi-instance device paths should never be placed
     25   on a Handle.
     26 
     27 --*/
     28 
     29 #include "Tiano.h"
     30 #include "EfiDriverLib.h"
     31 #include EFI_PROTOCOL_DEFINITION (DevicePath)
     32 
     33 EFI_DEVICE_PATH_PROTOCOL *
     34 EfiDevicePathInstance (
     35   IN OUT EFI_DEVICE_PATH_PROTOCOL   **DevicePath,
     36   OUT UINTN                         *Size
     37   )
     38 /*++
     39 
     40 Routine Description:
     41   Function retrieves the next device path instance from a device path data structure.
     42 
     43 Arguments:
     44   DevicePath           - A pointer to a device path data structure.
     45 
     46   Size                 - A pointer to the size of a device path instance in bytes.
     47 
     48 Returns:
     49 
     50   This function returns a pointer to the current device path instance.
     51   In addition, it returns the size in bytes of the current device path instance in Size,
     52   and a pointer to the next device path instance in DevicePath.
     53   If there are no more device path instances in DevicePath, then DevicePath will be set to NULL.
     54 
     55 --*/
     56 {
     57   EFI_DEVICE_PATH_PROTOCOL  *DevPath;
     58   EFI_DEVICE_PATH_PROTOCOL  *ReturnValue;
     59   UINT8                     Temp;
     60 
     61   if (*DevicePath == NULL) {
     62     if (Size != NULL) {
     63       *Size = 0;
     64     }
     65 
     66     return NULL;
     67   }
     68 
     69   //
     70   // Find the end of the device path instance
     71   //
     72   DevPath = *DevicePath;
     73   while (!IsDevicePathEndType (DevPath)) {
     74     DevPath = NextDevicePathNode (DevPath);
     75   }
     76 
     77   //
     78   // Compute the size of the device path instance
     79   //
     80   if (Size != NULL) {
     81     *Size = ((UINTN) DevPath - (UINTN) (*DevicePath)) + sizeof (EFI_DEVICE_PATH_PROTOCOL);
     82   }
     83 
     84   //
     85   // Make a copy and return the device path instance
     86   //
     87   Temp              = DevPath->SubType;
     88   DevPath->SubType  = END_ENTIRE_DEVICE_PATH_SUBTYPE;
     89   ReturnValue       = EfiDuplicateDevicePath (*DevicePath);
     90   DevPath->SubType  = Temp;
     91 
     92   //
     93   // If DevPath is the end of an entire device path, then another instance
     94   // does not follow, so *DevicePath is set to NULL.
     95   //
     96   if (DevicePathSubType (DevPath) == END_ENTIRE_DEVICE_PATH_SUBTYPE) {
     97     *DevicePath = NULL;
     98   } else {
     99     *DevicePath = NextDevicePathNode (DevPath);
    100   }
    101 
    102   return ReturnValue;
    103 }
    104 
    105 BOOLEAN
    106 EfiIsDevicePathMultiInstance (
    107   IN EFI_DEVICE_PATH_PROTOCOL  *DevicePath
    108   )
    109 /*++
    110 
    111 Routine Description:
    112   Return TRUE is this is a multi instance device path.
    113 
    114 Arguments:
    115   DevicePath  - A pointer to a device path data structure.
    116 
    117 
    118 Returns:
    119   TRUE - If DevicePath is multi instance. FALSE - If DevicePath is not multi
    120   instance.
    121 
    122 --*/
    123 {
    124   EFI_DEVICE_PATH_PROTOCOL  *Node;
    125 
    126   if (DevicePath == NULL) {
    127     return FALSE;
    128   }
    129 
    130   Node = DevicePath;
    131   while (!EfiIsDevicePathEnd (Node)) {
    132     if (EfiIsDevicePathEndInstance (Node)) {
    133       return TRUE;
    134     }
    135 
    136     Node = EfiNextDevicePathNode (Node);
    137   }
    138 
    139   return FALSE;
    140 }
    141 
    142 UINTN
    143 EfiDevicePathSize (
    144   IN EFI_DEVICE_PATH_PROTOCOL  *DevicePath
    145   )
    146 /*++
    147 
    148 Routine Description:
    149 
    150   Calculate the space size of a device path.
    151 
    152 Arguments:
    153 
    154   DevicePath  - A specified device path
    155 
    156 Returns:
    157 
    158   The size.
    159 
    160 --*/
    161 {
    162   EFI_DEVICE_PATH_PROTOCOL  *Start;
    163 
    164   if (DevicePath == NULL) {
    165     return 0;
    166   }
    167 
    168   //
    169   // Search for the end of the device path structure
    170   //
    171   Start = DevicePath;
    172   while (!EfiIsDevicePathEnd (DevicePath)) {
    173     DevicePath = EfiNextDevicePathNode (DevicePath);
    174   }
    175 
    176   //
    177   // Compute the size and add back in the size of the end device path structure
    178   //
    179   return ((UINTN) DevicePath - (UINTN) Start) + sizeof (EFI_DEVICE_PATH_PROTOCOL);
    180 }
    181 
    182 EFI_DEVICE_PATH_PROTOCOL *
    183 EfiDevicePathFromHandle (
    184   IN EFI_HANDLE  Handle
    185   )
    186 /*++
    187 
    188 Routine Description:
    189 
    190   Get the device path protocol interface installed on a specified handle.
    191 
    192 Arguments:
    193 
    194   Handle  - a specified handle
    195 
    196 Returns:
    197 
    198   The device path protocol interface installed on that handle.
    199 
    200 --*/
    201 {
    202   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
    203 
    204   DevicePath = NULL;
    205   gBS->HandleProtocol (
    206         Handle,
    207         &gEfiDevicePathProtocolGuid,
    208         (VOID *) &DevicePath
    209         );
    210   return DevicePath;
    211 }
    212 
    213 EFI_DEVICE_PATH_PROTOCOL *
    214 EfiDuplicateDevicePath (
    215   IN EFI_DEVICE_PATH_PROTOCOL   *DevicePath
    216   )
    217 /*++
    218 
    219 Routine Description:
    220 
    221   Duplicate a device path structure.
    222 
    223 Arguments:
    224 
    225   DevicePath  - The device path to duplicated.
    226 
    227 Returns:
    228 
    229   The duplicated device path.
    230 
    231 --*/
    232 {
    233   EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;
    234   UINTN                     Size;
    235 
    236   if (DevicePath == NULL) {
    237     return NULL;
    238   }
    239 
    240   //
    241   // Compute the size
    242   //
    243   Size = EfiDevicePathSize (DevicePath);
    244   if (Size == 0) {
    245     return NULL;
    246   }
    247 
    248   //
    249   // Allocate space for duplicate device path
    250   //
    251   NewDevicePath = EfiLibAllocateCopyPool (Size, DevicePath);
    252 
    253   return NewDevicePath;
    254 }
    255 
    256 EFI_DEVICE_PATH_PROTOCOL *
    257 EfiAppendDevicePath (
    258   IN EFI_DEVICE_PATH_PROTOCOL  *Src1,
    259   IN EFI_DEVICE_PATH_PROTOCOL  *Src2
    260   )
    261 /*++
    262 
    263 Routine Description:
    264   Function is used to append a Src1 and Src2 together.
    265 
    266 Arguments:
    267   Src1  - A pointer to a device path data structure.
    268 
    269   Src2  - A pointer to a device path data structure.
    270 
    271 Returns:
    272 
    273   A pointer to the new device path is returned.
    274   NULL is returned if space for the new device path could not be allocated from pool.
    275   It is up to the caller to free the memory used by Src1 and Src2 if they are no longer needed.
    276 
    277 --*/
    278 {
    279   UINTN                     Size;
    280   UINTN                     Size1;
    281   UINTN                     Size2;
    282   EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;
    283   EFI_DEVICE_PATH_PROTOCOL  *SecondDevicePath;
    284 
    285   //
    286   // If there's only 1 path, just duplicate it
    287   //
    288   if (!Src1) {
    289     ASSERT (!IsDevicePathUnpacked (Src2));
    290     return EfiDuplicateDevicePath (Src2);
    291   }
    292 
    293   if (!Src2) {
    294     ASSERT (!IsDevicePathUnpacked (Src1));
    295     return EfiDuplicateDevicePath (Src1);
    296   }
    297 
    298   //
    299   // Allocate space for the combined device path. It only has one end node of
    300   // length EFI_DEVICE_PATH_PROTOCOL
    301   //
    302   Size1         = EfiDevicePathSize (Src1);
    303   Size2         = EfiDevicePathSize (Src2);
    304   Size          = Size1 + Size2 - sizeof (EFI_DEVICE_PATH_PROTOCOL);
    305 
    306   NewDevicePath = EfiLibAllocateCopyPool (Size, Src1);
    307 
    308   if (NewDevicePath != NULL) {
    309 
    310     //
    311     // Over write Src1 EndNode and do the copy
    312     //
    313     SecondDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) ((CHAR8 *) NewDevicePath + (Size1 - sizeof (EFI_DEVICE_PATH_PROTOCOL)));
    314     EfiCopyMem (SecondDevicePath, Src2, Size2);
    315   }
    316 
    317   return NewDevicePath;
    318 }
    319 
    320 EFI_DEVICE_PATH_PROTOCOL *
    321 EfiAppendDevicePathNode (
    322   IN EFI_DEVICE_PATH_PROTOCOL  *Src1,
    323   IN EFI_DEVICE_PATH_PROTOCOL  *Node
    324   )
    325 /*++
    326 
    327 Routine Description:
    328   Function is used to append a device path node to the end of another device path.
    329 
    330 Arguments:
    331   Src1  - A pointer to a device path data structure.
    332 
    333   Node - A pointer to a device path data structure.
    334 
    335 Returns:
    336   This function returns a pointer to the new device path.
    337   If there is not enough temporary pool memory available to complete this function,
    338   then NULL is returned.
    339 
    340 
    341 --*/
    342 {
    343   EFI_DEVICE_PATH_PROTOCOL  *Temp;
    344   EFI_DEVICE_PATH_PROTOCOL  *NextNode;
    345   EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;
    346   UINTN                     NodeLength;
    347 
    348   //
    349   // Build a Node that has a terminator on it
    350   //
    351   NodeLength  = DevicePathNodeLength (Node);
    352 
    353   Temp        = EfiLibAllocateCopyPool (NodeLength + sizeof (EFI_DEVICE_PATH_PROTOCOL), Node);
    354   if (Temp == NULL) {
    355     return NULL;
    356   }
    357 
    358   //
    359   // Add and end device path node to convert Node to device path
    360   //
    361   NextNode = NextDevicePathNode (Temp);
    362   SetDevicePathEndNode (NextNode);
    363 
    364   //
    365   // Append device paths
    366   //
    367   NewDevicePath = EfiAppendDevicePath (Src1, Temp);
    368   gBS->FreePool (Temp);
    369   return NewDevicePath;
    370 }
    371 
    372 EFI_DEVICE_PATH_PROTOCOL *
    373 EfiFileDevicePath (
    374   IN EFI_HANDLE               Device  OPTIONAL,
    375   IN CHAR16                   *FileName
    376   )
    377 /*++
    378 
    379 Routine Description:
    380 
    381   This function allocates a device path for a file and appends it to an existiong
    382   device path.
    383 
    384 Arguments:
    385   Device     - A pointer to a device handle.
    386 
    387   FileName   - A pointer to a Null-terminated Unicodestring.
    388 
    389 Returns:
    390   A device path contain the file name.
    391 
    392 --*/
    393 {
    394   UINTN                     Size;
    395   FILEPATH_DEVICE_PATH      *FilePath;
    396   EFI_DEVICE_PATH_PROTOCOL  *Eop;
    397   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
    398 
    399   for (Size = 0; FileName[Size] != 0; Size++)
    400     ;
    401   Size        = (Size + 1) * 2;
    402 
    403   FilePath    = EfiLibAllocateZeroPool (Size + SIZE_OF_FILEPATH_DEVICE_PATH + sizeof (EFI_DEVICE_PATH_PROTOCOL));
    404 
    405   DevicePath  = NULL;
    406 
    407   if (FilePath != NULL) {
    408 
    409     //
    410     // Build a file path
    411     //
    412     FilePath->Header.Type     = MEDIA_DEVICE_PATH;
    413     FilePath->Header.SubType  = MEDIA_FILEPATH_DP;
    414     SetDevicePathNodeLength (&FilePath->Header, Size + SIZE_OF_FILEPATH_DEVICE_PATH);
    415     EfiCopyMem (FilePath->PathName, FileName, Size);
    416     Eop = NextDevicePathNode (&FilePath->Header);
    417     SetDevicePathEndNode (Eop);
    418 
    419     //
    420     // Append file path to device's device path
    421     //
    422 
    423     DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) FilePath;
    424     if (Device != NULL) {
    425       DevicePath = EfiAppendDevicePath (
    426                     EfiDevicePathFromHandle (Device),
    427                     DevicePath
    428                     );
    429 
    430       gBS->FreePool (FilePath);
    431     }
    432   }
    433 
    434   return DevicePath;
    435 }
    436 
    437 EFI_DEVICE_PATH_PROTOCOL *
    438 EfiAppendDevicePathInstance (
    439   IN EFI_DEVICE_PATH_PROTOCOL  *Src,
    440   IN EFI_DEVICE_PATH_PROTOCOL  *Instance
    441   )
    442 /*++
    443 
    444 Routine Description:
    445 
    446   Append a device path instance to another.
    447 
    448 Arguments:
    449 
    450   Src       - The device path instance to be appended with.
    451   Instance  - The device path instance appending the other.
    452 
    453 Returns:
    454 
    455   The contaction of these two.
    456 
    457 --*/
    458 {
    459   UINT8                     *Ptr;
    460   EFI_DEVICE_PATH_PROTOCOL  *DevPath;
    461   UINTN                     SrcSize;
    462   UINTN                     InstanceSize;
    463 
    464   if (Src == NULL) {
    465     return EfiDuplicateDevicePath (Instance);
    466   }
    467 
    468   SrcSize       = EfiDevicePathSize (Src);
    469   InstanceSize  = EfiDevicePathSize (Instance);
    470 
    471   Ptr           = EfiLibAllocateCopyPool (SrcSize + InstanceSize, Src);
    472   if (Ptr != NULL) {
    473 
    474     DevPath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
    475 
    476     while (!IsDevicePathEnd (DevPath)) {
    477       DevPath = NextDevicePathNode (DevPath);
    478     }
    479     //
    480     // Convert the End to an End Instance, since we are
    481     //  appending another instacne after this one its a good
    482     //  idea.
    483     //
    484     DevPath->SubType  = END_INSTANCE_DEVICE_PATH_SUBTYPE;
    485 
    486     DevPath           = NextDevicePathNode (DevPath);
    487     EfiCopyMem (DevPath, Instance, InstanceSize);
    488   }
    489 
    490   return (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
    491 }
    492 
    493 VOID
    494 EFIAPI
    495 EfiInitializeFwVolDevicepathNode (
    496   IN  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH     *FvDevicePathNode,
    497   IN EFI_GUID                               *NameGuid
    498   )
    499 /*++
    500 
    501 Routine Description:
    502 
    503   Initialize a Firmware Volume (FV) Media Device Path node.
    504 
    505 Arguments:
    506 
    507   FvDevicePathNode  - Pointer to a FV device path node to initialize
    508   NameGuid          - FV file name to use in FvDevicePathNode
    509 
    510 Returns:
    511 
    512   None
    513 
    514 --*/
    515 {
    516   FvDevicePathNode->Header.Type     = MEDIA_DEVICE_PATH;
    517   FvDevicePathNode->Header.SubType  = MEDIA_FV_FILEPATH_DP;
    518   SetDevicePathNodeLength (&FvDevicePathNode->Header, sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH));
    519 
    520   EfiCopyMem (&FvDevicePathNode->NameGuid, NameGuid, sizeof(EFI_GUID));
    521 }
    522 
    523 EFI_GUID *
    524 EFIAPI
    525 EfiGetNameGuidFromFwVolDevicePathNode (
    526   IN  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH   *FvDevicePathNode
    527   )
    528 /*++
    529 
    530 Routine Description:
    531 
    532   Check to see if the Firmware Volume (FV) Media Device Path is valid.
    533 
    534 Arguments:
    535 
    536   FvDevicePathNode  - Pointer to FV device path to check
    537 
    538 Returns:
    539 
    540   NULL              - FvDevicePathNode is not valid.
    541   Other             - FvDevicePathNode is valid and pointer to NameGuid was returned.
    542 
    543 --*/
    544 {
    545   if (DevicePathType (&FvDevicePathNode->Header) == MEDIA_DEVICE_PATH &&
    546       DevicePathSubType (&FvDevicePathNode->Header) == MEDIA_FV_FILEPATH_DP) {
    547     return &FvDevicePathNode->NameGuid;
    548   }
    549 
    550   return NULL;
    551 }
    552