Add in the 1st version of ECP.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@2832 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
@@ -0,0 +1,607 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) 2004 - 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:
|
||||
|
||||
DevicePath.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 "EfiDriverLib.h"
|
||||
#include EFI_PROTOCOL_DEFINITION (DevicePath)
|
||||
|
||||
EFI_DEVICE_PATH_PROTOCOL *
|
||||
EfiDevicePathInstance (
|
||||
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 = EfiDuplicateDevicePath (*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
|
||||
EfiIsDevicePathMultiInstance (
|
||||
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
|
||||
EfiDevicePathSize (
|
||||
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 *
|
||||
EfiDevicePathFromHandle (
|
||||
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 *
|
||||
EfiDuplicateDevicePath (
|
||||
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 = EfiDevicePathSize (DevicePath);
|
||||
if (Size == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// Allocate space for duplicate device path
|
||||
//
|
||||
NewDevicePath = EfiLibAllocateCopyPool (Size, DevicePath);
|
||||
|
||||
return NewDevicePath;
|
||||
}
|
||||
|
||||
EFI_DEVICE_PATH_PROTOCOL *
|
||||
EfiAppendDevicePath (
|
||||
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 EfiDuplicateDevicePath (Src2);
|
||||
}
|
||||
|
||||
if (!Src2) {
|
||||
ASSERT (!IsDevicePathUnpacked (Src1));
|
||||
return EfiDuplicateDevicePath (Src1);
|
||||
}
|
||||
|
||||
//
|
||||
// Allocate space for the combined device path. It only has one end node of
|
||||
// length EFI_DEVICE_PATH_PROTOCOL
|
||||
//
|
||||
Size1 = EfiDevicePathSize (Src1);
|
||||
Size2 = EfiDevicePathSize (Src2);
|
||||
Size = Size1 + Size2 - sizeof (EFI_DEVICE_PATH_PROTOCOL);
|
||||
|
||||
NewDevicePath = EfiLibAllocateCopyPool (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 *
|
||||
EfiAppendDevicePathNode (
|
||||
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 = EfiLibAllocateCopyPool (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 = EfiAppendDevicePath (Src1, Temp);
|
||||
gBS->FreePool (Temp);
|
||||
return NewDevicePath;
|
||||
}
|
||||
|
||||
EFI_DEVICE_PATH_PROTOCOL *
|
||||
EfiFileDevicePath (
|
||||
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 = EfiLibAllocateZeroPool (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 = EfiAppendDevicePath (
|
||||
EfiDevicePathFromHandle (Device),
|
||||
DevicePath
|
||||
);
|
||||
|
||||
gBS->FreePool (FilePath);
|
||||
}
|
||||
}
|
||||
|
||||
return DevicePath;
|
||||
}
|
||||
|
||||
EFI_DEVICE_PATH_PROTOCOL *
|
||||
EfiAppendDevicePathInstance (
|
||||
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 EfiDuplicateDevicePath (Instance);
|
||||
}
|
||||
|
||||
SrcSize = EfiDevicePathSize (Src);
|
||||
InstanceSize = EfiDevicePathSize (Instance);
|
||||
|
||||
Ptr = EfiLibAllocateCopyPool (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
|
||||
EfiInitializeFwVolDevicepathNode (
|
||||
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
|
||||
|
||||
--*/
|
||||
{
|
||||
#if (EFI_SPECIFICATION_VERSION != 0x00020000)
|
||||
//
|
||||
// Use old Device Path
|
||||
//
|
||||
FvDevicePathNode->Header.Type = MEDIA_DEVICE_PATH;
|
||||
FvDevicePathNode->Header.SubType = MEDIA_FV_FILEPATH_DP;
|
||||
SetDevicePathNodeLength (&FvDevicePathNode->Header, sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH));
|
||||
|
||||
#else
|
||||
//
|
||||
// Use the new Device path that does not conflict with the UEFI 2.0
|
||||
//
|
||||
FvDevicePathNode->Piwg.Header.Type = MEDIA_DEVICE_PATH;
|
||||
FvDevicePathNode->Piwg.Header.SubType = MEDIA_VENDOR_DP;
|
||||
SetDevicePathNodeLength (&FvDevicePathNode->Piwg.Header, sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH));
|
||||
|
||||
//
|
||||
// Add the GUID for generic PIWG device paths
|
||||
//
|
||||
EfiCopyMem (&FvDevicePathNode->Piwg.PiwgSpecificDevicePath, &gEfiFrameworkDevicePathGuid, sizeof(EFI_GUID));
|
||||
|
||||
//
|
||||
// Add in the FW Vol File Path PIWG defined inforation
|
||||
//
|
||||
FvDevicePathNode->Piwg.Type = PIWG_MEDIA_FW_VOL_FILEPATH_DEVICE_PATH_TYPE;
|
||||
|
||||
#endif
|
||||
EfiCopyMem (&FvDevicePathNode->NameGuid, NameGuid, sizeof(EFI_GUID));
|
||||
}
|
||||
|
||||
EFI_GUID *
|
||||
EFIAPI
|
||||
EfiGetNameGuidFromFwVolDevicePathNode (
|
||||
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.
|
||||
|
||||
--*/
|
||||
{
|
||||
#if (EFI_SPECIFICATION_VERSION != 0x00020000)
|
||||
//
|
||||
// Use old Device Path
|
||||
//
|
||||
if (DevicePathType (&FvDevicePathNode->Header) == MEDIA_DEVICE_PATH &&
|
||||
DevicePathSubType (&FvDevicePathNode->Header) == MEDIA_FV_FILEPATH_DP) {
|
||||
return &FvDevicePathNode->NameGuid;
|
||||
}
|
||||
|
||||
#else
|
||||
//
|
||||
// Use the new Device path that does not conflict with the UEFI 2.0
|
||||
//
|
||||
if (DevicePathType (&FvDevicePathNode->Piwg.Header) == MEDIA_DEVICE_PATH &&
|
||||
DevicePathSubType (&FvDevicePathNode->Piwg.Header) == MEDIA_VENDOR_DP) {
|
||||
if (EfiCompareGuid (&gEfiFrameworkDevicePathGuid, &FvDevicePathNode->Piwg.PiwgSpecificDevicePath)) {
|
||||
if (FvDevicePathNode->Piwg.Type == PIWG_MEDIA_FW_VOL_FILEPATH_DEVICE_PATH_TYPE) {
|
||||
return &FvDevicePathNode->NameGuid;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
Reference in New Issue
Block a user