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)
7 The only place where multi-instance device paths are supported is in
8 environment varibles. Multi-instance device paths should never be placed
11 Copyright (c) 2006 - 2008, Intel Corporation
12 All rights reserved. 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
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.
25 #include <Protocol/DevicePath.h>
27 #include <Library/DevicePathLib.h>
28 #include <Library/BaseMemoryLib.h>
29 #include <Library/DebugLib.h>
30 #include <Library/MemoryAllocationLib.h>
31 #include <Library/UefiBootServicesTableLib.h>
32 #include <Library/BaseLib.h>
35 // Template for an end-of-device path node.
37 GLOBAL_REMOVE_IF_UNREFERENCED CONST EFI_DEVICE_PATH_PROTOCOL mUefiDevicePathLibEndDevicePath
= {
39 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
41 END_DEVICE_PATH_LENGTH
,
47 Returns the Type field of a device path node.
49 Returns the Type field of the device path node specified by Node.
51 If Node is NULL, then ASSERT().
53 @param Node A pointer to a device path node data structure.
55 @return The Type field of the device path node specified by Node.
63 ASSERT (Node
!= NULL
);
64 return ((EFI_DEVICE_PATH_PROTOCOL
*)(Node
))->Type
;
68 Returns the SubType field of a device path node.
70 Returns the SubType field of the device path node specified by Node.
72 If Node is NULL, then ASSERT().
74 @param Node A pointer to a device path node data structure.
76 @return The SubType field of the device path node specified by Node.
84 ASSERT (Node
!= NULL
);
85 return ((EFI_DEVICE_PATH_PROTOCOL
*)(Node
))->SubType
;
89 Returns the 16-bit Length field of a device path node.
91 Returns the 16-bit Length field of the device path node specified by Node.
92 Node is not required to be aligned on a 16-bit boundary, so it is recommended
93 that a function such as ReadUnaligned16() be used to extract the contents of
96 If Node is NULL, then ASSERT().
98 @param Node A pointer to a device path node data structure.
100 @return The 16-bit Length field of the device path node specified by Node.
104 DevicePathNodeLength (
108 ASSERT (Node
!= NULL
);
109 return ReadUnaligned16 ((UINT16
*)&((EFI_DEVICE_PATH_PROTOCOL
*)(Node
))->Length
[0]);
113 Returns a pointer to the next node in a device path.
115 Returns a pointer to the device path node that follows the device path node specified by Node.
117 If Node is NULL, then ASSERT().
119 @param Node A pointer to a device path node data structure.
121 @return a pointer to the device path node that follows the device path node specified by Node.
124 EFI_DEVICE_PATH_PROTOCOL
*
129 ASSERT (Node
!= NULL
);
130 return (EFI_DEVICE_PATH_PROTOCOL
*)((UINT8
*)(Node
) + DevicePathNodeLength(Node
));
134 Determines if a device path node is an end node of a device path.
135 This includes nodes that are the end of a device path instance and nodes that are the end of an entire device path.
137 Determines if the device path node specified by Node is an end node of a device path.
138 This includes nodes that are the end of a device path instance and nodes that are the
139 end of an entire device path. If Node represents an end node of a device path,
140 then TRUE is returned. Otherwise, FALSE is returned.
142 If Node is NULL, then ASSERT().
144 @param Node A pointer to a device path node data structure.
146 @retval TRUE The device path node specified by Node is an end node of a device path.
147 @retval FALSE The device path node specified by Node is not an end node of a device path.
151 IsDevicePathEndType (
155 ASSERT (Node
!= NULL
);
156 return (BOOLEAN
) (DevicePathType (Node
) == END_DEVICE_PATH_TYPE
);
160 Determines if a device path node is an end node of an entire device path.
162 Determines if a device path node specified by Node is an end node of an entire device path.
163 If Node represents the end of an entire device path, then TRUE is returned. Otherwise, FALSE is returned.
165 If Node is NULL, then ASSERT().
167 @param Node A pointer to a device path node data structure.
169 @retval TRUE The device path node specified by Node is the end of an entire device path.
170 @retval FALSE The device path node specified by Node is not the end of an entire device path.
178 ASSERT (Node
!= NULL
);
179 return (BOOLEAN
) (IsDevicePathEndType (Node
) && DevicePathSubType(Node
) == END_ENTIRE_DEVICE_PATH_SUBTYPE
);
183 Determines if a device path node is an end node of a device path instance.
185 Determines if a device path node specified by Node is an end node of a device path instance.
186 If Node represents the end of a device path instance, then TRUE is returned. Otherwise, FALSE is returned.
188 If Node is NULL, then ASSERT().
190 @param Node A pointer to a device path node data structure.
192 @retval TRUE The device path node specified by Node is the end of a device path instance.
193 @retval FALSE The device path node specified by Node is not the end of a device path instance.
197 IsDevicePathEndInstance (
201 ASSERT (Node
!= NULL
);
202 return (BOOLEAN
) (IsDevicePathEndType (Node
) && DevicePathSubType(Node
) == END_INSTANCE_DEVICE_PATH_SUBTYPE
);
206 Sets the length, in bytes, of a device path node.
208 Sets the length of the device path node specified by Node to the value specified
209 by NodeLength. NodeLength is returned. Node is not required to be aligned on
210 a 16-bit boundary, so it is recommended that a function such as WriteUnaligned16()
211 be used to set the contents of the Length field.
213 If Node is NULL, then ASSERT().
214 If NodeLength >= 0x10000, then ASSERT().
216 @param Node A pointer to a device path node data structure.
217 @param Length The length, in bytes, of the device path node.
223 SetDevicePathNodeLength (
228 ASSERT (Node
!= NULL
);
229 ASSERT (Length
< 0x10000);
230 return WriteUnaligned16 ((UINT16
*)&((EFI_DEVICE_PATH_PROTOCOL
*)(Node
))->Length
[0], (UINT16
)(Length
));
234 Fills in all the fields of a device path node that is the end of an entire device path.
236 Fills in all the fields of a device path node specified by Node so Node represents
237 the end of an entire device path. The Type field of Node is set to
238 END_DEVICE_PATH_TYPE, the SubType field of Node is set to
239 END_ENTIRE_DEVICE_PATH_SUBTYPE, and the Length field of Node is set to
240 END_DEVICE_PATH_LENGTH. Node is not required to be aligned on a 16-bit boundary,
241 so it is recommended that a function such as WriteUnaligned16() be used to set
242 the contents of the Length field.
244 If Node is NULL, then ASSERT().
246 @param Node A pointer to a device path node data structure.
250 SetDevicePathEndNode (
254 ASSERT (Node
!= NULL
);
255 CopyMem (Node
, &mUefiDevicePathLibEndDevicePath
, sizeof (mUefiDevicePathLibEndDevicePath
));
259 Returns the size of a device path in bytes.
261 This function returns the size, in bytes, of the device path data structure specified by
262 DevicePath including the end of device path node. If DevicePath is NULL, then 0 is returned.
264 @param DevicePath A pointer to a device path data structure.
266 @retval 0 If DevicePath is NULL.
267 @retval Others The size of a device path in bytes.
273 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
276 CONST EFI_DEVICE_PATH_PROTOCOL
*Start
;
278 if (DevicePath
== NULL
) {
283 // Search for the end of the device path structure
286 while (!IsDevicePathEnd (DevicePath
)) {
287 DevicePath
= NextDevicePathNode (DevicePath
);
291 // Compute the size and add back in the size of the end device path structure
293 return ((UINTN
) DevicePath
- (UINTN
) Start
) + DevicePathNodeLength (DevicePath
);
297 Creates a new copy of an existing device path.
299 This function allocates space for a new copy of the device path specified by DevicePath. If
300 DevicePath is NULL, then NULL is returned. If the memory is successfully allocated, then the
301 contents of DevicePath are copied to the newly allocated buffer, and a pointer to that buffer
302 is returned. Otherwise, NULL is returned.
303 The memory for the new device path is allocated from EFI boot services memory.
304 It is the responsibility of the caller to free the memory allocated.
306 @param DevicePath A pointer to a device path data structure.
308 @retval NULL If DevicePath is NULL.
309 @retval Others A pointer to the duplicated device path.
312 EFI_DEVICE_PATH_PROTOCOL
*
314 DuplicateDevicePath (
315 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
323 Size
= GetDevicePathSize (DevicePath
);
329 // Allocate space for duplicate device path
332 return AllocateCopyPool (Size
, DevicePath
);
336 Creates a new device path by appending a second device path to a first device path.
338 This function creates a new device path by appending a copy of SecondDevicePath to a copy of
339 FirstDevicePath in a newly allocated buffer. Only the end-of-device-path device node from
340 SecondDevicePath is retained. The newly created device path is returned.
341 If FirstDevicePath is NULL, then it is ignored, and a duplicate of SecondDevicePath is returned.
342 If SecondDevicePath is NULL, then it is ignored, and a duplicate of FirstDevicePath is returned.
343 If both FirstDevicePath and SecondDevicePath are NULL, then a copy of an end-of-device-path is
345 If there is not enough memory for the newly allocated buffer, then NULL is returned.
346 The memory for the new device path is allocated from EFI boot services memory. It is the
347 responsibility of the caller to free the memory allocated.
349 @param FirstDevicePath A pointer to a device path data structure.
350 @param SecondDevicePath A pointer to a device path data structure.
352 @retval NULL If there is not enough memory for the newly allocated buffer.
353 @retval Others A pointer to the new device path if success.
354 Or a copy an end-of-device-path if both FirstDevicePath and SecondDevicePath are NULL.
357 EFI_DEVICE_PATH_PROTOCOL
*
360 IN CONST EFI_DEVICE_PATH_PROTOCOL
*FirstDevicePath
, OPTIONAL
361 IN CONST EFI_DEVICE_PATH_PROTOCOL
*SecondDevicePath OPTIONAL
367 EFI_DEVICE_PATH_PROTOCOL
*NewDevicePath
;
368 EFI_DEVICE_PATH_PROTOCOL
*DevicePath2
;
371 // If there's only 1 path, just duplicate it.
373 if (FirstDevicePath
== NULL
) {
374 return DuplicateDevicePath ((SecondDevicePath
!= NULL
) ? SecondDevicePath
: &mUefiDevicePathLibEndDevicePath
);
377 if (SecondDevicePath
== NULL
) {
378 return DuplicateDevicePath (FirstDevicePath
);
382 // Allocate space for the combined device path. It only has one end node of
383 // length EFI_DEVICE_PATH_PROTOCOL.
385 Size1
= GetDevicePathSize (FirstDevicePath
);
386 Size2
= GetDevicePathSize (SecondDevicePath
);
387 Size
= Size1
+ Size2
- END_DEVICE_PATH_LENGTH
;
389 NewDevicePath
= AllocatePool (Size
);
391 if (NewDevicePath
!= NULL
) {
392 NewDevicePath
= CopyMem (NewDevicePath
, FirstDevicePath
, Size1
);
394 // Over write FirstDevicePath EndNode and do the copy
396 DevicePath2
= (EFI_DEVICE_PATH_PROTOCOL
*) ((CHAR8
*) NewDevicePath
+
397 (Size1
- END_DEVICE_PATH_LENGTH
));
398 CopyMem (DevicePath2
, SecondDevicePath
, Size2
);
401 return NewDevicePath
;
405 Creates a new path by appending the device node to the device path.
407 This function creates a new device path by appending a copy of the device node specified by
408 DevicePathNode to a copy of the device path specified by DevicePath in an allocated buffer.
409 The end-of-device-path device node is moved after the end of the appended device node.
410 If DevicePathNode is NULL then a copy of DevicePath is returned.
411 If DevicePath is NULL then a copy of DevicePathNode, followed by an end-of-device path device
413 If both DevicePathNode and DevicePath are NULL then a copy of an end-of-device-path device node
415 If there is not enough memory to allocate space for the new device path, then NULL is returned.
416 The memory is allocated from EFI boot services memory. It is the responsibility of the caller to
417 free the memory allocated.
419 @param DevicePath A pointer to a device path data structure.
420 @param DevicePathNode A pointer to a single device path node.
422 @retval NULL If there is not enough memory for the new device path.
423 @retval Others A pointer to the new device path if success.
424 A copy of DevicePathNode followed by an end-of-device-path node
425 if both FirstDevicePath and SecondDevicePath are NULL.
426 A copy of an end-of-device-path node if both FirstDevicePath and SecondDevicePath are NULL.
429 EFI_DEVICE_PATH_PROTOCOL
*
431 AppendDevicePathNode (
432 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
, OPTIONAL
433 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode OPTIONAL
436 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
437 EFI_DEVICE_PATH_PROTOCOL
*NextNode
;
438 EFI_DEVICE_PATH_PROTOCOL
*NewDevicePath
;
441 if (DevicePathNode
== NULL
) {
442 return DuplicateDevicePath ((DevicePath
!= NULL
) ? DevicePath
: &mUefiDevicePathLibEndDevicePath
);
445 // Build a Node that has a terminator on it
447 NodeLength
= DevicePathNodeLength (DevicePathNode
);
449 TempDevicePath
= AllocatePool (NodeLength
+ END_DEVICE_PATH_LENGTH
);
450 if (TempDevicePath
== NULL
) {
453 TempDevicePath
= CopyMem (TempDevicePath
, DevicePathNode
, NodeLength
);
455 // Add and end device path node to convert Node to device path
457 NextNode
= NextDevicePathNode (TempDevicePath
);
458 SetDevicePathEndNode (NextNode
);
460 // Append device paths
462 NewDevicePath
= AppendDevicePath (DevicePath
, TempDevicePath
);
464 FreePool (TempDevicePath
);
466 return NewDevicePath
;
470 Creates a new device path by appending the specified device path instance to the specified device
473 This function creates a new device path by appending a copy of the device path instance specified
474 by DevicePathInstance to a copy of the device path secified by DevicePath in a allocated buffer.
475 The end-of-device-path device node is moved after the end of the appended device path instance
476 and a new end-of-device-path-instance node is inserted between.
477 If DevicePath is NULL, then a copy if DevicePathInstance is returned.
478 If DevicePathInstance is NULL, then NULL is returned.
479 If there is not enough memory to allocate space for the new device path, then NULL is returned.
480 The memory is allocated from EFI boot services memory. It is the responsibility of the caller to
481 free the memory allocated.
483 @param DevicePath A pointer to a device path data structure.
484 @param DevicePathInstance A pointer to a device path instance.
486 @return A pointer to the new device path.
489 EFI_DEVICE_PATH_PROTOCOL
*
491 AppendDevicePathInstance (
492 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
, OPTIONAL
493 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePathInstance OPTIONAL
496 EFI_DEVICE_PATH_PROTOCOL
*NewDevicePath
;
497 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
501 if (DevicePath
== NULL
) {
502 return DuplicateDevicePath (DevicePathInstance
);
505 if (DevicePathInstance
== NULL
) {
509 SrcSize
= GetDevicePathSize (DevicePath
);
510 InstanceSize
= GetDevicePathSize (DevicePathInstance
);
512 NewDevicePath
= AllocatePool (SrcSize
+ InstanceSize
);
513 if (NewDevicePath
!= NULL
) {
515 TempDevicePath
= CopyMem (NewDevicePath
, DevicePath
, SrcSize
);;
517 while (!IsDevicePathEnd (TempDevicePath
)) {
518 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
521 TempDevicePath
->SubType
= END_INSTANCE_DEVICE_PATH_SUBTYPE
;
522 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
523 CopyMem (TempDevicePath
, DevicePathInstance
, InstanceSize
);
526 return NewDevicePath
;
530 Creates a copy of the current device path instance and returns a pointer to the next device path
533 This function creates a copy of the current device path instance. It also updates DevicePath to
534 point to the next device path instance in the device path (or NULL if no more) and updates Size
535 to hold the size of the device path instance copy.
536 If DevicePath is NULL, then NULL is returned.
537 If there is not enough memory to allocate space for the new device path, then NULL is returned.
538 The memory is allocated from EFI boot services memory. It is the responsibility of the caller to
539 free the memory allocated.
540 If Size is NULL, then ASSERT().
542 @param DevicePath On input, this holds the pointer to the current device path
543 instance. On output, this holds the pointer to the next device
544 path instance or NULL if there are no more device path
545 instances in the device path pointer to a device path data
547 @param Size On output, this holds the size of the device path instance, in
548 bytes or zero, if DevicePath is NULL.
550 @return A pointer to the current device path instance.
553 EFI_DEVICE_PATH_PROTOCOL
*
555 GetNextDevicePathInstance (
556 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
,
560 EFI_DEVICE_PATH_PROTOCOL
*DevPath
;
561 EFI_DEVICE_PATH_PROTOCOL
*ReturnValue
;
564 ASSERT (Size
!= NULL
);
566 if (DevicePath
== NULL
|| *DevicePath
== NULL
) {
572 // Find the end of the device path instance
574 DevPath
= *DevicePath
;
575 while (!IsDevicePathEndType (DevPath
)) {
576 DevPath
= NextDevicePathNode (DevPath
);
580 // Compute the size of the device path instance
582 *Size
= ((UINTN
) DevPath
- (UINTN
) (*DevicePath
)) + sizeof (EFI_DEVICE_PATH_PROTOCOL
);
585 // Make a copy and return the device path instance
587 Temp
= DevPath
->SubType
;
588 DevPath
->SubType
= END_ENTIRE_DEVICE_PATH_SUBTYPE
;
589 ReturnValue
= DuplicateDevicePath (*DevicePath
);
590 DevPath
->SubType
= Temp
;
593 // If DevPath is the end of an entire device path, then another instance
594 // does not follow, so *DevicePath is set to NULL.
596 if (DevicePathSubType (DevPath
) == END_ENTIRE_DEVICE_PATH_SUBTYPE
) {
599 *DevicePath
= NextDevicePathNode (DevPath
);
606 Creates a device node.
608 This function creates a new device node in a newly allocated buffer of size NodeLength and
609 initializes the device path node header with NodeType and NodeSubType. The new device path node
611 If NodeLength is smaller than a device path header, then NULL is returned.
612 If there is not enough memory to allocate space for the new device path, then NULL is returned.
613 The memory is allocated from EFI boot services memory. It is the responsibility of the caller to
614 free the memory allocated.
616 @param NodeType The device node type for the new device node.
617 @param NodeSubType The device node sub-type for the new device node.
618 @param NodeLength The length of the new device node.
620 @return The new device path.
623 EFI_DEVICE_PATH_PROTOCOL
*
627 IN UINT8 NodeSubType
,
631 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
633 if (NodeLength
< sizeof (EFI_DEVICE_PATH_PROTOCOL
)) {
635 // NodeLength is less than the size of the header.
640 DevicePath
= AllocateZeroPool (NodeLength
);
641 if (DevicePath
!= NULL
) {
642 DevicePath
->Type
= NodeType
;
643 DevicePath
->SubType
= NodeSubType
;
644 SetDevicePathNodeLength (DevicePath
, NodeLength
);
651 Determines if a device path is single or multi-instance.
653 This function returns TRUE if the device path specified by DevicePath is multi-instance.
654 Otherwise, FALSE is returned. If DevicePath is NULL, then FALSE is returned.
656 @param DevicePath A pointer to a device path data structure.
658 @retval TRUE DevicePath is multi-instance.
659 @retval FALSE DevicePath is not multi-instance or DevicePath is NULL.
664 IsDevicePathMultiInstance (
665 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
668 CONST EFI_DEVICE_PATH_PROTOCOL
*Node
;
670 if (DevicePath
== NULL
) {
675 while (!IsDevicePathEnd (Node
)) {
676 if (IsDevicePathEndInstance (Node
)) {
680 Node
= NextDevicePathNode (Node
);
688 Retrieves the device path protocol from a handle.
690 This function returns the device path protocol from the handle specified by Handle. If Handle is
691 NULL or Handle does not contain a device path protocol, then NULL is returned.
693 @param Handle The handle from which to retrieve the device path protocol.
695 @return The device path protocol from the handle specified by Handle.
698 EFI_DEVICE_PATH_PROTOCOL
*
700 DevicePathFromHandle (
704 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
707 Status
= gBS
->HandleProtocol (
709 &gEfiDevicePathProtocolGuid
,
712 if (EFI_ERROR (Status
)) {
719 Allocates a device path for a file and appends it to an existing device path.
721 If Device is a valid device handle that contains a device path protocol, then a device path for
722 the file specified by FileName is allocated and appended to the device path associated with the
723 handle Device. The allocated device path is returned. If Device is NULL or Device is a handle
724 that does not support the device path protocol, then a device path containing a single device
725 path node for the file specified by FileName is allocated and returned.
726 The memory for the new device path is allocated from EFI boot services memory. It is the responsibility
727 of the caller to free the memory allocated.
729 If FileName is NULL, then ASSERT().
730 If FileName is not aligned on a 16-bit boundary, then ASSERT().
732 @param Device A pointer to a device handle. This parameter is optional and
734 @param FileName A pointer to a Null-terminated Unicode string.
736 @return The allocated device path.
739 EFI_DEVICE_PATH_PROTOCOL
*
742 IN EFI_HANDLE Device
, OPTIONAL
743 IN CONST CHAR16
*FileName
747 FILEPATH_DEVICE_PATH
*FilePath
;
748 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
749 EFI_DEVICE_PATH_PROTOCOL
*FileDevicePath
;
753 Size
= (UINT16
) StrSize (FileName
);
755 FileDevicePath
= AllocatePool (Size
+ SIZE_OF_FILEPATH_DEVICE_PATH
+ END_DEVICE_PATH_LENGTH
);
756 if (FileDevicePath
!= NULL
) {
757 FilePath
= (FILEPATH_DEVICE_PATH
*) FileDevicePath
;
758 FilePath
->Header
.Type
= MEDIA_DEVICE_PATH
;
759 FilePath
->Header
.SubType
= MEDIA_FILEPATH_DP
;
760 CopyMem (&FilePath
->PathName
, FileName
, Size
);
761 SetDevicePathNodeLength (&FilePath
->Header
, Size
+ SIZE_OF_FILEPATH_DEVICE_PATH
);
762 SetDevicePathEndNode (NextDevicePathNode (&FilePath
->Header
));
764 if (Device
!= NULL
) {
765 DevicePath
= DevicePathFromHandle (Device
);
768 DevicePath
= AppendDevicePath (DevicePath
, FileDevicePath
);
769 FreePool (FileDevicePath
);