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