aboutsummaryrefslogtreecommitdiff
path: root/lib/libefivar/uefi-dputil.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libefivar/uefi-dputil.c')
-rw-r--r--lib/libefivar/uefi-dputil.c537
1 files changed, 412 insertions, 125 deletions
diff --git a/lib/libefivar/uefi-dputil.c b/lib/libefivar/uefi-dputil.c
index c31da14eed2d..da87bffb7bd5 100644
--- a/lib/libefivar/uefi-dputil.c
+++ b/lib/libefivar/uefi-dputil.c
@@ -35,11 +35,9 @@
#include <sys/endian.h>
#include "uefi-dplib.h"
-/* XXX maybe I should include the entire DevicePathUtiltiies.c and ifdef out what we don't use */
-
/*
* Taken from MdePkg/Library/UefiDevicePathLib/DevicePathUtilities.c
- * hash a11928f3310518ab1c6fd34e8d0fdbb72de9602c 2017-Mar-01
+ * hash 2f88bd3a1296c522317f1c21377876de63de5be7 2021-Dec-07
*/
/** @file
@@ -52,17 +50,13 @@
environment varibles. Multi-instance device paths should never be placed
on a Handle.
- Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
- This program and the accompanying materials
- are licensed and made available under the terms and conditions of the BSD License
- which accompanies this distribution. The full text of the license may be found at
- http://opensource.org/licenses/bsd-license.php.
-
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
**/
+// #include "UefiDevicePathLib.h"
+
//
// Template for an end-of-device path node.
//
@@ -75,59 +69,16 @@ static CONST EFI_DEVICE_PATH_PROTOCOL mUefiDevicePathLibEndDevicePath = {
}
};
-
-/**
- Returns the size of a device path in bytes.
-
- This function returns the size, in bytes, of the device path data structure
- specified by DevicePath including the end of device path node.
- If DevicePath is NULL or invalid, then 0 is returned.
-
- @param DevicePath A pointer to a device path data structure.
-
- @retval 0 If DevicePath is NULL or invalid.
- @retval Others The size of a device path in bytes.
-
-**/
-UINTN
-EFIAPI
-GetDevicePathSize (
- IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
- )
-{
- CONST EFI_DEVICE_PATH_PROTOCOL *Start;
-
- if (DevicePath == NULL) {
- return 0;
- }
-
- if (!IsDevicePathValid (DevicePath, 0)) {
- return 0;
- }
-
- //
- // Search for the end of the device path structure
- //
- Start = DevicePath;
- while (!IsDevicePathEnd (DevicePath)) {
- DevicePath = NextDevicePathNode (DevicePath);
- }
-
- //
- // Compute the size and add back in the size of the end device path structure
- //
- return ((UINTN) DevicePath - (UINTN) Start) + DevicePathNodeLength (DevicePath);
-}
-
/**
Determine whether a given device path is valid.
- If DevicePath is NULL, then ASSERT().
@param DevicePath A pointer to a device path data structure.
@param MaxSize The maximum size of the device path data structure.
@retval TRUE DevicePath is valid.
- @retval FALSE The length of any node in the DevicePath is less
+ @retval FALSE DevicePath is NULL.
+ @retval FALSE Maxsize is less than sizeof(EFI_DEVICE_PATH_PROTOCOL).
+ @retval FALSE The length of any node Node in the DevicePath is less
than sizeof (EFI_DEVICE_PATH_PROTOCOL).
@retval FALSE If MaxSize is not zero, the size of the DevicePath
exceeds MaxSize.
@@ -137,27 +88,25 @@ GetDevicePathSize (
BOOLEAN
EFIAPI
IsDevicePathValid (
- IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
- IN UINTN MaxSize
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN UINTN MaxSize
)
{
- UINTN Count;
- UINTN Size;
- UINTN NodeLength;
-
- ASSERT (DevicePath != NULL);
-
- if (MaxSize == 0) {
- MaxSize = MAX_UINTN;
- }
+ UINTN Count;
+ UINTN Size;
+ UINTN NodeLength;
//
- // Validate the input size big enough to touch the first node.
+ // Validate the input whether exists and its size big enough to touch the first node
//
- if (MaxSize < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
+ if ((DevicePath == NULL) || ((MaxSize > 0) && (MaxSize < END_DEVICE_PATH_LENGTH))) {
return FALSE;
}
+ if (MaxSize == 0) {
+ MaxSize = MAX_UINTN;
+ }
+
for (Count = 0, Size = 0; !IsDevicePathEnd (DevicePath); DevicePath = NextDevicePathNode (DevicePath)) {
NodeLength = DevicePathNodeLength (DevicePath);
if (NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
@@ -167,6 +116,7 @@ IsDevicePathValid (
if (NodeLength > MAX_UINTN - Size) {
return FALSE;
}
+
Size += NodeLength;
//
@@ -182,12 +132,22 @@ IsDevicePathValid (
return FALSE;
}
}
+
+ //
+ // FilePath must be a NULL-terminated string.
+ //
+ if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
+ (DevicePathSubType (DevicePath) == MEDIA_FILEPATH_DP) &&
+ (*(const CHAR16 *)((const UINT8 *) DevicePath + NodeLength - 2) != 0))
+ {
+ return FALSE;
+ }
}
//
// Only return TRUE when the End Device Path node is valid.
//
- return (BOOLEAN) (DevicePathNodeLength (DevicePath) == END_DEVICE_PATH_LENGTH);
+ return (BOOLEAN)(DevicePathNodeLength (DevicePath) == END_DEVICE_PATH_LENGTH);
}
/**
@@ -212,7 +172,6 @@ DevicePathType (
return ((const EFI_DEVICE_PATH_PROTOCOL *)(Node))->Type;
}
-
/**
Returns the SubType field of a device path node.
@@ -257,6 +216,7 @@ DevicePathNodeLength (
)
{
ASSERT (Node != NULL);
+// return ReadUnaligned16 ((UINT16 *)&((EFI_DEVICE_PATH_PROTOCOL *)(Node))->Length[0]);
return ((const EFI_DEVICE_PATH_PROTOCOL *)Node)->Length[0] |
(((const EFI_DEVICE_PATH_PROTOCOL *)Node)->Length[1] << 8);
}
@@ -282,7 +242,7 @@ NextDevicePathNode (
)
{
ASSERT (Node != NULL);
- return ((EFI_DEVICE_PATH_PROTOCOL *)(__DECONST(UINT8 *, Node) + DevicePathNodeLength(Node)));
+ return (EFI_DEVICE_PATH_PROTOCOL *)(__DECONST(UINT8 *, Node) + DevicePathNodeLength (Node));
}
/**
@@ -312,7 +272,7 @@ IsDevicePathEndType (
)
{
ASSERT (Node != NULL);
- return (BOOLEAN) (DevicePathType (Node) == END_DEVICE_PATH_TYPE);
+ return (BOOLEAN)(DevicePathType (Node) == END_DEVICE_PATH_TYPE);
}
/**
@@ -339,34 +299,37 @@ IsDevicePathEnd (
)
{
ASSERT (Node != NULL);
- return (BOOLEAN) (IsDevicePathEndType (Node) && DevicePathSubType(Node) == END_ENTIRE_DEVICE_PATH_SUBTYPE);
+ return (BOOLEAN)(IsDevicePathEndType (Node) && DevicePathSubType (Node) == END_ENTIRE_DEVICE_PATH_SUBTYPE);
}
+#ifndef __FreeBSD__
/**
- Fills in all the fields of a device path node that is the end of an entire device path.
+ Determines if a device path node is an end node of a device path instance.
- Fills in all the fields of a device path node specified by Node so Node represents
- the end of an entire device path. The Type field of Node is set to
- END_DEVICE_PATH_TYPE, the SubType field of Node is set to
- END_ENTIRE_DEVICE_PATH_SUBTYPE, and the Length field of Node is set to
- END_DEVICE_PATH_LENGTH. Node is not required to be aligned on a 16-bit boundary,
- so it is recommended that a function such as WriteUnaligned16() be used to set
- the contents of the Length field.
+ Determines if a device path node specified by Node is an end node of a device
+ path instance. If Node represents the end of a device path instance, then TRUE
+ is returned. Otherwise, FALSE is returned.
If Node is NULL, then ASSERT().
@param Node A pointer to a device path node data structure.
+ @retval TRUE The device path node specified by Node is the end of a device
+ path instance.
+ @retval FALSE The device path node specified by Node is not the end of a
+ device path instance.
+
**/
-VOID
+BOOLEAN
EFIAPI
-SetDevicePathEndNode (
- OUT VOID *Node
+IsDevicePathEndInstance (
+ IN CONST VOID *Node
)
{
ASSERT (Node != NULL);
- memcpy (Node, &mUefiDevicePathLibEndDevicePath, sizeof (mUefiDevicePathLibEndDevicePath));
+ return (BOOLEAN)(IsDevicePathEndType (Node) && DevicePathSubType (Node) == END_INSTANCE_DEVICE_PATH_SUBTYPE);
}
+#endif
/**
Sets the length, in bytes, of a device path node.
@@ -401,49 +364,72 @@ SetDevicePathNodeLength (
}
/**
- Creates a device node.
+ Fills in all the fields of a device path node that is the end of an entire device path.
- This function creates a new device node in a newly allocated buffer of size
- NodeLength and initializes the device path node header with NodeType and NodeSubType.
- The new device path node is returned.
- If NodeLength is smaller than a device path header, then NULL is returned.
- If there is not enough memory to allocate space for the new device path, then
- NULL is returned.
- The memory is allocated from EFI boot services memory. It is the responsibility
- of the caller to free the memory allocated.
+ Fills in all the fields of a device path node specified by Node so Node represents
+ the end of an entire device path. The Type field of Node is set to
+ END_DEVICE_PATH_TYPE, the SubType field of Node is set to
+ END_ENTIRE_DEVICE_PATH_SUBTYPE, and the Length field of Node is set to
+ END_DEVICE_PATH_LENGTH. Node is not required to be aligned on a 16-bit boundary,
+ so it is recommended that a function such as WriteUnaligned16() be used to set
+ the contents of the Length field.
- @param NodeType The device node type for the new device node.
- @param NodeSubType The device node sub-type for the new device node.
- @param NodeLength The length of the new device node.
+ If Node is NULL, then ASSERT().
- @return The new device path.
+ @param Node A pointer to a device path node data structure.
**/
-EFI_DEVICE_PATH_PROTOCOL *
+VOID
EFIAPI
-CreateDeviceNode (
- IN UINT8 NodeType,
- IN UINT8 NodeSubType,
- IN UINT16 NodeLength
+SetDevicePathEndNode (
+ OUT VOID *Node
)
{
- EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ ASSERT (Node != NULL);
+ memcpy (Node, &mUefiDevicePathLibEndDevicePath, sizeof (mUefiDevicePathLibEndDevicePath));
+}
- if (NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
- //
- // NodeLength is less than the size of the header.
- //
- return NULL;
+/**
+ Returns the size of a device path in bytes.
+
+ This function returns the size, in bytes, of the device path data structure
+ specified by DevicePath including the end of device path node.
+ If DevicePath is NULL or invalid, then 0 is returned.
+
+ @param DevicePath A pointer to a device path data structure.
+
+ @retval 0 If DevicePath is NULL or invalid.
+ @retval Others The size of a device path in bytes.
+
+**/
+UINTN
+EFIAPI
+GetDevicePathSize (
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ CONST EFI_DEVICE_PATH_PROTOCOL *Start;
+
+ if (DevicePath == NULL) {
+ return 0;
}
- DevicePath = AllocateZeroPool (NodeLength);
- if (DevicePath != NULL) {
- DevicePath->Type = NodeType;
- DevicePath->SubType = NodeSubType;
- SetDevicePathNodeLength (DevicePath, NodeLength);
+ if (!IsDevicePathValid (DevicePath, 0)) {
+ return 0;
}
- return DevicePath;
+ //
+ // Search for the end of the device path structure
+ //
+ Start = DevicePath;
+ while (!IsDevicePathEnd (DevicePath)) {
+ DevicePath = NextDevicePathNode (DevicePath);
+ }
+
+ //
+ // Compute the size and add back in the size of the end device path structure
+ //
+ return ((UINTN)DevicePath - (UINTN)Start) + DevicePathNodeLength (DevicePath);
}
/**
@@ -468,7 +454,7 @@ DuplicateDevicePath (
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
)
{
- UINTN Size;
+ UINTN Size;
//
// Compute the size
@@ -512,7 +498,7 @@ DuplicateDevicePath (
EFI_DEVICE_PATH_PROTOCOL *
EFIAPI
AppendDevicePath (
- IN CONST EFI_DEVICE_PATH_PROTOCOL *FirstDevicePath, OPTIONAL
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *FirstDevicePath OPTIONAL,
IN CONST EFI_DEVICE_PATH_PROTOCOL *SecondDevicePath OPTIONAL
)
{
@@ -541,9 +527,9 @@ AppendDevicePath (
// Allocate space for the combined device path. It only has one end node of
// length EFI_DEVICE_PATH_PROTOCOL.
//
- Size1 = GetDevicePathSize (FirstDevicePath);
- Size2 = GetDevicePathSize (SecondDevicePath);
- Size = Size1 + Size2 - END_DEVICE_PATH_LENGTH;
+ Size1 = GetDevicePathSize (FirstDevicePath);
+ Size2 = GetDevicePathSize (SecondDevicePath);
+ Size = Size1 + Size2 - END_DEVICE_PATH_LENGTH;
NewDevicePath = AllocatePool (Size);
@@ -552,8 +538,8 @@ AppendDevicePath (
//
// Over write FirstDevicePath EndNode and do the copy
//
- DevicePath2 = (EFI_DEVICE_PATH_PROTOCOL *) ((CHAR8 *) NewDevicePath +
- (Size1 - END_DEVICE_PATH_LENGTH));
+ DevicePath2 = (EFI_DEVICE_PATH_PROTOCOL *)((CHAR8 *)NewDevicePath +
+ (Size1 - END_DEVICE_PATH_LENGTH));
CopyMem (DevicePath2, SecondDevicePath, Size2);
}
@@ -591,7 +577,7 @@ AppendDevicePath (
EFI_DEVICE_PATH_PROTOCOL *
EFIAPI
AppendDevicePathNode (
- IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath, OPTIONAL
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL,
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePathNode OPTIONAL
)
{
@@ -603,6 +589,7 @@ AppendDevicePathNode (
if (DevicePathNode == NULL) {
return DuplicateDevicePath ((DevicePath != NULL) ? DevicePath : &mUefiDevicePathLibEndDevicePath);
}
+
//
// Build a Node that has a terminator on it
//
@@ -612,6 +599,7 @@ AppendDevicePathNode (
if (TempDevicePath == NULL) {
return NULL;
}
+
TempDevicePath = CopyMem (TempDevicePath, DevicePathNode, NodeLength);
//
// Add and end device path node to convert Node to device path
@@ -627,3 +615,302 @@ AppendDevicePathNode (
return NewDevicePath;
}
+
+#ifndef __FreeBSD__
+/**
+ Creates a new device path by appending the specified device path instance to the specified device
+ path.
+
+ This function creates a new device path by appending a copy of the device path
+ instance specified by DevicePathInstance to a copy of the device path specified
+ by DevicePath in a allocated buffer.
+ The end-of-device-path device node is moved after the end of the appended device
+ path instance and a new end-of-device-path-instance node is inserted between.
+ If DevicePath is NULL, then a copy if DevicePathInstance is returned.
+ If DevicePathInstance is NULL, then NULL is returned.
+ If DevicePath or DevicePathInstance is invalid, then NULL is returned.
+ If there is not enough memory to allocate space for the new device path, then
+ NULL is returned.
+ The memory is allocated from EFI boot services memory. It is the responsibility
+ of the caller to free the memory allocated.
+
+ @param DevicePath A pointer to a device path data structure.
+ @param DevicePathInstance A pointer to a device path instance.
+
+ @return A pointer to the new device path.
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+EFIAPI
+UefiDevicePathLibAppendDevicePathInstance (
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePathInstance OPTIONAL
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ UINTN SrcSize;
+ UINTN InstanceSize;
+
+ if (DevicePath == NULL) {
+ return DuplicateDevicePath (DevicePathInstance);
+ }
+
+ if (DevicePathInstance == NULL) {
+ return NULL;
+ }
+
+ if (!IsDevicePathValid (DevicePath, 0) || !IsDevicePathValid (DevicePathInstance, 0)) {
+ return NULL;
+ }
+
+ SrcSize = GetDevicePathSize (DevicePath);
+ InstanceSize = GetDevicePathSize (DevicePathInstance);
+
+ NewDevicePath = AllocatePool (SrcSize + InstanceSize);
+ if (NewDevicePath != NULL) {
+ TempDevicePath = CopyMem (NewDevicePath, DevicePath, SrcSize);
+
+ while (!IsDevicePathEnd (TempDevicePath)) {
+ TempDevicePath = NextDevicePathNode (TempDevicePath);
+ }
+
+ TempDevicePath->SubType = END_INSTANCE_DEVICE_PATH_SUBTYPE;
+ TempDevicePath = NextDevicePathNode (TempDevicePath);
+ CopyMem (TempDevicePath, DevicePathInstance, InstanceSize);
+ }
+
+ return NewDevicePath;
+}
+
+/**
+ Creates a copy of the current device path instance and returns a pointer to the next device path
+ instance.
+
+ This function creates a copy of the current device path instance. It also updates
+ DevicePath to point to the next device path instance in the device path (or NULL
+ if no more) and updates Size to hold the size of the device path instance copy.
+ If DevicePath is NULL, then NULL is returned.
+ If DevicePath points to a invalid device path, then NULL is returned.
+ If there is not enough memory to allocate space for the new device path, then
+ NULL is returned.
+ The memory is allocated from EFI boot services memory. It is the responsibility
+ of the caller to free the memory allocated.
+ If Size is NULL, then ASSERT().
+
+ @param DevicePath On input, this holds the pointer to the current
+ device path instance. On output, this holds
+ the pointer to the next device path instance
+ or NULL if there are no more device path
+ instances in the device path pointer to a
+ device path data structure.
+ @param Size On output, this holds the size of the device
+ path instance, in bytes or zero, if DevicePath
+ is NULL.
+
+ @return A pointer to the current device path instance.
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+EFIAPI
+UefiDevicePathLibGetNextDevicePathInstance (
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
+ OUT UINTN *Size
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *DevPath;
+ EFI_DEVICE_PATH_PROTOCOL *ReturnValue;
+ UINT8 Temp;
+
+ ASSERT (Size != NULL);
+
+ if ((DevicePath == NULL) || (*DevicePath == NULL)) {
+ *Size = 0;
+ return NULL;
+ }
+
+ if (!IsDevicePathValid (*DevicePath, 0)) {
+ return NULL;
+ }
+
+ //
+ // Find the end of the device path instance
+ //
+ DevPath = *DevicePath;
+ while (!IsDevicePathEndType (DevPath)) {
+ DevPath = NextDevicePathNode (DevPath);
+ }
+
+ //
+ // Compute the size of the device path instance
+ //
+ *Size = ((UINTN)DevPath - (UINTN)(*DevicePath)) + sizeof (EFI_DEVICE_PATH_PROTOCOL);
+
+ //
+ // Make a copy and return the device path instance
+ //
+ Temp = DevPath->SubType;
+ DevPath->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
+ ReturnValue = DuplicateDevicePath (*DevicePath);
+ DevPath->SubType = Temp;
+
+ //
+ // If DevPath is the end of an entire device path, then another instance
+ // does not follow, so *DevicePath is set to NULL.
+ //
+ if (DevicePathSubType (DevPath) == END_ENTIRE_DEVICE_PATH_SUBTYPE) {
+ *DevicePath = NULL;
+ } else {
+ *DevicePath = NextDevicePathNode (DevPath);
+ }
+
+ return ReturnValue;
+}
+#endif
+
+/**
+ Creates a device node.
+
+ This function creates a new device node in a newly allocated buffer of size
+ NodeLength and initializes the device path node header with NodeType and NodeSubType.
+ The new device path node is returned.
+ If NodeLength is smaller than a device path header, then NULL is returned.
+ If there is not enough memory to allocate space for the new device path, then
+ NULL is returned.
+ The memory is allocated from EFI boot services memory. It is the responsibility
+ of the caller to free the memory allocated.
+
+ @param NodeType The device node type for the new device node.
+ @param NodeSubType The device node sub-type for the new device node.
+ @param NodeLength The length of the new device node.
+
+ @return The new device path.
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+EFIAPI
+CreateDeviceNode (
+ IN UINT8 NodeType,
+ IN UINT8 NodeSubType,
+ IN UINT16 NodeLength
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ if (NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
+ //
+ // NodeLength is less than the size of the header.
+ //
+ return NULL;
+ }
+
+ DevicePath = AllocateZeroPool (NodeLength);
+ if (DevicePath != NULL) {
+ DevicePath->Type = NodeType;
+ DevicePath->SubType = NodeSubType;
+ SetDevicePathNodeLength (DevicePath, NodeLength);
+ }
+
+ return DevicePath;
+}
+
+#ifndef __FreeBSD__
+/**
+ Determines if a device path is single or multi-instance.
+
+ This function returns TRUE if the device path specified by DevicePath is
+ multi-instance.
+ Otherwise, FALSE is returned.
+ If DevicePath is NULL or invalid, then FALSE is returned.
+
+ @param DevicePath A pointer to a device path data structure.
+
+ @retval TRUE DevicePath is multi-instance.
+ @retval FALSE DevicePath is not multi-instance, or DevicePath
+ is NULL or invalid.
+
+**/
+BOOLEAN
+EFIAPI
+UefiDevicePathLibIsDevicePathMultiInstance (
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ CONST EFI_DEVICE_PATH_PROTOCOL *Node;
+
+ if (DevicePath == NULL) {
+ return FALSE;
+ }
+
+ if (!IsDevicePathValid (DevicePath, 0)) {
+ return FALSE;
+ }
+
+ Node = DevicePath;
+ while (!IsDevicePathEnd (Node)) {
+ if (IsDevicePathEndInstance (Node)) {
+ return TRUE;
+ }
+
+ Node = NextDevicePathNode (Node);
+ }
+
+ return FALSE;
+}
+
+/**
+ Allocates a device path for a file and appends it to an existing device path.
+
+ If Device is a valid device handle that contains a device path protocol, then a device path for
+ the file specified by FileName is allocated and appended to the device path associated with the
+ handle Device. The allocated device path is returned. If Device is NULL or Device is a handle
+ that does not support the device path protocol, then a device path containing a single device
+ path node for the file specified by FileName is allocated and returned.
+ The memory for the new device path is allocated from EFI boot services memory. It is the responsibility
+ of the caller to free the memory allocated.
+
+ If FileName is NULL, then ASSERT().
+ If FileName is not aligned on a 16-bit boundary, then ASSERT().
+
+ @param Device A pointer to a device handle. This parameter
+ is optional and may be NULL.
+ @param FileName A pointer to a Null-terminated Unicode string.
+
+ @return The allocated device path.
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+EFIAPI
+FileDevicePath (
+ IN EFI_HANDLE Device OPTIONAL,
+ IN CONST CHAR16 *FileName
+ )
+{
+ UINTN Size;
+ FILEPATH_DEVICE_PATH *FilePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *FileDevicePath;
+
+ DevicePath = NULL;
+
+ Size = StrSize (FileName);
+ FileDevicePath = AllocatePool (Size + SIZE_OF_FILEPATH_DEVICE_PATH + END_DEVICE_PATH_LENGTH);
+ if (FileDevicePath != NULL) {
+ FilePath = (FILEPATH_DEVICE_PATH *)FileDevicePath;
+ FilePath->Header.Type = MEDIA_DEVICE_PATH;
+ FilePath->Header.SubType = MEDIA_FILEPATH_DP;
+ CopyMem (&FilePath->PathName, FileName, Size);
+ SetDevicePathNodeLength (&FilePath->Header, Size + SIZE_OF_FILEPATH_DEVICE_PATH);
+ SetDevicePathEndNode (NextDevicePathNode (&FilePath->Header));
+
+ if (Device != NULL) {
+ DevicePath = DevicePathFromHandle (Device);
+ }
+
+ DevicePath = AppendDevicePath (DevicePath, FileDevicePath);
+ FreePool (FileDevicePath);
+ }
+
+ return DevicePath;
+}
+#endif