/*-1* Copyright (c) 2017 Netflix, Inc.2*3* Redistribution and use in source and binary forms, with or without4* modification, are permitted provided that the following conditions5* are met:6* 1. Redistributions of source code must retain the above copyright7* notice, this list of conditions and the following disclaimer.8* 2. Redistributions in binary form must reproduce the above copyright9* notice, this list of conditions and the following disclaimer in the10* documentation and/or other materials provided with the distribution.11*12* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND13* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE14* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE15* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE16* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL17* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS18* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)19* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT20* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY21* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF22* SUCH DAMAGE.23*/2425/*26* Routines to format EFI_DEVICE_PATHs from the UEFI standard. Much of27* this file is taken from EDK2 and rototilled.28*/2930#include <efivar.h>31#include <limits.h>32#include <stdio.h>33#include <string.h>34#include <sys/endian.h>35#include "uefi-dplib.h"3637/*38* Taken from MdePkg/Library/UefiDevicePathLib/DevicePathUtilities.c39* hash 2f88bd3a1296c522317f1c21377876de63de5be7 2021-Dec-0740*/4142/** @file43Device Path services. The thing to remember is device paths are built out of44nodes. The device path is terminated by an end node that is length45sizeof(EFI_DEVICE_PATH_PROTOCOL). That would be why there is sizeof(EFI_DEVICE_PATH_PROTOCOL)46all over this file.4748The only place where multi-instance device paths are supported is in49environment varibles. Multi-instance device paths should never be placed50on a Handle.5152Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>53SPDX-License-Identifier: BSD-2-Clause-Patent5455**/5657// #include "UefiDevicePathLib.h"5859//60// Template for an end-of-device path node.61//62static CONST EFI_DEVICE_PATH_PROTOCOL mUefiDevicePathLibEndDevicePath = {63END_DEVICE_PATH_TYPE,64END_ENTIRE_DEVICE_PATH_SUBTYPE,65{66END_DEVICE_PATH_LENGTH,67068}69};7071/**72Determine whether a given device path is valid.7374@param DevicePath A pointer to a device path data structure.75@param MaxSize The maximum size of the device path data structure.7677@retval TRUE DevicePath is valid.78@retval FALSE DevicePath is NULL.79@retval FALSE Maxsize is less than sizeof(EFI_DEVICE_PATH_PROTOCOL).80@retval FALSE The length of any node Node in the DevicePath is less81than sizeof (EFI_DEVICE_PATH_PROTOCOL).82@retval FALSE If MaxSize is not zero, the size of the DevicePath83exceeds MaxSize.84@retval FALSE If PcdMaximumDevicePathNodeCount is not zero, the node85count of the DevicePath exceeds PcdMaximumDevicePathNodeCount.86**/87BOOLEAN88EFIAPI89IsDevicePathValid (90IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,91IN UINTN MaxSize92)93{94UINTN Count;95UINTN Size;96UINTN NodeLength;9798//99// Validate the input whether exists and its size big enough to touch the first node100//101if ((DevicePath == NULL) || ((MaxSize > 0) && (MaxSize < END_DEVICE_PATH_LENGTH))) {102return FALSE;103}104105if (MaxSize == 0) {106MaxSize = MAX_UINTN;107}108109for (Count = 0, Size = 0; !IsDevicePathEnd (DevicePath); DevicePath = NextDevicePathNode (DevicePath)) {110NodeLength = DevicePathNodeLength (DevicePath);111if (NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {112return FALSE;113}114115if (NodeLength > MAX_UINTN - Size) {116return FALSE;117}118119Size += NodeLength;120121//122// Validate next node before touch it.123//124if (Size > MaxSize - END_DEVICE_PATH_LENGTH ) {125return FALSE;126}127128if (PcdGet32 (PcdMaximumDevicePathNodeCount) > 0) {129Count++;130if (Count >= PcdGet32 (PcdMaximumDevicePathNodeCount)) {131return FALSE;132}133}134135//136// FilePath must be a NULL-terminated string.137//138if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&139(DevicePathSubType (DevicePath) == MEDIA_FILEPATH_DP) &&140(*(const CHAR16 *)((const UINT8 *) DevicePath + NodeLength - 2) != 0))141{142return FALSE;143}144}145146//147// Only return TRUE when the End Device Path node is valid.148//149return (BOOLEAN)(DevicePathNodeLength (DevicePath) == END_DEVICE_PATH_LENGTH);150}151152/**153Returns the Type field of a device path node.154155Returns the Type field of the device path node specified by Node.156157If Node is NULL, then ASSERT().158159@param Node A pointer to a device path node data structure.160161@return The Type field of the device path node specified by Node.162163**/164UINT8165EFIAPI166DevicePathType (167IN CONST VOID *Node168)169{170ASSERT (Node != NULL);171return ((const EFI_DEVICE_PATH_PROTOCOL *)(Node))->Type;172}173174/**175Returns the SubType field of a device path node.176177Returns the SubType field of the device path node specified by Node.178179If Node is NULL, then ASSERT().180181@param Node A pointer to a device path node data structure.182183@return The SubType field of the device path node specified by Node.184185**/186UINT8187EFIAPI188DevicePathSubType (189IN CONST VOID *Node190)191{192ASSERT (Node != NULL);193return ((const EFI_DEVICE_PATH_PROTOCOL *)(Node))->SubType;194}195196/**197Returns the 16-bit Length field of a device path node.198199Returns the 16-bit Length field of the device path node specified by Node.200Node is not required to be aligned on a 16-bit boundary, so it is recommended201that a function such as ReadUnaligned16() be used to extract the contents of202the Length field.203204If Node is NULL, then ASSERT().205206@param Node A pointer to a device path node data structure.207208@return The 16-bit Length field of the device path node specified by Node.209210**/211UINTN212EFIAPI213DevicePathNodeLength (214IN CONST VOID *Node215)216{217ASSERT (Node != NULL);218// return ReadUnaligned16 ((UINT16 *)&((EFI_DEVICE_PATH_PROTOCOL *)(Node))->Length[0]);219return ((const EFI_DEVICE_PATH_PROTOCOL *)Node)->Length[0] |220(((const EFI_DEVICE_PATH_PROTOCOL *)Node)->Length[1] << 8);221}222223/**224Returns a pointer to the next node in a device path.225226Returns a pointer to the device path node that follows the device path node227specified by Node.228229If Node is NULL, then ASSERT().230231@param Node A pointer to a device path node data structure.232233@return a pointer to the device path node that follows the device path node234specified by Node.235236**/237EFI_DEVICE_PATH_PROTOCOL *238EFIAPI239NextDevicePathNode (240IN CONST VOID *Node241)242{243ASSERT (Node != NULL);244return (EFI_DEVICE_PATH_PROTOCOL *)(__DECONST(UINT8 *, Node) + DevicePathNodeLength (Node));245}246247/**248Determines if a device path node is an end node of a device path.249This includes nodes that are the end of a device path instance and nodes that250are the end of an entire device path.251252Determines if the device path node specified by Node is an end node of a device path.253This includes nodes that are the end of a device path instance and nodes that are the254end of an entire device path. If Node represents an end node of a device path,255then TRUE is returned. Otherwise, FALSE is returned.256257If Node is NULL, then ASSERT().258259@param Node A pointer to a device path node data structure.260261@retval TRUE The device path node specified by Node is an end node of a262device path.263@retval FALSE The device path node specified by Node is not an end node of264a device path.265266**/267BOOLEAN268EFIAPI269IsDevicePathEndType (270IN CONST VOID *Node271)272{273ASSERT (Node != NULL);274return (BOOLEAN)(DevicePathType (Node) == END_DEVICE_PATH_TYPE);275}276277/**278Determines if a device path node is an end node of an entire device path.279280Determines if a device path node specified by Node is an end node of an entire281device path. If Node represents the end of an entire device path, then TRUE is282returned. Otherwise, FALSE is returned.283284If Node is NULL, then ASSERT().285286@param Node A pointer to a device path node data structure.287288@retval TRUE The device path node specified by Node is the end of an entire289device path.290@retval FALSE The device path node specified by Node is not the end of an291entire device path.292293**/294BOOLEAN295EFIAPI296IsDevicePathEnd (297IN CONST VOID *Node298)299{300ASSERT (Node != NULL);301return (BOOLEAN)(IsDevicePathEndType (Node) && DevicePathSubType (Node) == END_ENTIRE_DEVICE_PATH_SUBTYPE);302}303304#ifndef __FreeBSD__305/**306Determines if a device path node is an end node of a device path instance.307308Determines if a device path node specified by Node is an end node of a device309path instance. If Node represents the end of a device path instance, then TRUE310is returned. Otherwise, FALSE is returned.311312If Node is NULL, then ASSERT().313314@param Node A pointer to a device path node data structure.315316@retval TRUE The device path node specified by Node is the end of a device317path instance.318@retval FALSE The device path node specified by Node is not the end of a319device path instance.320321**/322BOOLEAN323EFIAPI324IsDevicePathEndInstance (325IN CONST VOID *Node326)327{328ASSERT (Node != NULL);329return (BOOLEAN)(IsDevicePathEndType (Node) && DevicePathSubType (Node) == END_INSTANCE_DEVICE_PATH_SUBTYPE);330}331#endif332333/**334Sets the length, in bytes, of a device path node.335336Sets the length of the device path node specified by Node to the value specified337by NodeLength. NodeLength is returned. Node is not required to be aligned on338a 16-bit boundary, so it is recommended that a function such as WriteUnaligned16()339be used to set the contents of the Length field.340341If Node is NULL, then ASSERT().342If NodeLength >= SIZE_64KB, then ASSERT().343If NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL), then ASSERT().344345@param Node A pointer to a device path node data structure.346@param Length The length, in bytes, of the device path node.347348@return Length349350**/351UINT16352EFIAPI353SetDevicePathNodeLength (354IN OUT VOID *Node,355IN UINTN Length356)357{358ASSERT (Node != NULL);359ASSERT ((Length >= sizeof (EFI_DEVICE_PATH_PROTOCOL)) && (Length < SIZE_64KB));360// return WriteUnaligned16 ((UINT16 *)&((EFI_DEVICE_PATH_PROTOCOL *)(Node))->Length[0], (UINT16)(Length));361le16enc(&((EFI_DEVICE_PATH_PROTOCOL *)(Node))->Length[0], (UINT16)(Length));362return Length;363}364365/**366Fills in all the fields of a device path node that is the end of an entire device path.367368Fills in all the fields of a device path node specified by Node so Node represents369the end of an entire device path. The Type field of Node is set to370END_DEVICE_PATH_TYPE, the SubType field of Node is set to371END_ENTIRE_DEVICE_PATH_SUBTYPE, and the Length field of Node is set to372END_DEVICE_PATH_LENGTH. Node is not required to be aligned on a 16-bit boundary,373so it is recommended that a function such as WriteUnaligned16() be used to set374the contents of the Length field.375376If Node is NULL, then ASSERT().377378@param Node A pointer to a device path node data structure.379380**/381VOID382EFIAPI383SetDevicePathEndNode (384OUT VOID *Node385)386{387ASSERT (Node != NULL);388memcpy (Node, &mUefiDevicePathLibEndDevicePath, sizeof (mUefiDevicePathLibEndDevicePath));389}390391/**392Returns the size of a device path in bytes.393394This function returns the size, in bytes, of the device path data structure395specified by DevicePath including the end of device path node.396If DevicePath is NULL or invalid, then 0 is returned.397398@param DevicePath A pointer to a device path data structure.399400@retval 0 If DevicePath is NULL or invalid.401@retval Others The size of a device path in bytes.402403**/404UINTN405EFIAPI406GetDevicePathSize (407IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath408)409{410CONST EFI_DEVICE_PATH_PROTOCOL *Start;411412if (DevicePath == NULL) {413return 0;414}415416if (!IsDevicePathValid (DevicePath, 0)) {417return 0;418}419420//421// Search for the end of the device path structure422//423Start = DevicePath;424while (!IsDevicePathEnd (DevicePath)) {425DevicePath = NextDevicePathNode (DevicePath);426}427428//429// Compute the size and add back in the size of the end device path structure430//431return ((UINTN)DevicePath - (UINTN)Start) + DevicePathNodeLength (DevicePath);432}433434/**435Creates a new copy of an existing device path.436437This function allocates space for a new copy of the device path specified by DevicePath.438If DevicePath is NULL, then NULL is returned. If the memory is successfully439allocated, then the contents of DevicePath are copied to the newly allocated440buffer, and a pointer to that buffer is returned. Otherwise, NULL is returned.441The memory for the new device path is allocated from EFI boot services memory.442It is the responsibility of the caller to free the memory allocated.443444@param DevicePath A pointer to a device path data structure.445446@retval NULL DevicePath is NULL or invalid.447@retval Others A pointer to the duplicated device path.448449**/450EFI_DEVICE_PATH_PROTOCOL *451EFIAPI452DuplicateDevicePath (453IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath454)455{456UINTN Size;457458//459// Compute the size460//461Size = GetDevicePathSize (DevicePath);462if (Size == 0) {463return NULL;464}465466//467// Allocate space for duplicate device path468//469470return AllocateCopyPool (Size, DevicePath);471}472473/**474Creates a new device path by appending a second device path to a first device path.475476This function creates a new device path by appending a copy of SecondDevicePath477to a copy of FirstDevicePath in a newly allocated buffer. Only the end-of-device-path478device node from SecondDevicePath is retained. The newly created device path is479returned. If FirstDevicePath is NULL, then it is ignored, and a duplicate of480SecondDevicePath is returned. If SecondDevicePath is NULL, then it is ignored,481and a duplicate of FirstDevicePath is returned. If both FirstDevicePath and482SecondDevicePath are NULL, then a copy of an end-of-device-path is returned.483484If there is not enough memory for the newly allocated buffer, then NULL is returned.485The memory for the new device path is allocated from EFI boot services memory.486It is the responsibility of the caller to free the memory allocated.487488@param FirstDevicePath A pointer to a device path data structure.489@param SecondDevicePath A pointer to a device path data structure.490491@retval NULL If there is not enough memory for the newly allocated buffer.492@retval NULL If FirstDevicePath or SecondDevicePath is invalid.493@retval Others A pointer to the new device path if success.494Or a copy an end-of-device-path if both FirstDevicePath and SecondDevicePath are NULL.495496**/497EFI_DEVICE_PATH_PROTOCOL *498EFIAPI499AppendDevicePath (500IN CONST EFI_DEVICE_PATH_PROTOCOL *FirstDevicePath OPTIONAL,501IN CONST EFI_DEVICE_PATH_PROTOCOL *SecondDevicePath OPTIONAL502)503{504UINTN Size;505UINTN Size1;506UINTN Size2;507EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;508EFI_DEVICE_PATH_PROTOCOL *DevicePath2;509510//511// If there's only 1 path, just duplicate it.512//513if (FirstDevicePath == NULL) {514return DuplicateDevicePath ((SecondDevicePath != NULL) ? SecondDevicePath : &mUefiDevicePathLibEndDevicePath);515}516517if (SecondDevicePath == NULL) {518return DuplicateDevicePath (FirstDevicePath);519}520521if (!IsDevicePathValid (FirstDevicePath, 0) || !IsDevicePathValid (SecondDevicePath, 0)) {522return NULL;523}524525//526// Allocate space for the combined device path. It only has one end node of527// length EFI_DEVICE_PATH_PROTOCOL.528//529Size1 = GetDevicePathSize (FirstDevicePath);530Size2 = GetDevicePathSize (SecondDevicePath);531Size = Size1 + Size2 - END_DEVICE_PATH_LENGTH;532533NewDevicePath = AllocatePool (Size);534535if (NewDevicePath != NULL) {536NewDevicePath = CopyMem (NewDevicePath, FirstDevicePath, Size1);537//538// Over write FirstDevicePath EndNode and do the copy539//540DevicePath2 = (EFI_DEVICE_PATH_PROTOCOL *)((CHAR8 *)NewDevicePath +541(Size1 - END_DEVICE_PATH_LENGTH));542CopyMem (DevicePath2, SecondDevicePath, Size2);543}544545return NewDevicePath;546}547548/**549Creates a new path by appending the device node to the device path.550551This function creates a new device path by appending a copy of the device node552specified by DevicePathNode to a copy of the device path specified by DevicePath553in an allocated buffer. The end-of-device-path device node is moved after the554end of the appended device node.555If DevicePathNode is NULL then a copy of DevicePath is returned.556If DevicePath is NULL then a copy of DevicePathNode, followed by an end-of-device557path device node is returned.558If both DevicePathNode and DevicePath are NULL then a copy of an end-of-device-path559device node is returned.560If there is not enough memory to allocate space for the new device path, then561NULL is returned.562The memory is allocated from EFI boot services memory. It is the responsibility563of the caller to free the memory allocated.564565@param DevicePath A pointer to a device path data structure.566@param DevicePathNode A pointer to a single device path node.567568@retval NULL If there is not enough memory for the new device path.569@retval Others A pointer to the new device path if success.570A copy of DevicePathNode followed by an end-of-device-path node571if both FirstDevicePath and SecondDevicePath are NULL.572A copy of an end-of-device-path node if both FirstDevicePath573and SecondDevicePath are NULL.574575**/576EFI_DEVICE_PATH_PROTOCOL *577EFIAPI578AppendDevicePathNode (579IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL,580IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePathNode OPTIONAL581)582{583EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;584EFI_DEVICE_PATH_PROTOCOL *NextNode;585EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;586UINTN NodeLength;587588if (DevicePathNode == NULL) {589return DuplicateDevicePath ((DevicePath != NULL) ? DevicePath : &mUefiDevicePathLibEndDevicePath);590}591592//593// Build a Node that has a terminator on it594//595NodeLength = DevicePathNodeLength (DevicePathNode);596597TempDevicePath = AllocatePool (NodeLength + END_DEVICE_PATH_LENGTH);598if (TempDevicePath == NULL) {599return NULL;600}601602TempDevicePath = CopyMem (TempDevicePath, DevicePathNode, NodeLength);603//604// Add and end device path node to convert Node to device path605//606NextNode = NextDevicePathNode (TempDevicePath);607SetDevicePathEndNode (NextNode);608//609// Append device paths610//611NewDevicePath = AppendDevicePath (DevicePath, TempDevicePath);612613FreePool (TempDevicePath);614615return NewDevicePath;616}617618#ifndef __FreeBSD__619/**620Creates a new device path by appending the specified device path instance to the specified device621path.622623This function creates a new device path by appending a copy of the device path624instance specified by DevicePathInstance to a copy of the device path specified625by DevicePath in a allocated buffer.626The end-of-device-path device node is moved after the end of the appended device627path instance and a new end-of-device-path-instance node is inserted between.628If DevicePath is NULL, then a copy if DevicePathInstance is returned.629If DevicePathInstance is NULL, then NULL is returned.630If DevicePath or DevicePathInstance is invalid, then NULL is returned.631If there is not enough memory to allocate space for the new device path, then632NULL is returned.633The memory is allocated from EFI boot services memory. It is the responsibility634of the caller to free the memory allocated.635636@param DevicePath A pointer to a device path data structure.637@param DevicePathInstance A pointer to a device path instance.638639@return A pointer to the new device path.640641**/642EFI_DEVICE_PATH_PROTOCOL *643EFIAPI644UefiDevicePathLibAppendDevicePathInstance (645IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL,646IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePathInstance OPTIONAL647)648{649EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;650EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;651UINTN SrcSize;652UINTN InstanceSize;653654if (DevicePath == NULL) {655return DuplicateDevicePath (DevicePathInstance);656}657658if (DevicePathInstance == NULL) {659return NULL;660}661662if (!IsDevicePathValid (DevicePath, 0) || !IsDevicePathValid (DevicePathInstance, 0)) {663return NULL;664}665666SrcSize = GetDevicePathSize (DevicePath);667InstanceSize = GetDevicePathSize (DevicePathInstance);668669NewDevicePath = AllocatePool (SrcSize + InstanceSize);670if (NewDevicePath != NULL) {671TempDevicePath = CopyMem (NewDevicePath, DevicePath, SrcSize);672673while (!IsDevicePathEnd (TempDevicePath)) {674TempDevicePath = NextDevicePathNode (TempDevicePath);675}676677TempDevicePath->SubType = END_INSTANCE_DEVICE_PATH_SUBTYPE;678TempDevicePath = NextDevicePathNode (TempDevicePath);679CopyMem (TempDevicePath, DevicePathInstance, InstanceSize);680}681682return NewDevicePath;683}684685/**686Creates a copy of the current device path instance and returns a pointer to the next device path687instance.688689This function creates a copy of the current device path instance. It also updates690DevicePath to point to the next device path instance in the device path (or NULL691if no more) and updates Size to hold the size of the device path instance copy.692If DevicePath is NULL, then NULL is returned.693If DevicePath points to a invalid device path, then NULL is returned.694If there is not enough memory to allocate space for the new device path, then695NULL is returned.696The memory is allocated from EFI boot services memory. It is the responsibility697of the caller to free the memory allocated.698If Size is NULL, then ASSERT().699700@param DevicePath On input, this holds the pointer to the current701device path instance. On output, this holds702the pointer to the next device path instance703or NULL if there are no more device path704instances in the device path pointer to a705device path data structure.706@param Size On output, this holds the size of the device707path instance, in bytes or zero, if DevicePath708is NULL.709710@return A pointer to the current device path instance.711712**/713EFI_DEVICE_PATH_PROTOCOL *714EFIAPI715UefiDevicePathLibGetNextDevicePathInstance (716IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,717OUT UINTN *Size718)719{720EFI_DEVICE_PATH_PROTOCOL *DevPath;721EFI_DEVICE_PATH_PROTOCOL *ReturnValue;722UINT8 Temp;723724ASSERT (Size != NULL);725726if ((DevicePath == NULL) || (*DevicePath == NULL)) {727*Size = 0;728return NULL;729}730731if (!IsDevicePathValid (*DevicePath, 0)) {732return NULL;733}734735//736// Find the end of the device path instance737//738DevPath = *DevicePath;739while (!IsDevicePathEndType (DevPath)) {740DevPath = NextDevicePathNode (DevPath);741}742743//744// Compute the size of the device path instance745//746*Size = ((UINTN)DevPath - (UINTN)(*DevicePath)) + sizeof (EFI_DEVICE_PATH_PROTOCOL);747748//749// Make a copy and return the device path instance750//751Temp = DevPath->SubType;752DevPath->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;753ReturnValue = DuplicateDevicePath (*DevicePath);754DevPath->SubType = Temp;755756//757// If DevPath is the end of an entire device path, then another instance758// does not follow, so *DevicePath is set to NULL.759//760if (DevicePathSubType (DevPath) == END_ENTIRE_DEVICE_PATH_SUBTYPE) {761*DevicePath = NULL;762} else {763*DevicePath = NextDevicePathNode (DevPath);764}765766return ReturnValue;767}768#endif769770/**771Creates a device node.772773This function creates a new device node in a newly allocated buffer of size774NodeLength and initializes the device path node header with NodeType and NodeSubType.775The new device path node is returned.776If NodeLength is smaller than a device path header, then NULL is returned.777If there is not enough memory to allocate space for the new device path, then778NULL is returned.779The memory is allocated from EFI boot services memory. It is the responsibility780of the caller to free the memory allocated.781782@param NodeType The device node type for the new device node.783@param NodeSubType The device node sub-type for the new device node.784@param NodeLength The length of the new device node.785786@return The new device path.787788**/789EFI_DEVICE_PATH_PROTOCOL *790EFIAPI791CreateDeviceNode (792IN UINT8 NodeType,793IN UINT8 NodeSubType,794IN UINT16 NodeLength795)796{797EFI_DEVICE_PATH_PROTOCOL *DevicePath;798799if (NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {800//801// NodeLength is less than the size of the header.802//803return NULL;804}805806DevicePath = AllocateZeroPool (NodeLength);807if (DevicePath != NULL) {808DevicePath->Type = NodeType;809DevicePath->SubType = NodeSubType;810SetDevicePathNodeLength (DevicePath, NodeLength);811}812813return DevicePath;814}815816#ifndef __FreeBSD__817/**818Determines if a device path is single or multi-instance.819820This function returns TRUE if the device path specified by DevicePath is821multi-instance.822Otherwise, FALSE is returned.823If DevicePath is NULL or invalid, then FALSE is returned.824825@param DevicePath A pointer to a device path data structure.826827@retval TRUE DevicePath is multi-instance.828@retval FALSE DevicePath is not multi-instance, or DevicePath829is NULL or invalid.830831**/832BOOLEAN833EFIAPI834UefiDevicePathLibIsDevicePathMultiInstance (835IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath836)837{838CONST EFI_DEVICE_PATH_PROTOCOL *Node;839840if (DevicePath == NULL) {841return FALSE;842}843844if (!IsDevicePathValid (DevicePath, 0)) {845return FALSE;846}847848Node = DevicePath;849while (!IsDevicePathEnd (Node)) {850if (IsDevicePathEndInstance (Node)) {851return TRUE;852}853854Node = NextDevicePathNode (Node);855}856857return FALSE;858}859860/**861Allocates a device path for a file and appends it to an existing device path.862863If Device is a valid device handle that contains a device path protocol, then a device path for864the file specified by FileName is allocated and appended to the device path associated with the865handle Device. The allocated device path is returned. If Device is NULL or Device is a handle866that does not support the device path protocol, then a device path containing a single device867path node for the file specified by FileName is allocated and returned.868The memory for the new device path is allocated from EFI boot services memory. It is the responsibility869of the caller to free the memory allocated.870871If FileName is NULL, then ASSERT().872If FileName is not aligned on a 16-bit boundary, then ASSERT().873874@param Device A pointer to a device handle. This parameter875is optional and may be NULL.876@param FileName A pointer to a Null-terminated Unicode string.877878@return The allocated device path.879880**/881EFI_DEVICE_PATH_PROTOCOL *882EFIAPI883FileDevicePath (884IN EFI_HANDLE Device OPTIONAL,885IN CONST CHAR16 *FileName886)887{888UINTN Size;889FILEPATH_DEVICE_PATH *FilePath;890EFI_DEVICE_PATH_PROTOCOL *DevicePath;891EFI_DEVICE_PATH_PROTOCOL *FileDevicePath;892893DevicePath = NULL;894895Size = StrSize (FileName);896FileDevicePath = AllocatePool (Size + SIZE_OF_FILEPATH_DEVICE_PATH + END_DEVICE_PATH_LENGTH);897if (FileDevicePath != NULL) {898FilePath = (FILEPATH_DEVICE_PATH *)FileDevicePath;899FilePath->Header.Type = MEDIA_DEVICE_PATH;900FilePath->Header.SubType = MEDIA_FILEPATH_DP;901CopyMem (&FilePath->PathName, FileName, Size);902SetDevicePathNodeLength (&FilePath->Header, Size + SIZE_OF_FILEPATH_DEVICE_PATH);903SetDevicePathEndNode (NextDevicePathNode (&FilePath->Header));904905if (Device != NULL) {906DevicePath = DevicePathFromHandle (Device);907}908909DevicePath = AppendDevicePath (DevicePath, FileDevicePath);910FreePool (FileDevicePath);911}912913return DevicePath;914}915#endif916917918