mirror of https://github.com/acidanthera/audk.git
676 lines
16 KiB
C
676 lines
16 KiB
C
/*++
|
|
|
|
Copyright (c) 2006 - 2007, 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.
|
|
|
|
Tiano extended the EFI 1.10 device path nodes. Tiano does not own this enum
|
|
so as we move to UEFI 2.0 support we must use a mechanism that conforms with
|
|
the UEFI 2.0 specification to define the FV device path. An UEFI GUIDed
|
|
device path is defined for PIWG extensions of device path. If the code
|
|
is compiled to conform with the UEFI 2.0 specification use the new device path
|
|
else use the old form for backwards compatability.
|
|
|
|
Arguments:
|
|
|
|
FvDevicePathNode - Pointer to a FV device path node to initialize
|
|
NameGuid - FV file name to use in FvDevicePathNode
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// EFI Specification extension on Media Device Path. MEDIA_FW_VOL_FILEPATH_DEVICE_PATH is adopted by UEFI later and added in UEFI2.10.
|
|
// In EdkCompatibility Package, we only support MEDIA_FW_VOL_FILEPATH_DEVICE_PATH that complies with
|
|
// EFI 1.10 and UEFI 2.10.
|
|
//
|
|
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.
|
|
|
|
Tiano extended the EFI 1.10 device path nodes. Tiano does not own this enum
|
|
so as we move to UEFI 2.0 support we must use a mechanism that conforms with
|
|
the UEFI 2.0 specification to define the FV device path. An UEFI GUIDed
|
|
device path is defined for PIWG extensions of device path. If the code
|
|
is compiled to conform with the UEFI 2.0 specification use the new device path
|
|
else use the old form for backwards compatability. The return value to this
|
|
function points to a location in FvDevicePathNode and it does not allocate
|
|
new memory for the GUID pointer that is returned.
|
|
|
|
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.
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// EFI Specification extension on Media Device Path. MEDIA_FW_VOL_FILEPATH_DEVICE_PATH is adopted by UEFI later and added in UEFI2.10.
|
|
// In EdkCompatibility Package, we only support MEDIA_FW_VOL_FILEPATH_DEVICE_PATH that complies with
|
|
// EFI 1.10 and UEFI 2.10.
|
|
//
|
|
if (DevicePathType (&FvDevicePathNode->Header) == MEDIA_DEVICE_PATH &&
|
|
DevicePathSubType (&FvDevicePathNode->Header) == MEDIA_FV_FILEPATH_DP) {
|
|
return &FvDevicePathNode->NameGuid;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|