Home | History | Annotate | Download | only in UefiDevicePathLib
      1 /** @file
      2   Device Path services. The thing to remember is device paths are built out of
      3   nodes. The device path is terminated by an end node that is length
      4   sizeof(EFI_DEVICE_PATH_PROTOCOL). That would be why there is sizeof(EFI_DEVICE_PATH_PROTOCOL)
      5   all over this file.
      6 
      7   The only place where multi-instance device paths are supported is in
      8   environment varibles. Multi-instance device paths should never be placed
      9   on a Handle.
     10 
     11   Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
     12   This program and the accompanying materials
     13   are licensed and made available under the terms and conditions of the BSD License
     14   which accompanies this distribution.  The full text of the license may be found at
     15   http://opensource.org/licenses/bsd-license.php.
     16 
     17   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     18   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     19 
     20 **/
     21 
     22 #include "UefiDevicePathLib.h"
     23 
     24 //
     25 // Template for an end-of-device path node.
     26 //
     27 GLOBAL_REMOVE_IF_UNREFERENCED CONST EFI_DEVICE_PATH_PROTOCOL  mUefiDevicePathLibEndDevicePath = {
     28   END_DEVICE_PATH_TYPE,
     29   END_ENTIRE_DEVICE_PATH_SUBTYPE,
     30   {
     31     END_DEVICE_PATH_LENGTH,
     32     0
     33   }
     34 };
     35 
     36 /**
     37   Determine whether a given device path is valid.
     38   If DevicePath is NULL, then ASSERT().
     39 
     40   @param  DevicePath  A pointer to a device path data structure.
     41   @param  MaxSize     The maximum size of the device path data structure.
     42 
     43   @retval TRUE        DevicePath is valid.
     44   @retval FALSE       The length of any node node in the DevicePath is less
     45                       than sizeof (EFI_DEVICE_PATH_PROTOCOL).
     46   @retval FALSE       If MaxSize is not zero, the size of the DevicePath
     47                       exceeds MaxSize.
     48   @retval FALSE       If PcdMaximumDevicePathNodeCount is not zero, the node
     49                       count of the DevicePath exceeds PcdMaximumDevicePathNodeCount.
     50 **/
     51 BOOLEAN
     52 EFIAPI
     53 IsDevicePathValid (
     54   IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
     55   IN       UINTN                    MaxSize
     56   )
     57 {
     58   UINTN Count;
     59   UINTN Size;
     60   UINTN NodeLength;
     61 
     62   ASSERT (DevicePath != NULL);
     63 
     64   for (Count = 0, Size = 0; !IsDevicePathEnd (DevicePath); DevicePath = NextDevicePathNode (DevicePath)) {
     65     NodeLength = DevicePathNodeLength (DevicePath);
     66     if (NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
     67       return FALSE;
     68     }
     69 
     70     if (MaxSize > 0) {
     71       Size += NodeLength;
     72       if (Size + END_DEVICE_PATH_LENGTH > MaxSize) {
     73         return FALSE;
     74       }
     75     }
     76 
     77     if (PcdGet32 (PcdMaximumDevicePathNodeCount) > 0) {
     78       Count++;
     79       if (Count >= PcdGet32 (PcdMaximumDevicePathNodeCount)) {
     80         return FALSE;
     81       }
     82     }
     83   }
     84 
     85   //
     86   // Only return TRUE when the End Device Path node is valid.
     87   //
     88   return (BOOLEAN) (DevicePathNodeLength (DevicePath) == END_DEVICE_PATH_LENGTH);
     89 }
     90 
     91 /**
     92   Returns the Type field of a device path node.
     93 
     94   Returns the Type field of the device path node specified by Node.
     95 
     96   If Node is NULL, then ASSERT().
     97 
     98   @param  Node      A pointer to a device path node data structure.
     99 
    100   @return The Type field of the device path node specified by Node.
    101 
    102 **/
    103 UINT8
    104 EFIAPI
    105 DevicePathType (
    106   IN CONST VOID  *Node
    107   )
    108 {
    109   ASSERT (Node != NULL);
    110   return ((EFI_DEVICE_PATH_PROTOCOL *)(Node))->Type;
    111 }
    112 
    113 /**
    114   Returns the SubType field of a device path node.
    115 
    116   Returns the SubType field of the device path node specified by Node.
    117 
    118   If Node is NULL, then ASSERT().
    119 
    120   @param  Node      A pointer to a device path node data structure.
    121 
    122   @return The SubType field of the device path node specified by Node.
    123 
    124 **/
    125 UINT8
    126 EFIAPI
    127 DevicePathSubType (
    128   IN CONST VOID  *Node
    129   )
    130 {
    131   ASSERT (Node != NULL);
    132   return ((EFI_DEVICE_PATH_PROTOCOL *)(Node))->SubType;
    133 }
    134 
    135 /**
    136   Returns the 16-bit Length field of a device path node.
    137 
    138   Returns the 16-bit Length field of the device path node specified by Node.
    139   Node is not required to be aligned on a 16-bit boundary, so it is recommended
    140   that a function such as ReadUnaligned16() be used to extract the contents of
    141   the Length field.
    142 
    143   If Node is NULL, then ASSERT().
    144 
    145   @param  Node      A pointer to a device path node data structure.
    146 
    147   @return The 16-bit Length field of the device path node specified by Node.
    148 
    149 **/
    150 UINTN
    151 EFIAPI
    152 DevicePathNodeLength (
    153   IN CONST VOID  *Node
    154   )
    155 {
    156   ASSERT (Node != NULL);
    157   return ReadUnaligned16 ((UINT16 *)&((EFI_DEVICE_PATH_PROTOCOL *)(Node))->Length[0]);
    158 }
    159 
    160 /**
    161   Returns a pointer to the next node in a device path.
    162 
    163   Returns a pointer to the device path node that follows the device path node
    164   specified by Node.
    165 
    166   If Node is NULL, then ASSERT().
    167 
    168   @param  Node      A pointer to a device path node data structure.
    169 
    170   @return a pointer to the device path node that follows the device path node
    171   specified by Node.
    172 
    173 **/
    174 EFI_DEVICE_PATH_PROTOCOL *
    175 EFIAPI
    176 NextDevicePathNode (
    177   IN CONST VOID  *Node
    178   )
    179 {
    180   ASSERT (Node != NULL);
    181   return (EFI_DEVICE_PATH_PROTOCOL *)((UINT8 *)(Node) + DevicePathNodeLength(Node));
    182 }
    183 
    184 /**
    185   Determines if a device path node is an end node of a device path.
    186   This includes nodes that are the end of a device path instance and nodes that
    187   are the end of an entire device path.
    188 
    189   Determines if the device path node specified by Node is an end node of a device path.
    190   This includes nodes that are the end of a device path instance and nodes that are the
    191   end of an entire device path.  If Node represents an end node of a device path,
    192   then TRUE is returned.  Otherwise, FALSE is returned.
    193 
    194   If Node is NULL, then ASSERT().
    195 
    196   @param  Node      A pointer to a device path node data structure.
    197 
    198   @retval TRUE      The device path node specified by Node is an end node of a
    199                     device path.
    200   @retval FALSE     The device path node specified by Node is not an end node of
    201                     a device path.
    202 
    203 **/
    204 BOOLEAN
    205 EFIAPI
    206 IsDevicePathEndType (
    207   IN CONST VOID  *Node
    208   )
    209 {
    210   ASSERT (Node != NULL);
    211   return (BOOLEAN) (DevicePathType (Node) == END_DEVICE_PATH_TYPE);
    212 }
    213 
    214 /**
    215   Determines if a device path node is an end node of an entire device path.
    216 
    217   Determines if a device path node specified by Node is an end node of an entire
    218   device path. If Node represents the end of an entire device path, then TRUE is
    219   returned.  Otherwise, FALSE is returned.
    220 
    221   If Node is NULL, then ASSERT().
    222 
    223   @param  Node      A pointer to a device path node data structure.
    224 
    225   @retval TRUE      The device path node specified by Node is the end of an entire
    226                     device path.
    227   @retval FALSE     The device path node specified by Node is not the end of an
    228                     entire device path.
    229 
    230 **/
    231 BOOLEAN
    232 EFIAPI
    233 IsDevicePathEnd (
    234   IN CONST VOID  *Node
    235   )
    236 {
    237   ASSERT (Node != NULL);
    238   return (BOOLEAN) (IsDevicePathEndType (Node) && DevicePathSubType(Node) == END_ENTIRE_DEVICE_PATH_SUBTYPE);
    239 }
    240 
    241 /**
    242   Determines if a device path node is an end node of a device path instance.
    243 
    244   Determines if a device path node specified by Node is an end node of a device
    245   path instance. If Node represents the end of a device path instance, then TRUE
    246   is returned.  Otherwise, FALSE is returned.
    247 
    248   If Node is NULL, then ASSERT().
    249 
    250   @param  Node      A pointer to a device path node data structure.
    251 
    252   @retval TRUE      The device path node specified by Node is the end of a device
    253                     path instance.
    254   @retval FALSE     The device path node specified by Node is not the end of a
    255                     device path instance.
    256 
    257 **/
    258 BOOLEAN
    259 EFIAPI
    260 IsDevicePathEndInstance (
    261   IN CONST VOID  *Node
    262   )
    263 {
    264   ASSERT (Node != NULL);
    265   return (BOOLEAN) (IsDevicePathEndType (Node) && DevicePathSubType(Node) == END_INSTANCE_DEVICE_PATH_SUBTYPE);
    266 }
    267 
    268 /**
    269   Sets the length, in bytes, of a device path node.
    270 
    271   Sets the length of the device path node specified by Node to the value specified
    272   by NodeLength.  NodeLength is returned.  Node is not required to be aligned on
    273   a 16-bit boundary, so it is recommended that a function such as WriteUnaligned16()
    274   be used to set the contents of the Length field.
    275 
    276   If Node is NULL, then ASSERT().
    277   If NodeLength >= SIZE_64KB, then ASSERT().
    278   If NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL), then ASSERT().
    279 
    280   @param  Node      A pointer to a device path node data structure.
    281   @param  Length    The length, in bytes, of the device path node.
    282 
    283   @return Length
    284 
    285 **/
    286 UINT16
    287 EFIAPI
    288 SetDevicePathNodeLength (
    289   IN OUT VOID  *Node,
    290   IN UINTN     Length
    291   )
    292 {
    293   ASSERT (Node != NULL);
    294   ASSERT ((Length >= sizeof (EFI_DEVICE_PATH_PROTOCOL)) && (Length < SIZE_64KB));
    295   return WriteUnaligned16 ((UINT16 *)&((EFI_DEVICE_PATH_PROTOCOL *)(Node))->Length[0], (UINT16)(Length));
    296 }
    297 
    298 /**
    299   Fills in all the fields of a device path node that is the end of an entire device path.
    300 
    301   Fills in all the fields of a device path node specified by Node so Node represents
    302   the end of an entire device path.  The Type field of Node is set to
    303   END_DEVICE_PATH_TYPE, the SubType field of Node is set to
    304   END_ENTIRE_DEVICE_PATH_SUBTYPE, and the Length field of Node is set to
    305   END_DEVICE_PATH_LENGTH.  Node is not required to be aligned on a 16-bit boundary,
    306   so it is recommended that a function such as WriteUnaligned16() be used to set
    307   the contents of the Length field.
    308 
    309   If Node is NULL, then ASSERT().
    310 
    311   @param  Node      A pointer to a device path node data structure.
    312 
    313 **/
    314 VOID
    315 EFIAPI
    316 SetDevicePathEndNode (
    317   OUT VOID  *Node
    318   )
    319 {
    320   ASSERT (Node != NULL);
    321   CopyMem (Node, &mUefiDevicePathLibEndDevicePath, sizeof (mUefiDevicePathLibEndDevicePath));
    322 }
    323 
    324 /**
    325   Returns the size of a device path in bytes.
    326 
    327   This function returns the size, in bytes, of the device path data structure
    328   specified by DevicePath including the end of device path node.
    329   If DevicePath is NULL or invalid, then 0 is returned.
    330 
    331   @param  DevicePath  A pointer to a device path data structure.
    332 
    333   @retval 0           If DevicePath is NULL or invalid.
    334   @retval Others      The size of a device path in bytes.
    335 
    336 **/
    337 UINTN
    338 EFIAPI
    339 UefiDevicePathLibGetDevicePathSize (
    340   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath
    341   )
    342 {
    343   CONST EFI_DEVICE_PATH_PROTOCOL  *Start;
    344 
    345   if (DevicePath == NULL) {
    346     return 0;
    347   }
    348 
    349   if (!IsDevicePathValid (DevicePath, 0)) {
    350     return 0;
    351   }
    352 
    353   //
    354   // Search for the end of the device path structure
    355   //
    356   Start = DevicePath;
    357   while (!IsDevicePathEnd (DevicePath)) {
    358     DevicePath = NextDevicePathNode (DevicePath);
    359   }
    360 
    361   //
    362   // Compute the size and add back in the size of the end device path structure
    363   //
    364   return ((UINTN) DevicePath - (UINTN) Start) + DevicePathNodeLength (DevicePath);
    365 }
    366 
    367 /**
    368   Creates a new copy of an existing device path.
    369 
    370   This function allocates space for a new copy of the device path specified by DevicePath.
    371   If DevicePath is NULL, then NULL is returned.  If the memory is successfully
    372   allocated, then the contents of DevicePath are copied to the newly allocated
    373   buffer, and a pointer to that buffer is returned.  Otherwise, NULL is returned.
    374   The memory for the new device path is allocated from EFI boot services memory.
    375   It is the responsibility of the caller to free the memory allocated.
    376 
    377   @param  DevicePath    A pointer to a device path data structure.
    378 
    379   @retval NULL          DevicePath is NULL or invalid.
    380   @retval Others        A pointer to the duplicated device path.
    381 
    382 **/
    383 EFI_DEVICE_PATH_PROTOCOL *
    384 EFIAPI
    385 UefiDevicePathLibDuplicateDevicePath (
    386   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath
    387   )
    388 {
    389   UINTN                     Size;
    390 
    391   //
    392   // Compute the size
    393   //
    394   Size = GetDevicePathSize (DevicePath);
    395   if (Size == 0) {
    396     return NULL;
    397   }
    398 
    399   //
    400   // Allocate space for duplicate device path
    401   //
    402 
    403   return AllocateCopyPool (Size, DevicePath);
    404 }
    405 
    406 /**
    407   Creates a new device path by appending a second device path to a first device path.
    408 
    409   This function creates a new device path by appending a copy of SecondDevicePath
    410   to a copy of FirstDevicePath in a newly allocated buffer.  Only the end-of-device-path
    411   device node from SecondDevicePath is retained. The newly created device path is
    412   returned. If FirstDevicePath is NULL, then it is ignored, and a duplicate of
    413   SecondDevicePath is returned.  If SecondDevicePath is NULL, then it is ignored,
    414   and a duplicate of FirstDevicePath is returned. If both FirstDevicePath and
    415   SecondDevicePath are NULL, then a copy of an end-of-device-path is returned.
    416 
    417   If there is not enough memory for the newly allocated buffer, then NULL is returned.
    418   The memory for the new device path is allocated from EFI boot services memory.
    419   It is the responsibility of the caller to free the memory allocated.
    420 
    421   @param  FirstDevicePath            A pointer to a device path data structure.
    422   @param  SecondDevicePath           A pointer to a device path data structure.
    423 
    424   @retval NULL      If there is not enough memory for the newly allocated buffer.
    425   @retval NULL      If FirstDevicePath or SecondDevicePath is invalid.
    426   @retval Others    A pointer to the new device path if success.
    427                     Or a copy an end-of-device-path if both FirstDevicePath and SecondDevicePath are NULL.
    428 
    429 **/
    430 EFI_DEVICE_PATH_PROTOCOL *
    431 EFIAPI
    432 UefiDevicePathLibAppendDevicePath (
    433   IN CONST EFI_DEVICE_PATH_PROTOCOL  *FirstDevicePath,  OPTIONAL
    434   IN CONST EFI_DEVICE_PATH_PROTOCOL  *SecondDevicePath  OPTIONAL
    435   )
    436 {
    437   UINTN                     Size;
    438   UINTN                     Size1;
    439   UINTN                     Size2;
    440   EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;
    441   EFI_DEVICE_PATH_PROTOCOL  *DevicePath2;
    442 
    443   //
    444   // If there's only 1 path, just duplicate it.
    445   //
    446   if (FirstDevicePath == NULL) {
    447     return DuplicateDevicePath ((SecondDevicePath != NULL) ? SecondDevicePath : &mUefiDevicePathLibEndDevicePath);
    448   }
    449 
    450   if (SecondDevicePath == NULL) {
    451     return DuplicateDevicePath (FirstDevicePath);
    452   }
    453 
    454   if (!IsDevicePathValid (FirstDevicePath, 0) || !IsDevicePathValid (SecondDevicePath, 0)) {
    455     return NULL;
    456   }
    457 
    458   //
    459   // Allocate space for the combined device path. It only has one end node of
    460   // length EFI_DEVICE_PATH_PROTOCOL.
    461   //
    462   Size1         = GetDevicePathSize (FirstDevicePath);
    463   Size2         = GetDevicePathSize (SecondDevicePath);
    464   Size          = Size1 + Size2 - END_DEVICE_PATH_LENGTH;
    465 
    466   NewDevicePath = AllocatePool (Size);
    467 
    468   if (NewDevicePath != NULL) {
    469     NewDevicePath = CopyMem (NewDevicePath, FirstDevicePath, Size1);
    470     //
    471     // Over write FirstDevicePath EndNode and do the copy
    472     //
    473     DevicePath2 = (EFI_DEVICE_PATH_PROTOCOL *) ((CHAR8 *) NewDevicePath +
    474                   (Size1 - END_DEVICE_PATH_LENGTH));
    475     CopyMem (DevicePath2, SecondDevicePath, Size2);
    476   }
    477 
    478   return NewDevicePath;
    479 }
    480 
    481 /**
    482   Creates a new path by appending the device node to the device path.
    483 
    484   This function creates a new device path by appending a copy of the device node
    485   specified by DevicePathNode to a copy of the device path specified by DevicePath
    486   in an allocated buffer. The end-of-device-path device node is moved after the
    487   end of the appended device node.
    488   If DevicePathNode is NULL then a copy of DevicePath is returned.
    489   If DevicePath is NULL then a copy of DevicePathNode, followed by an end-of-device
    490   path device node is returned.
    491   If both DevicePathNode and DevicePath are NULL then a copy of an end-of-device-path
    492   device node is returned.
    493   If there is not enough memory to allocate space for the new device path, then
    494   NULL is returned.
    495   The memory is allocated from EFI boot services memory. It is the responsibility
    496   of the caller to free the memory allocated.
    497 
    498   @param  DevicePath                 A pointer to a device path data structure.
    499   @param  DevicePathNode             A pointer to a single device path node.
    500 
    501   @retval NULL      If there is not enough memory for the new device path.
    502   @retval Others    A pointer to the new device path if success.
    503                     A copy of DevicePathNode followed by an end-of-device-path node
    504                     if both FirstDevicePath and SecondDevicePath are NULL.
    505                     A copy of an end-of-device-path node if both FirstDevicePath
    506                     and SecondDevicePath are NULL.
    507 
    508 **/
    509 EFI_DEVICE_PATH_PROTOCOL *
    510 EFIAPI
    511 UefiDevicePathLibAppendDevicePathNode (
    512   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath,     OPTIONAL
    513   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePathNode  OPTIONAL
    514   )
    515 {
    516   EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;
    517   EFI_DEVICE_PATH_PROTOCOL  *NextNode;
    518   EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;
    519   UINTN                     NodeLength;
    520 
    521   if (DevicePathNode == NULL) {
    522     return DuplicateDevicePath ((DevicePath != NULL) ? DevicePath : &mUefiDevicePathLibEndDevicePath);
    523   }
    524   //
    525   // Build a Node that has a terminator on it
    526   //
    527   NodeLength = DevicePathNodeLength (DevicePathNode);
    528 
    529   TempDevicePath = AllocatePool (NodeLength + END_DEVICE_PATH_LENGTH);
    530   if (TempDevicePath == NULL) {
    531     return NULL;
    532   }
    533   TempDevicePath = CopyMem (TempDevicePath, DevicePathNode, NodeLength);
    534   //
    535   // Add and end device path node to convert Node to device path
    536   //
    537   NextNode = NextDevicePathNode (TempDevicePath);
    538   SetDevicePathEndNode (NextNode);
    539   //
    540   // Append device paths
    541   //
    542   NewDevicePath = AppendDevicePath (DevicePath, TempDevicePath);
    543 
    544   FreePool (TempDevicePath);
    545 
    546   return NewDevicePath;
    547 }
    548 
    549 /**
    550   Creates a new device path by appending the specified device path instance to the specified device
    551   path.
    552 
    553   This function creates a new device path by appending a copy of the device path
    554   instance specified by DevicePathInstance to a copy of the device path specified
    555   by DevicePath in a allocated buffer.
    556   The end-of-device-path device node is moved after the end of the appended device
    557   path instance and a new end-of-device-path-instance node is inserted between.
    558   If DevicePath is NULL, then a copy if DevicePathInstance is returned.
    559   If DevicePathInstance is NULL, then NULL is returned.
    560   If DevicePath or DevicePathInstance is invalid, then NULL is returned.
    561   If there is not enough memory to allocate space for the new device path, then
    562   NULL is returned.
    563   The memory is allocated from EFI boot services memory. It is the responsibility
    564   of the caller to free the memory allocated.
    565 
    566   @param  DevicePath                 A pointer to a device path data structure.
    567   @param  DevicePathInstance         A pointer to a device path instance.
    568 
    569   @return A pointer to the new device path.
    570 
    571 **/
    572 EFI_DEVICE_PATH_PROTOCOL *
    573 EFIAPI
    574 UefiDevicePathLibAppendDevicePathInstance (
    575   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath,        OPTIONAL
    576   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePathInstance OPTIONAL
    577   )
    578 {
    579   EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;
    580   EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;
    581   UINTN                     SrcSize;
    582   UINTN                     InstanceSize;
    583 
    584   if (DevicePath == NULL) {
    585     return DuplicateDevicePath (DevicePathInstance);
    586   }
    587 
    588   if (DevicePathInstance == NULL) {
    589     return NULL;
    590   }
    591 
    592   if (!IsDevicePathValid (DevicePath, 0) || !IsDevicePathValid (DevicePathInstance, 0)) {
    593     return NULL;
    594   }
    595 
    596   SrcSize       = GetDevicePathSize (DevicePath);
    597   InstanceSize  = GetDevicePathSize (DevicePathInstance);
    598 
    599   NewDevicePath = AllocatePool (SrcSize + InstanceSize);
    600   if (NewDevicePath != NULL) {
    601 
    602     TempDevicePath = CopyMem (NewDevicePath, DevicePath, SrcSize);;
    603 
    604     while (!IsDevicePathEnd (TempDevicePath)) {
    605       TempDevicePath = NextDevicePathNode (TempDevicePath);
    606     }
    607 
    608     TempDevicePath->SubType  = END_INSTANCE_DEVICE_PATH_SUBTYPE;
    609     TempDevicePath           = NextDevicePathNode (TempDevicePath);
    610     CopyMem (TempDevicePath, DevicePathInstance, InstanceSize);
    611   }
    612 
    613   return NewDevicePath;
    614 }
    615 
    616 /**
    617   Creates a copy of the current device path instance and returns a pointer to the next device path
    618   instance.
    619 
    620   This function creates a copy of the current device path instance. It also updates
    621   DevicePath to point to the next device path instance in the device path (or NULL
    622   if no more) and updates Size to hold the size of the device path instance copy.
    623   If DevicePath is NULL, then NULL is returned.
    624   If DevicePath points to a invalid device path, then NULL is returned.
    625   If there is not enough memory to allocate space for the new device path, then
    626   NULL is returned.
    627   The memory is allocated from EFI boot services memory. It is the responsibility
    628   of the caller to free the memory allocated.
    629   If Size is NULL, then ASSERT().
    630 
    631   @param  DevicePath                 On input, this holds the pointer to the current
    632                                      device path instance. On output, this holds
    633                                      the pointer to the next device path instance
    634                                      or NULL if there are no more device path
    635                                      instances in the device path pointer to a
    636                                      device path data structure.
    637   @param  Size                       On output, this holds the size of the device
    638                                      path instance, in bytes or zero, if DevicePath
    639                                      is NULL.
    640 
    641   @return A pointer to the current device path instance.
    642 
    643 **/
    644 EFI_DEVICE_PATH_PROTOCOL *
    645 EFIAPI
    646 UefiDevicePathLibGetNextDevicePathInstance (
    647   IN OUT EFI_DEVICE_PATH_PROTOCOL    **DevicePath,
    648   OUT UINTN                          *Size
    649   )
    650 {
    651   EFI_DEVICE_PATH_PROTOCOL  *DevPath;
    652   EFI_DEVICE_PATH_PROTOCOL  *ReturnValue;
    653   UINT8                     Temp;
    654 
    655   ASSERT (Size != NULL);
    656 
    657   if (DevicePath == NULL || *DevicePath == NULL) {
    658     *Size = 0;
    659     return NULL;
    660   }
    661 
    662   if (!IsDevicePathValid (*DevicePath, 0)) {
    663     return NULL;
    664   }
    665 
    666   //
    667   // Find the end of the device path instance
    668   //
    669   DevPath = *DevicePath;
    670   while (!IsDevicePathEndType (DevPath)) {
    671     DevPath = NextDevicePathNode (DevPath);
    672   }
    673 
    674   //
    675   // Compute the size of the device path instance
    676   //
    677   *Size = ((UINTN) DevPath - (UINTN) (*DevicePath)) + sizeof (EFI_DEVICE_PATH_PROTOCOL);
    678 
    679   //
    680   // Make a copy and return the device path instance
    681   //
    682   Temp              = DevPath->SubType;
    683   DevPath->SubType  = END_ENTIRE_DEVICE_PATH_SUBTYPE;
    684   ReturnValue       = DuplicateDevicePath (*DevicePath);
    685   DevPath->SubType  = Temp;
    686 
    687   //
    688   // If DevPath is the end of an entire device path, then another instance
    689   // does not follow, so *DevicePath is set to NULL.
    690   //
    691   if (DevicePathSubType (DevPath) == END_ENTIRE_DEVICE_PATH_SUBTYPE) {
    692     *DevicePath = NULL;
    693   } else {
    694     *DevicePath = NextDevicePathNode (DevPath);
    695   }
    696 
    697   return ReturnValue;
    698 }
    699 
    700 /**
    701   Creates a device node.
    702 
    703   This function creates a new device node in a newly allocated buffer of size
    704   NodeLength and initializes the device path node header with NodeType and NodeSubType.
    705   The new device path node is returned.
    706   If NodeLength is smaller than a device path header, then NULL is returned.
    707   If there is not enough memory to allocate space for the new device path, then
    708   NULL is returned.
    709   The memory is allocated from EFI boot services memory. It is the responsibility
    710   of the caller to free the memory allocated.
    711 
    712   @param  NodeType                   The device node type for the new device node.
    713   @param  NodeSubType                The device node sub-type for the new device node.
    714   @param  NodeLength                 The length of the new device node.
    715 
    716   @return The new device path.
    717 
    718 **/
    719 EFI_DEVICE_PATH_PROTOCOL *
    720 EFIAPI
    721 UefiDevicePathLibCreateDeviceNode (
    722   IN UINT8                           NodeType,
    723   IN UINT8                           NodeSubType,
    724   IN UINT16                          NodeLength
    725   )
    726 {
    727   EFI_DEVICE_PATH_PROTOCOL      *DevicePath;
    728 
    729   if (NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
    730     //
    731     // NodeLength is less than the size of the header.
    732     //
    733     return NULL;
    734   }
    735 
    736   DevicePath = AllocateZeroPool (NodeLength);
    737   if (DevicePath != NULL) {
    738      DevicePath->Type    = NodeType;
    739      DevicePath->SubType = NodeSubType;
    740      SetDevicePathNodeLength (DevicePath, NodeLength);
    741   }
    742 
    743   return DevicePath;
    744 }
    745 
    746 /**
    747   Determines if a device path is single or multi-instance.
    748 
    749   This function returns TRUE if the device path specified by DevicePath is
    750   multi-instance.
    751   Otherwise, FALSE is returned.
    752   If DevicePath is NULL or invalid, then FALSE is returned.
    753 
    754   @param  DevicePath                 A pointer to a device path data structure.
    755 
    756   @retval  TRUE                      DevicePath is multi-instance.
    757   @retval  FALSE                     DevicePath is not multi-instance, or DevicePath
    758                                      is NULL or invalid.
    759 
    760 **/
    761 BOOLEAN
    762 EFIAPI
    763 UefiDevicePathLibIsDevicePathMultiInstance (
    764   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath
    765   )
    766 {
    767   CONST EFI_DEVICE_PATH_PROTOCOL     *Node;
    768 
    769   if (DevicePath == NULL) {
    770     return FALSE;
    771   }
    772 
    773   if (!IsDevicePathValid (DevicePath, 0)) {
    774     return FALSE;
    775   }
    776 
    777   Node = DevicePath;
    778   while (!IsDevicePathEnd (Node)) {
    779     if (IsDevicePathEndInstance (Node)) {
    780       return TRUE;
    781     }
    782 
    783     Node = NextDevicePathNode (Node);
    784   }
    785 
    786   return FALSE;
    787 }
    788 
    789 
    790 /**
    791   Retrieves the device path protocol from a handle.
    792 
    793   This function returns the device path protocol from the handle specified by Handle.
    794   If Handle is NULL or Handle does not contain a device path protocol, then NULL
    795   is returned.
    796 
    797   @param  Handle                     The handle from which to retrieve the device
    798                                      path protocol.
    799 
    800   @return The device path protocol from the handle specified by Handle.
    801 
    802 **/
    803 EFI_DEVICE_PATH_PROTOCOL *
    804 EFIAPI
    805 DevicePathFromHandle (
    806   IN EFI_HANDLE                      Handle
    807   )
    808 {
    809   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
    810   EFI_STATUS                Status;
    811 
    812   Status = gBS->HandleProtocol (
    813                   Handle,
    814                   &gEfiDevicePathProtocolGuid,
    815                   (VOID *) &DevicePath
    816                   );
    817   if (EFI_ERROR (Status)) {
    818     DevicePath = NULL;
    819   }
    820   return DevicePath;
    821 }
    822 
    823 /**
    824   Allocates a device path for a file and appends it to an existing device path.
    825 
    826   If Device is a valid device handle that contains a device path protocol, then a device path for
    827   the file specified by FileName  is allocated and appended to the device path associated with the
    828   handle Device.  The allocated device path is returned.  If Device is NULL or Device is a handle
    829   that does not support the device path protocol, then a device path containing a single device
    830   path node for the file specified by FileName is allocated and returned.
    831   The memory for the new device path is allocated from EFI boot services memory. It is the responsibility
    832   of the caller to free the memory allocated.
    833 
    834   If FileName is NULL, then ASSERT().
    835   If FileName is not aligned on a 16-bit boundary, then ASSERT().
    836 
    837   @param  Device                     A pointer to a device handle.  This parameter
    838                                      is optional and may be NULL.
    839   @param  FileName                   A pointer to a Null-terminated Unicode string.
    840 
    841   @return The allocated device path.
    842 
    843 **/
    844 EFI_DEVICE_PATH_PROTOCOL *
    845 EFIAPI
    846 FileDevicePath (
    847   IN EFI_HANDLE                      Device,     OPTIONAL
    848   IN CONST CHAR16                    *FileName
    849   )
    850 {
    851   UINTN                     Size;
    852   FILEPATH_DEVICE_PATH      *FilePath;
    853   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
    854   EFI_DEVICE_PATH_PROTOCOL  *FileDevicePath;
    855 
    856   DevicePath = NULL;
    857 
    858   Size = StrSize (FileName);
    859   FileDevicePath = AllocatePool (Size + SIZE_OF_FILEPATH_DEVICE_PATH + END_DEVICE_PATH_LENGTH);
    860   if (FileDevicePath != NULL) {
    861     FilePath = (FILEPATH_DEVICE_PATH *) FileDevicePath;
    862     FilePath->Header.Type    = MEDIA_DEVICE_PATH;
    863     FilePath->Header.SubType = MEDIA_FILEPATH_DP;
    864     CopyMem (&FilePath->PathName, FileName, Size);
    865     SetDevicePathNodeLength (&FilePath->Header, Size + SIZE_OF_FILEPATH_DEVICE_PATH);
    866     SetDevicePathEndNode (NextDevicePathNode (&FilePath->Header));
    867 
    868     if (Device != NULL) {
    869       DevicePath = DevicePathFromHandle (Device);
    870     }
    871 
    872     DevicePath = AppendDevicePath (DevicePath, FileDevicePath);
    873     FreePool (FileDevicePath);
    874   }
    875 
    876   return DevicePath;
    877 }
    878 
    879