diff options
author | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
---|---|---|
committer | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
commit | b7c51c9cf4864df6aabb99a1ae843becd577237c (patch) | |
tree | eebe9b0d0ca03062955223097e57da84dd618b9a /EDK/Foundation/Library/RuntimeDxe/EfiRuntimeLib/RtDevicePath.c | |
download | zprj-master.tar.xz |
Diffstat (limited to 'EDK/Foundation/Library/RuntimeDxe/EfiRuntimeLib/RtDevicePath.c')
-rw-r--r-- | EDK/Foundation/Library/RuntimeDxe/EfiRuntimeLib/RtDevicePath.c | 649 |
1 files changed, 649 insertions, 0 deletions
diff --git a/EDK/Foundation/Library/RuntimeDxe/EfiRuntimeLib/RtDevicePath.c b/EDK/Foundation/Library/RuntimeDxe/EfiRuntimeLib/RtDevicePath.c new file mode 100644 index 0000000..44fc9a1 --- /dev/null +++ b/EDK/Foundation/Library/RuntimeDxe/EfiRuntimeLib/RtDevicePath.c @@ -0,0 +1,649 @@ +/*++ + +Copyright (c) 2006 - 2008, Intel Corporation +All rights reserved. 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. + +Module Name: + + RtDevicePath.c + +Abstract: + + Device Path services. The thing to remember is device paths are built out of + nodes. The device path is terminated by an end node that is length + sizeof(EFI_DEVICE_PATH_PROTOCOL). That would be why there is sizeof(EFI_DEVICE_PATH_PROTOCOL) + all over this file. + + The only place where multi-instance device paths are supported is in + environment varibles. Multi-instance device paths should never be placed + on a Handle. + +--*/ + +#include "Tiano.h" +#include "EfiRuntimeLib.h" +#include "RtDevicePath.h" +#include EFI_GUID_DEFINITION (FrameworkDevicePath) +#include EFI_PROTOCOL_DEFINITION (DevicePath) + +STATIC +VOID * +InternalAllocatePool ( + IN UINTN AllocationSize + ) +/*++ + +Routine Description: + + Allocate BootServicesData pool. + +Arguments: + + AllocationSize - The size to allocate + +Returns: + + Pointer of the buffer allocated. + +--*/ +{ + VOID *Memory; + + Memory = NULL; + gBS->AllocatePool (EfiBootServicesData, AllocationSize, &Memory); + return Memory; +} + +STATIC +VOID * +InternalAllocateCopyPool ( + IN UINTN AllocationSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Allocate BootServicesData pool and use a buffer provided by + caller to fill it. + +Arguments: + + AllocationSize - The size to allocate + + Buffer - Buffer that will be filled into the buffer allocated + +Returns: + + Pointer of the buffer allocated. + +--*/ +{ + VOID *Memory; + + Memory = NULL; + gBS->AllocatePool (EfiBootServicesData, AllocationSize, &Memory); + if (Memory != NULL) { + gBS->CopyMem (Memory, Buffer, AllocationSize); + } + + return Memory; +} + +STATIC +VOID * +InternalAllocateZeroPool ( + IN UINTN AllocationSize + ) +/*++ + +Routine Description: + + Allocate BootServicesData pool and zero it. + +Arguments: + + AllocationSize - The size to allocate + +Returns: + + Pointer of the buffer allocated. + +--*/ +{ + VOID *Memory; + + Memory = InternalAllocatePool (AllocationSize); + if (Memory != NULL) { + gBS->SetMem (Memory, AllocationSize, 0); + } + + return Memory; +} + +EFI_DEVICE_PATH_PROTOCOL * +RtEfiDevicePathInstance ( + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath, + OUT UINTN *Size + ) +/*++ + +Routine Description: + Function retrieves the next device path instance from a device path data structure. + +Arguments: + DevicePath - A pointer to a device path data structure. + + Size - A pointer to the size of a device path instance in bytes. + +Returns: + + This function returns a pointer to the current device path instance. + In addition, it returns the size in bytes of the current device path instance in Size, + and a pointer to the next device path instance in DevicePath. + If there are no more device path instances in DevicePath, then DevicePath will be set to NULL. + +--*/ +{ + EFI_DEVICE_PATH_PROTOCOL *DevPath; + EFI_DEVICE_PATH_PROTOCOL *ReturnValue; + UINT8 Temp; + + if (*DevicePath == NULL) { + if (Size != NULL) { + *Size = 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 + // + if (Size != NULL) { + *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 = RtEfiDuplicateDevicePath (*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; +} + +BOOLEAN +RtEfiIsDevicePathMultiInstance ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +/*++ + +Routine Description: + Return TRUE is this is a multi instance device path. + +Arguments: + DevicePath - A pointer to a device path data structure. + + +Returns: + TRUE - If DevicePath is multi instance. FALSE - If DevicePath is not multi + instance. + +--*/ +{ + EFI_DEVICE_PATH_PROTOCOL *Node; + + if (DevicePath == NULL) { + return FALSE; + } + + Node = DevicePath; + while (!EfiIsDevicePathEnd (Node)) { + if (EfiIsDevicePathEndInstance (Node)) { + return TRUE; + } + + Node = EfiNextDevicePathNode (Node); + } + + return FALSE; +} + +UINTN +RtEfiDevicePathSize ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +/*++ + +Routine Description: + + Calculate the space size of a device path. + +Arguments: + + DevicePath - A specified device path + +Returns: + + The size. + +--*/ +{ + EFI_DEVICE_PATH_PROTOCOL *Start; + + if (DevicePath == NULL) { + return 0; + } + + // + // Search for the end of the device path structure + // + Start = DevicePath; + while (!EfiIsDevicePathEnd (DevicePath)) { + DevicePath = EfiNextDevicePathNode (DevicePath); + } + + // + // Compute the size and add back in the size of the end device path structure + // + return ((UINTN) DevicePath - (UINTN) Start) + sizeof (EFI_DEVICE_PATH_PROTOCOL); +} + +EFI_DEVICE_PATH_PROTOCOL * +RtEfiDevicePathFromHandle ( + IN EFI_HANDLE Handle + ) +/*++ + +Routine Description: + + Get the device path protocol interface installed on a specified handle. + +Arguments: + + Handle - a specified handle + +Returns: + + The device path protocol interface installed on that handle. + +--*/ +{ + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + DevicePath = NULL; + gBS->HandleProtocol ( + Handle, + &gEfiDevicePathProtocolGuid, + (VOID *) &DevicePath + ); + return DevicePath; +} + +EFI_DEVICE_PATH_PROTOCOL * +RtEfiDuplicateDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +/*++ + +Routine Description: + + Duplicate a device path structure. + +Arguments: + + DevicePath - The device path to duplicated. + +Returns: + + The duplicated device path. + +--*/ +{ + EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; + UINTN Size; + + if (DevicePath == NULL) { + return NULL; + } + + // + // Compute the size + // + Size = RtEfiDevicePathSize (DevicePath); + if (Size == 0) { + return NULL; + } + + // + // Allocate space for duplicate device path + // + NewDevicePath = InternalAllocateCopyPool (Size, DevicePath); + + return NewDevicePath; +} + +EFI_DEVICE_PATH_PROTOCOL * +RtEfiAppendDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *Src1, + IN EFI_DEVICE_PATH_PROTOCOL *Src2 + ) +/*++ + +Routine Description: + Function is used to append a Src1 and Src2 together. + +Arguments: + Src1 - A pointer to a device path data structure. + + Src2 - A pointer to a device path data structure. + +Returns: + + A pointer to the new device path is returned. + NULL is returned if space for the new device path could not be allocated from pool. + It is up to the caller to free the memory used by Src1 and Src2 if they are no longer needed. + +--*/ +{ + UINTN Size; + UINTN Size1; + UINTN Size2; + EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; + EFI_DEVICE_PATH_PROTOCOL *SecondDevicePath; + + // + // If there's only 1 path, just duplicate it + // + if (!Src1) { + ASSERT (!IsDevicePathUnpacked (Src2)); + return RtEfiDuplicateDevicePath (Src2); + } + + if (!Src2) { + ASSERT (!IsDevicePathUnpacked (Src1)); + return RtEfiDuplicateDevicePath (Src1); + } + + // + // Allocate space for the combined device path. It only has one end node of + // length EFI_DEVICE_PATH_PROTOCOL + // + Size1 = RtEfiDevicePathSize (Src1); + Size2 = RtEfiDevicePathSize (Src2); + Size = Size1 + Size2 - sizeof (EFI_DEVICE_PATH_PROTOCOL); + + NewDevicePath = InternalAllocateCopyPool (Size, Src1); + + if (NewDevicePath != NULL) { + + // + // Over write Src1 EndNode and do the copy + // + SecondDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) ((CHAR8 *) NewDevicePath + (Size1 - sizeof (EFI_DEVICE_PATH_PROTOCOL))); + EfiCopyMem (SecondDevicePath, Src2, Size2); + } + + return NewDevicePath; +} + +EFI_DEVICE_PATH_PROTOCOL * +RtEfiAppendDevicePathNode ( + IN EFI_DEVICE_PATH_PROTOCOL *Src1, + IN EFI_DEVICE_PATH_PROTOCOL *Node + ) +/*++ + +Routine Description: + Function is used to append a device path node to the end of another device path. + +Arguments: + Src1 - A pointer to a device path data structure. + + Node - A pointer to a device path data structure. + +Returns: + This function returns a pointer to the new device path. + If there is not enough temporary pool memory available to complete this function, + then NULL is returned. + + +--*/ +{ + EFI_DEVICE_PATH_PROTOCOL *Temp; + EFI_DEVICE_PATH_PROTOCOL *NextNode; + EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; + UINTN NodeLength; + + // + // Build a Node that has a terminator on it + // + NodeLength = DevicePathNodeLength (Node); + + Temp = InternalAllocateCopyPool (NodeLength + sizeof (EFI_DEVICE_PATH_PROTOCOL), Node); + if (Temp == NULL) { + return NULL; + } + + // + // Add and end device path node to convert Node to device path + // + NextNode = NextDevicePathNode (Temp); + SetDevicePathEndNode (NextNode); + + // + // Append device paths + // + NewDevicePath = RtEfiAppendDevicePath (Src1, Temp); + gBS->FreePool (Temp); + return NewDevicePath; +} + +EFI_DEVICE_PATH_PROTOCOL * +RtEfiFileDevicePath ( + IN EFI_HANDLE Device OPTIONAL, + IN CHAR16 *FileName + ) +/*++ + +Routine Description: + + This function allocates a device path for a file and appends it to an existiong + device path. + +Arguments: + Device - A pointer to a device handle. + + FileName - A pointer to a Null-terminated Unicodestring. + +Returns: + A device path contain the file name. + +--*/ +{ + UINTN Size; + FILEPATH_DEVICE_PATH *FilePath; + EFI_DEVICE_PATH_PROTOCOL *Eop; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + for (Size = 0; FileName[Size] != 0; Size++) + ; + Size = (Size + 1) * 2; + + FilePath = InternalAllocateZeroPool (Size + SIZE_OF_FILEPATH_DEVICE_PATH + sizeof (EFI_DEVICE_PATH_PROTOCOL)); + + DevicePath = NULL; + + if (FilePath != NULL) { + + // + // Build a file path + // + FilePath->Header.Type = MEDIA_DEVICE_PATH; + FilePath->Header.SubType = MEDIA_FILEPATH_DP; + SetDevicePathNodeLength (&FilePath->Header, Size + SIZE_OF_FILEPATH_DEVICE_PATH); + EfiCopyMem (FilePath->PathName, FileName, Size); + Eop = NextDevicePathNode (&FilePath->Header); + SetDevicePathEndNode (Eop); + + // + // Append file path to device's device path + // + + DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) FilePath; + if (Device != NULL) { + DevicePath = RtEfiAppendDevicePath ( + RtEfiDevicePathFromHandle (Device), + DevicePath + ); + + gBS->FreePool (FilePath); + } + } + + return DevicePath; +} + +EFI_DEVICE_PATH_PROTOCOL * +RtEfiAppendDevicePathInstance ( + IN EFI_DEVICE_PATH_PROTOCOL *Src, + IN EFI_DEVICE_PATH_PROTOCOL *Instance + ) +/*++ + +Routine Description: + + Append a device path instance to another. + +Arguments: + + Src - The device path instance to be appended with. + Instance - The device path instance appending the other. + +Returns: + + The contaction of these two. + +--*/ +{ + UINT8 *Ptr; + EFI_DEVICE_PATH_PROTOCOL *DevPath; + UINTN SrcSize; + UINTN InstanceSize; + + if (Src == NULL) { + return RtEfiDuplicateDevicePath (Instance); + } + + SrcSize = RtEfiDevicePathSize (Src); + InstanceSize = RtEfiDevicePathSize (Instance); + + Ptr = InternalAllocateCopyPool (SrcSize + InstanceSize, Src); + if (Ptr != NULL) { + + DevPath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr; + + while (!IsDevicePathEnd (DevPath)) { + DevPath = NextDevicePathNode (DevPath); + } + // + // Convert the End to an End Instance, since we are + // appending another instacne after this one its a good + // idea. + // + DevPath->SubType = END_INSTANCE_DEVICE_PATH_SUBTYPE; + + DevPath = NextDevicePathNode (DevPath); + EfiCopyMem (DevPath, Instance, InstanceSize); + } + + return (EFI_DEVICE_PATH_PROTOCOL *) Ptr; +} + +VOID +EFIAPI +RtEfiInitializeFwVolDevicepathNode ( + IN MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvDevicePathNode, + IN EFI_GUID *NameGuid + ) +/*++ + +Routine Description: + + Initialize a Firmware Volume (FV) Media Device Path node. + +Arguments: + + FvDevicePathNode - Pointer to a FV device path node to initialize + NameGuid - FV file name to use in FvDevicePathNode + +Returns: + + None + +--*/ +{ + FvDevicePathNode->Header.Type = MEDIA_DEVICE_PATH; + FvDevicePathNode->Header.SubType = MEDIA_FV_FILEPATH_DP; + SetDevicePathNodeLength (&FvDevicePathNode->Header, sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH)); + + EfiCopyMem (&FvDevicePathNode->NameGuid, NameGuid, sizeof(EFI_GUID)); +} + +EFI_GUID * +EFIAPI +RtEfiGetNameGuidFromFwVolDevicePathNode ( + IN MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvDevicePathNode + ) +/*++ + +Routine Description: + + Check to see if the Firmware Volume (FV) Media Device Path is valid. + +Arguments: + + FvDevicePathNode - Pointer to FV device path to check + +Returns: + + NULL - FvDevicePathNode is not valid. + Other - FvDevicePathNode is valid and pointer to NameGuid was returned. + +--*/ +{ + if (DevicePathType (&FvDevicePathNode->Header) == MEDIA_DEVICE_PATH && + DevicePathSubType (&FvDevicePathNode->Header) == MEDIA_FV_FILEPATH_DP) { + return &FvDevicePathNode->NameGuid; + } + + return NULL; +} + |