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
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   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
DevicePathType(IN CONST VOID * Node)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
DevicePathSubType(IN CONST VOID * Node)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
DevicePathNodeLength(IN CONST VOID * Node)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
NextDevicePathNode(IN CONST VOID * Node)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
IsDevicePathEndType(IN CONST VOID * Node)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
IsDevicePathEnd(IN CONST VOID * Node)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
IsDevicePathEndInstance(IN CONST VOID * Node)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
SetDevicePathNodeLength(IN OUT VOID * Node,IN UINTN Length)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
SetDevicePathEndNode(OUT VOID * Node)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
UefiDevicePathLibGetDevicePathSize(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath)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
UefiDevicePathLibDuplicateDevicePath(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath)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
UefiDevicePathLibAppendDevicePath(IN CONST EFI_DEVICE_PATH_PROTOCOL * FirstDevicePath,OPTIONAL IN CONST EFI_DEVICE_PATH_PROTOCOL * SecondDevicePath OPTIONAL)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
UefiDevicePathLibAppendDevicePathNode(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath,OPTIONAL IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePathNode OPTIONAL)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
UefiDevicePathLibAppendDevicePathInstance(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath,OPTIONAL IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePathInstance OPTIONAL)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
UefiDevicePathLibGetNextDevicePathInstance(IN OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePath,OUT UINTN * Size)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
UefiDevicePathLibCreateDeviceNode(IN UINT8 NodeType,IN UINT8 NodeSubType,IN UINT16 NodeLength)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
UefiDevicePathLibIsDevicePathMultiInstance(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath)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
DevicePathFromHandle(IN EFI_HANDLE Handle)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
FileDevicePath(IN EFI_HANDLE Device,OPTIONAL IN CONST CHAR16 * FileName)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