Home | History | Annotate | Download | only in UefiDevicePathLib
      1 /*++
      2 
      3 Copyright (c) 2004 - 2006, 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 
     13 Module Name:
     14 
     15   UefiDevicePathLib.c
     16 
     17 Abstract:
     18 
     19   Device Path services. The thing to remember is device paths are built out of
     20   nodes. The device path is terminated by an end node that is length
     21   sizeof(EFI_DEVICE_PATH_PROTOCOL). That would be why there is sizeof(EFI_DEVICE_PATH_PROTOCOL)
     22   all over this file.
     23 
     24   The only place where multi-instance device paths are supported is in
     25   environment varibles. Multi-instance device paths should never be placed
     26   on a Handle.
     27 
     28 --*/
     29 
     30 #include "EdkIIGlueUefi.h"
     31 #include "Library/EdkIIGlueMemoryAllocationLib.h"
     32 
     33 /**
     34   Returns the size of a device path in bytes.
     35 
     36   This function returns the size, in bytes, of the device path data structure specified by
     37   DevicePath including the end of device path node.  If DevicePath is NULL, then 0 is returned.
     38 
     39   @param  DevicePath                 A pointer to a device path data structure.
     40 
     41   @return The size of a device path in bytes.
     42 
     43 **/
     44 UINTN
     45 EFIAPI
     46 GlueGetDevicePathSize (
     47   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath
     48   )
     49 {
     50   CONST EFI_DEVICE_PATH_PROTOCOL  *Start;
     51 
     52   if (DevicePath == NULL) {
     53     return 0;
     54   }
     55 
     56   //
     57   // Search for the end of the device path structure
     58   //
     59   Start = DevicePath;
     60   while (!EfiIsDevicePathEnd (DevicePath)) {
     61     DevicePath = EfiNextDevicePathNode (DevicePath);
     62   }
     63 
     64   //
     65   // Compute the size and add back in the size of the end device path structure
     66   //
     67   return ((UINTN) DevicePath - (UINTN) Start) + sizeof (EFI_DEVICE_PATH_PROTOCOL);
     68 }
     69 
     70 /**
     71   Creates a new device path by appending a second device path to a first device path.
     72 
     73   This function allocates space for a new copy of the device path specified by DevicePath.  If
     74   DevicePath is NULL, then NULL is returned.  If the memory is successfully allocated, then the
     75   contents of DevicePath are copied to the newly allocated buffer, and a pointer to that buffer
     76   is returned.  Otherwise, NULL is returned.
     77 
     78   @param  DevicePath                 A pointer to a device path data structure.
     79 
     80   @return A pointer to the duplicated device path.
     81 
     82 **/
     83 EFI_DEVICE_PATH_PROTOCOL *
     84 EFIAPI
     85 GlueDuplicateDevicePath (
     86   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath
     87   )
     88 {
     89   EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;
     90   UINTN                     Size;
     91 
     92   //
     93   // Compute the size
     94   //
     95   Size = GetDevicePathSize (DevicePath);
     96   if (Size == 0) {
     97     return NULL;
     98   }
     99 
    100   //
    101   // Allocate space for duplicate device path
    102   //
    103   NewDevicePath = AllocateCopyPool (Size, DevicePath);
    104 
    105   return NewDevicePath;
    106 }
    107 
    108 /**
    109   Creates a new device path by appending a second device path to a first device path.
    110 
    111   This function creates a new device path by appending a copy of SecondDevicePath to a copy of
    112   FirstDevicePath in a newly allocated buffer.  Only the end-of-device-path device node from
    113   SecondDevicePath is retained. The newly created device path is returned.
    114   If FirstDevicePath is NULL, then it is ignored, and a duplicate of SecondDevicePath is returned.
    115   If SecondDevicePath is NULL, then it is ignored, and a duplicate of FirstDevicePath is returned.
    116   If both FirstDevicePath and SecondDevicePath are NULL, then NULL is returned.
    117   If there is not enough memory for the newly allocated buffer, then NULL is returned.
    118   The memory for the new device path is allocated from EFI boot services memory. It is the
    119   responsibility of the caller to free the memory allocated.
    120 
    121   @param  FirstDevicePath            A pointer to a device path data structure.
    122   @param  SecondDevicePath           A pointer to a device path data structure.
    123 
    124   @return A pointer to the new device path.
    125 
    126 **/
    127 EFI_DEVICE_PATH_PROTOCOL *
    128 EFIAPI
    129 GlueAppendDevicePath (
    130   IN CONST EFI_DEVICE_PATH_PROTOCOL  *FirstDevicePath,  OPTIONAL
    131   IN CONST EFI_DEVICE_PATH_PROTOCOL  *SecondDevicePath  OPTIONAL
    132   )
    133 {
    134   UINTN                     Size;
    135   UINTN                     Size1;
    136   UINTN                     Size2;
    137   EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;
    138   EFI_DEVICE_PATH_PROTOCOL  *DevicePath2;
    139 
    140   //
    141   // If there's only 1 path, just duplicate it.
    142   //
    143   if (FirstDevicePath == NULL) {
    144     return DuplicateDevicePath (SecondDevicePath);
    145   }
    146 
    147   if (SecondDevicePath == NULL) {
    148     return DuplicateDevicePath (FirstDevicePath);
    149   }
    150 
    151   //
    152   // Allocate space for the combined device path. It only has one end node of
    153   // length EFI_DEVICE_PATH_PROTOCOL.
    154   //
    155   Size1         = GetDevicePathSize (FirstDevicePath);
    156   Size2         = GetDevicePathSize (SecondDevicePath);
    157   Size          = Size1 + Size2 - sizeof (EFI_DEVICE_PATH_PROTOCOL);
    158 
    159   NewDevicePath = AllocatePool (Size);
    160 
    161   if (NewDevicePath != NULL) {
    162     NewDevicePath = CopyMem (NewDevicePath, FirstDevicePath, Size1);
    163     //
    164     // Over write FirstDevicePath EndNode and do the copy
    165     //
    166     DevicePath2 = (EFI_DEVICE_PATH_PROTOCOL *) ((CHAR8 *) NewDevicePath +
    167                   (Size1 - sizeof (EFI_DEVICE_PATH_PROTOCOL)));
    168     CopyMem (DevicePath2, SecondDevicePath, Size2);
    169   }
    170 
    171   return NewDevicePath;
    172 }
    173 
    174 /**
    175   Creates a new path by appending the device node to the device path.
    176 
    177   This function creates a new device path by appending a copy of the device node specified by
    178   DevicePathNode to a copy of the device path specified by DevicePath in an allocated buffer.
    179   The end-of-device-path device node is moved after the end of the appended device node.
    180   If DevicePath is NULL, then NULL is returned.
    181   If DevicePathNode is NULL, then NULL is returned.
    182   If there is not enough memory to allocate space for the new device path, then NULL is returned.
    183   The memory is allocated from EFI boot services memory. It is the responsibility of the caller to
    184   free the memory allocated.
    185 
    186   @param  DevicePath                 A pointer to a device path data structure.
    187   @param  DevicePathNode             A pointer to a single device path node.
    188 
    189   @return A pointer to the new device path.
    190 
    191 **/
    192 EFI_DEVICE_PATH_PROTOCOL *
    193 EFIAPI
    194 GlueAppendDevicePathNode (
    195   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath,     OPTIONAL
    196   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePathNode  OPTIONAL
    197   )
    198 {
    199   EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;
    200   EFI_DEVICE_PATH_PROTOCOL  *NextNode;
    201   EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;
    202   UINTN                     NodeLength;
    203 
    204   if (DevicePath == NULL || DevicePathNode == NULL) {
    205     return NULL;
    206   }
    207   //
    208   // Build a Node that has a terminator on it
    209   //
    210   NodeLength = DevicePathNodeLength (DevicePathNode);
    211 
    212   TempDevicePath = AllocatePool (NodeLength + sizeof (EFI_DEVICE_PATH_PROTOCOL));
    213   if (TempDevicePath == NULL) {
    214     return NULL;
    215   }
    216   TempDevicePath = CopyMem (TempDevicePath, DevicePathNode, NodeLength);
    217   //
    218   // Add and end device path node to convert Node to device path
    219   //
    220   NextNode = NextDevicePathNode (TempDevicePath);
    221   SetDevicePathEndNode (NextNode);
    222   //
    223   // Append device paths
    224   //
    225   NewDevicePath = AppendDevicePath (DevicePath, TempDevicePath);
    226 
    227   FreePool (TempDevicePath);
    228 
    229   return NewDevicePath;
    230 }
    231 
    232 /**
    233   Creates a new device path by appending the specified device path instance to the specified device
    234   path.
    235 
    236   This function creates a new device path by appending a copy of the device path instance specified
    237   by DevicePathInstance to a copy of the device path secified by DevicePath in a allocated buffer.
    238   The end-of-device-path device node is moved after the end of the appended device path instance
    239   and a new end-of-device-path-instance node is inserted between.
    240   If DevicePath is NULL, then a copy if DevicePathInstance is returned.
    241   If DevicePathInstance is NULL, then NULL is returned.
    242   If there is not enough memory to allocate space for the new device path, then NULL is returned.
    243   The memory is allocated from EFI boot services memory. It is the responsibility of the caller to
    244   free the memory allocated.
    245 
    246   @param  DevicePath                 A pointer to a device path data structure.
    247   @param  DevicePathInstance         A pointer to a device path instance.
    248 
    249   @return A pointer to the new device path.
    250 
    251 **/
    252 EFI_DEVICE_PATH_PROTOCOL *
    253 EFIAPI
    254 GlueAppendDevicePathInstance (
    255   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath,        OPTIONAL
    256   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePathInstance OPTIONAL
    257   )
    258 {
    259   EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;
    260   EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;
    261   UINTN                     SrcSize;
    262   UINTN                     InstanceSize;
    263 
    264   if (DevicePath == NULL) {
    265     return DuplicateDevicePath (DevicePathInstance);
    266   }
    267 
    268   if (DevicePathInstance == NULL) {
    269     return NULL;
    270   }
    271 
    272   SrcSize       = GetDevicePathSize (DevicePath);
    273   InstanceSize  = GetDevicePathSize (DevicePathInstance);
    274 
    275   NewDevicePath = AllocatePool (SrcSize + InstanceSize);
    276   if (NewDevicePath != NULL) {
    277 
    278     TempDevicePath = CopyMem (NewDevicePath, DevicePath, SrcSize);;
    279 
    280     while (!IsDevicePathEnd (TempDevicePath)) {
    281       TempDevicePath = NextDevicePathNode (TempDevicePath);
    282     }
    283 
    284     TempDevicePath->SubType  = END_INSTANCE_DEVICE_PATH_SUBTYPE;
    285     TempDevicePath           = NextDevicePathNode (TempDevicePath);
    286     CopyMem (TempDevicePath, DevicePathInstance, InstanceSize);
    287   }
    288 
    289   return NewDevicePath;
    290 }
    291 
    292 /**
    293   Creates a copy of the current device path instance and returns a pointer to the next device path
    294   instance.
    295 
    296   This function creates a copy of the current device path instance. It also updates DevicePath to
    297   point to the next device path instance in the device path (or NULL if no more) and updates Size
    298   to hold the size of the device path instance copy.
    299   If DevicePath is NULL, then NULL is returned.
    300   If there is not enough memory to allocate space for the new device path, then NULL is returned.
    301   The memory is allocated from EFI boot services memory. It is the responsibility of the caller to
    302   free the memory allocated.
    303   If Size is NULL, then ASSERT().
    304 
    305   @param  DevicePath                 On input, this holds the pointer to the current device path
    306                                      instance. On output, this holds the pointer to the next device
    307                                      path instance or NULL if there are no more device path
    308                                      instances in the device path pointer to a device path data
    309                                      structure.
    310   @param  Size                       On output, this holds the size of the device path instance, in
    311                                      bytes or zero, if DevicePath is NULL.
    312 
    313   @return A pointer to the current device path instance.
    314 
    315 **/
    316 EFI_DEVICE_PATH_PROTOCOL *
    317 EFIAPI
    318 GlueGetNextDevicePathInstance (
    319   IN OUT EFI_DEVICE_PATH_PROTOCOL    **DevicePath,
    320   OUT UINTN                          *Size
    321   )
    322 {
    323   EFI_DEVICE_PATH_PROTOCOL  *DevPath;
    324   EFI_DEVICE_PATH_PROTOCOL  *ReturnValue;
    325   UINT8                     Temp;
    326 
    327   ASSERT (Size != NULL);
    328 
    329   if (DevicePath == NULL || *DevicePath == NULL) {
    330     *Size = 0;
    331     return NULL;
    332   }
    333 
    334   //
    335   // Find the end of the device path instance
    336   //
    337   DevPath = *DevicePath;
    338   while (!IsDevicePathEndType (DevPath)) {
    339     DevPath = NextDevicePathNode (DevPath);
    340   }
    341 
    342   //
    343   // Compute the size of the device path instance
    344   //
    345   *Size = ((UINTN) DevPath - (UINTN) (*DevicePath)) + sizeof (EFI_DEVICE_PATH_PROTOCOL);
    346 
    347   //
    348   // Make a copy and return the device path instance
    349   //
    350   Temp              = DevPath->SubType;
    351   DevPath->SubType  = END_ENTIRE_DEVICE_PATH_SUBTYPE;
    352   ReturnValue       = DuplicateDevicePath (*DevicePath);
    353   DevPath->SubType  = Temp;
    354 
    355   //
    356   // If DevPath is the end of an entire device path, then another instance
    357   // does not follow, so *DevicePath is set to NULL.
    358   //
    359   if (DevicePathSubType (DevPath) == END_ENTIRE_DEVICE_PATH_SUBTYPE) {
    360     *DevicePath = NULL;
    361   } else {
    362     *DevicePath = NextDevicePathNode (DevPath);
    363   }
    364 
    365   return ReturnValue;
    366 }
    367 
    368 /**
    369   Creates a copy of the current device path instance and returns a pointer to the next device path
    370   instance.
    371 
    372   This function creates a new device node in a newly allocated buffer of size NodeLength and
    373   initializes the device path node header with NodeType and NodeSubType.  The new device path node
    374   is returned.
    375   If NodeLength is smaller than a device path header, then NULL is returned.
    376   If there is not enough memory to allocate space for the new device path, then NULL is returned.
    377   The memory is allocated from EFI boot services memory. It is the responsibility of the caller to
    378   free the memory allocated.
    379 
    380   @param  NodeType                   The device node type for the new device node.
    381   @param  NodeSubType                The device node sub-type for the new device node.
    382   @param  NodeLength                 The length of the new device node.
    383 
    384   @return The new device path.
    385 
    386 **/
    387 EFI_DEVICE_PATH_PROTOCOL *
    388 EFIAPI
    389 CreateDeviceNode (
    390   IN UINT8                           NodeType,
    391   IN UINT8                           NodeSubType,
    392   IN UINT16                          NodeLength
    393   )
    394 {
    395   EFI_DEVICE_PATH_PROTOCOL      *DevicePath;
    396 
    397   if (NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
    398     //
    399     // NodeLength is less than the size of the header.
    400     //
    401     return NULL;
    402   }
    403 
    404   DevicePath = AllocatePool (NodeLength);
    405   if (DevicePath != NULL) {
    406      DevicePath->Type    = NodeType;
    407      DevicePath->SubType = NodeSubType;
    408      SetDevicePathNodeLength (DevicePath, NodeLength);
    409   }
    410 
    411   return DevicePath;
    412 }
    413 
    414 /**
    415   Determines if a device path is single or multi-instance.
    416 
    417   This function returns TRUE if the device path specified by DevicePath is multi-instance.
    418   Otherwise, FALSE is returned.  If DevicePath is NULL, then FALSE is returned.
    419 
    420   @param  DevicePath                 A pointer to a device path data structure.
    421 
    422   @retval  TRUE                      DevicePath is multi-instance.
    423   @retval  FALSE                     DevicePath is not multi-instance or DevicePath is NULL.
    424 
    425 **/
    426 BOOLEAN
    427 EFIAPI
    428 GlueIsDevicePathMultiInstance (
    429   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath
    430   )
    431 {
    432   CONST EFI_DEVICE_PATH_PROTOCOL     *Node;
    433 
    434   if (DevicePath == NULL) {
    435     return FALSE;
    436   }
    437 
    438   Node = DevicePath;
    439   while (!EfiIsDevicePathEnd (Node)) {
    440     if (EfiIsDevicePathEndInstance (Node)) {
    441       return TRUE;
    442     }
    443 
    444     Node = EfiNextDevicePathNode (Node);
    445   }
    446 
    447   return FALSE;
    448 }
    449 
    450 
    451 /**
    452   Retrieves the device path protocol from a handle.
    453 
    454   This function returns the device path protocol from the handle specified by Handle.  If Handle is
    455   NULL or Handle does not contain a device path protocol, then NULL is returned.
    456 
    457   @param  Handle                     The handle from which to retrieve the device path protocol.
    458 
    459   @return The device path protocol from the handle specified by Handle.
    460 
    461 **/
    462 EFI_DEVICE_PATH_PROTOCOL *
    463 EFIAPI
    464 GlueDevicePathFromHandle (
    465   IN EFI_HANDLE                      Handle
    466   )
    467 {
    468   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
    469   EFI_STATUS                Status;
    470 
    471   Status = gBS->HandleProtocol (
    472                   Handle,
    473                   &gEfiDevicePathProtocolGuid,
    474                   (VOID *) &DevicePath
    475                   );
    476   if (EFI_ERROR (Status)) {
    477     DevicePath = NULL;
    478   }
    479   return DevicePath;
    480 }
    481 
    482 /**
    483   Allocates a device path for a file and appends it to an existing device path.
    484 
    485   If Device is a valid device handle that contains a device path protocol, then a device path for
    486   the file specified by FileName  is allocated and appended to the device path associated with the
    487   handle Device.  The allocated device path is returned.  If Device is NULL or Device is a handle
    488   that does not support the device path protocol, then a device path containing a single device
    489   path node for the file specified by FileName is allocated and returned.
    490   If FileName is NULL, then ASSERT().
    491 
    492   @param  Device                     A pointer to a device handle.  This parameter is optional and
    493                                      may be NULL.
    494   @param  FileName                   A pointer to a Null-terminated Unicode string.
    495 
    496   @return The allocated device path.
    497 
    498 **/
    499 EFI_DEVICE_PATH_PROTOCOL *
    500 EFIAPI
    501 GlueFileDevicePath (
    502   IN EFI_HANDLE                      Device,     OPTIONAL
    503   IN CONST CHAR16                    *FileName
    504   )
    505 {
    506   UINTN                     Size;
    507   FILEPATH_DEVICE_PATH      *FilePath;
    508   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
    509   EFI_DEVICE_PATH_PROTOCOL  *FileDevicePath;
    510 
    511   DevicePath = NULL;
    512 
    513   Size = StrSize (FileName);
    514   FileDevicePath = AllocatePool (Size + SIZE_OF_FILEPATH_DEVICE_PATH + EFI_END_DEVICE_PATH_LENGTH);
    515   if (FileDevicePath != NULL) {
    516     FilePath = (FILEPATH_DEVICE_PATH *) FileDevicePath;
    517     FilePath->Header.Type    = MEDIA_DEVICE_PATH;
    518     FilePath->Header.SubType = MEDIA_FILEPATH_DP;
    519     CopyMem (&FilePath->PathName, FileName, Size);
    520     SetDevicePathNodeLength (&FilePath->Header, Size + SIZE_OF_FILEPATH_DEVICE_PATH);
    521     SetDevicePathEndNode (NextDevicePathNode (&FilePath->Header));
    522 
    523     if (Device != NULL) {
    524       DevicePath = DevicePathFromHandle (Device);
    525     }
    526 
    527     DevicePath = AppendDevicePath (DevicePath, FileDevicePath);
    528     FreePool (FileDevicePath);
    529   }
    530 
    531   return DevicePath;
    532 }
    533 
    534