summaryrefslogtreecommitdiff
path: root/EDK/Foundation/Library/RuntimeDxe/EfiRuntimeLib/RtDevicePath.c
diff options
context:
space:
mode:
Diffstat (limited to 'EDK/Foundation/Library/RuntimeDxe/EfiRuntimeLib/RtDevicePath.c')
-rw-r--r--EDK/Foundation/Library/RuntimeDxe/EfiRuntimeLib/RtDevicePath.c649
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;
+}
+