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