mirror of https://github.com/acidanthera/audk.git
1311 lines
37 KiB
C
1311 lines
37 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:
|
|
|
|
BdsBoot.c
|
|
|
|
Abstract:
|
|
|
|
BDS Lib functions which relate with create or process the boot
|
|
option.
|
|
|
|
--*/
|
|
|
|
#include "EdkGenericBdsLibInternal.h"
|
|
|
|
BOOLEAN mEnumBootDevice = FALSE;
|
|
|
|
EFI_STATUS
|
|
BdsLibDoLegacyBoot (
|
|
IN BDS_COMMON_OPTION *Option
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Boot the legacy system with the boot option
|
|
|
|
Arguments:
|
|
|
|
Option - The legacy boot option which have BBS device path
|
|
|
|
Returns:
|
|
|
|
EFI_UNSUPPORTED - There is no legacybios protocol, do not support
|
|
legacy boot.
|
|
|
|
EFI_STATUS - Return the status of LegacyBios->LegacyBoot ().
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
|
|
|
|
Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, &LegacyBios);
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// If no LegacyBios protocol we do not support legacy boot
|
|
//
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
//
|
|
// Notes: if we seperate the int 19, then we don't need to refresh BBS
|
|
//
|
|
BdsRefreshBbsTableForBoot (Option);
|
|
|
|
//
|
|
// Write boot to OS performance data to a file
|
|
//
|
|
PERF_CODE (
|
|
WriteBootToOsPerformanceData ();
|
|
);
|
|
|
|
|
|
DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Legacy Boot: %S\n", Option->Description));
|
|
return LegacyBios->LegacyBoot (
|
|
LegacyBios,
|
|
(BBS_BBS_DEVICE_PATH *) Option->DevicePath,
|
|
Option->LoadOptionsSize,
|
|
Option->LoadOptions
|
|
);
|
|
}
|
|
|
|
EFI_STATUS
|
|
BdsLibBootViaBootOption (
|
|
IN BDS_COMMON_OPTION * Option,
|
|
IN EFI_DEVICE_PATH_PROTOCOL * DevicePath,
|
|
OUT UINTN *ExitDataSize,
|
|
OUT CHAR16 **ExitData OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process the boot option follow the EFI 1.1 specification and
|
|
special treat the legacy boot option with BBS_DEVICE_PATH.
|
|
|
|
Arguments:
|
|
|
|
Option - The boot option need to be processed
|
|
|
|
DevicePath - The device path which describe where to load
|
|
the boot image or the legcy BBS device path
|
|
to boot the legacy OS
|
|
|
|
ExitDataSize - Returned directly from gBS->StartImage ()
|
|
|
|
ExitData - Returned directly from gBS->StartImage ()
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - Status from gBS->StartImage (),
|
|
or BdsBootByDiskSignatureAndPartition ()
|
|
|
|
EFI_NOT_FOUND - If the Device Path is not found in the system
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE Handle;
|
|
EFI_HANDLE ImageHandle;
|
|
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL *FilePath;
|
|
EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
|
|
EFI_BLOCK_IO_PROTOCOL *BlkIo;
|
|
VOID *Buffer;
|
|
LIST_ENTRY TempBootLists;
|
|
|
|
//
|
|
// Record the performance data for End of BDS
|
|
//
|
|
PERF_END (0, BDS_TOK, NULL, 0);
|
|
|
|
*ExitDataSize = 0;
|
|
*ExitData = NULL;
|
|
|
|
//
|
|
// Notes: put EFI64 ROM Shadow Solution
|
|
//
|
|
EFI64_SHADOW_ALL_LEGACY_ROM ();
|
|
|
|
//
|
|
// If it's Device Path that starts with a hard drive path,
|
|
// this routine will do the booting.
|
|
//
|
|
Status = BdsBootByDiskSignatureAndPartition (
|
|
Option,
|
|
(HARDDRIVE_DEVICE_PATH *) DevicePath,
|
|
Option->LoadOptionsSize,
|
|
Option->LoadOptions,
|
|
ExitDataSize,
|
|
ExitData
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
//
|
|
// If we found a disk signature and partition device path return success
|
|
//
|
|
return EFI_SUCCESS;
|
|
}
|
|
//
|
|
// Signal the EFI_EVENT_SIGNAL_READY_TO_BOOT event
|
|
//
|
|
EfiSignalEventReadyToBoot ();
|
|
|
|
//
|
|
// Set Boot Current
|
|
//
|
|
gRT->SetVariable (
|
|
L"BootCurrent",
|
|
&gEfiGlobalVariableGuid,
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
|
sizeof (UINT16),
|
|
&Option->BootCurrent
|
|
);
|
|
|
|
if ((DevicePathType (Option->DevicePath) == BBS_DEVICE_PATH) &&
|
|
(DevicePathSubType (Option->DevicePath) == BBS_BBS_DP)
|
|
) {
|
|
//
|
|
// Check to see if we should legacy BOOT. If yes then do the legacy boot
|
|
//
|
|
return BdsLibDoLegacyBoot (Option);
|
|
}
|
|
|
|
//
|
|
// If the boot option point to Internal FV shell, make sure it is valid
|
|
//
|
|
Status = UpdateFvFileDevicePath (&DevicePath, &gEfiShellFileGuid);
|
|
if (!EFI_ERROR(Status)) {
|
|
if (Option->DevicePath != NULL) {
|
|
FreePool (Option->DevicePath);
|
|
}
|
|
Option->DevicePath = AllocateZeroPool (GetDevicePathSize (DevicePath));
|
|
CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath));
|
|
//
|
|
// Update the shell boot option
|
|
//
|
|
InitializeListHead (&TempBootLists);
|
|
BdsLibRegisterNewOption (&TempBootLists, DevicePath, L"EFI Internal Shell", L"BootOrder");
|
|
}
|
|
|
|
DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Booting EFI 1.1 way %S\n", Option->Description));
|
|
|
|
Status = gBS->LoadImage (
|
|
TRUE,
|
|
mBdsImageHandle,
|
|
DevicePath,
|
|
NULL,
|
|
0,
|
|
&ImageHandle
|
|
);
|
|
|
|
//
|
|
// If we didn't find an image, we may need to load the default
|
|
// boot behavior for the device.
|
|
//
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// Find a Simple File System protocol on the device path. If the remaining
|
|
// device path is set to end then no Files are being specified, so try
|
|
// the removable media file name.
|
|
//
|
|
TempDevicePath = DevicePath;
|
|
Status = gBS->LocateDevicePath (
|
|
&gEfiSimpleFileSystemProtocolGuid,
|
|
&TempDevicePath,
|
|
&Handle
|
|
);
|
|
if (!EFI_ERROR (Status) && IsDevicePathEnd (TempDevicePath)) {
|
|
FilePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
|
|
if (FilePath) {
|
|
//
|
|
// Issue a dummy read to the device to check for media change.
|
|
// When the removable media is changed, any Block IO read/write will
|
|
// cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
|
|
// returned. After the Block IO protocol is reinstalled, subsequent
|
|
// Block IO read/write will success.
|
|
//
|
|
Status = gBS->HandleProtocol (
|
|
Handle,
|
|
&gEfiBlockIoProtocolGuid,
|
|
(VOID **) &BlkIo
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
Buffer = AllocatePool (BlkIo->Media->BlockSize);
|
|
if (Buffer != NULL) {
|
|
BlkIo->ReadBlocks (
|
|
BlkIo,
|
|
BlkIo->Media->MediaId,
|
|
0,
|
|
BlkIo->Media->BlockSize,
|
|
Buffer
|
|
);
|
|
FreePool (Buffer);
|
|
}
|
|
}
|
|
|
|
Status = gBS->LoadImage (
|
|
TRUE,
|
|
mBdsImageHandle,
|
|
FilePath,
|
|
NULL,
|
|
0,
|
|
&ImageHandle
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// The DevicePath failed, and it's not a valid
|
|
// removable media device.
|
|
//
|
|
goto Done;
|
|
}
|
|
}
|
|
} else {
|
|
Status = EFI_NOT_FOUND;
|
|
}
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// It there is any error from the Boot attempt exit now.
|
|
//
|
|
goto Done;
|
|
}
|
|
//
|
|
// Provide the image with it's load options
|
|
//
|
|
Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, &ImageInfo);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
if (Option->LoadOptionsSize != 0) {
|
|
ImageInfo->LoadOptionsSize = Option->LoadOptionsSize;
|
|
ImageInfo->LoadOptions = Option->LoadOptions;
|
|
}
|
|
//
|
|
// Before calling the image, enable the Watchdog Timer for
|
|
// the 5 Minute period
|
|
//
|
|
gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
|
|
|
|
Status = gBS->StartImage (ImageHandle, ExitDataSize, ExitData);
|
|
DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Image Return Status = %r\n", Status));
|
|
|
|
//
|
|
// Clear the Watchdog Timer after the image returns
|
|
//
|
|
gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
|
|
|
|
Done:
|
|
//
|
|
// Clear Boot Current
|
|
//
|
|
gRT->SetVariable (
|
|
L"BootCurrent",
|
|
&gEfiGlobalVariableGuid,
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
|
0,
|
|
&Option->BootCurrent
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
BdsBootByDiskSignatureAndPartition (
|
|
IN BDS_COMMON_OPTION * Option,
|
|
IN HARDDRIVE_DEVICE_PATH * HardDriveDevicePath,
|
|
IN UINT32 LoadOptionsSize,
|
|
IN VOID *LoadOptions,
|
|
OUT UINTN *ExitDataSize,
|
|
OUT CHAR16 **ExitData OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check to see if a hard ware device path was passed in. If it was then search
|
|
all the block IO devices for the passed in hard drive device path.
|
|
|
|
Arguments:
|
|
|
|
Option - The current processing boot option.
|
|
|
|
HardDriveDevicePath - EFI Device Path to boot, if it starts with a hard
|
|
drive device path.
|
|
|
|
LoadOptionsSize - Passed into gBS->StartImage ()
|
|
via the loaded image protocol.
|
|
|
|
LoadOptions - Passed into gBS->StartImage ()
|
|
via the loaded image protocol.
|
|
|
|
ExitDataSize - returned directly from gBS->StartImage ()
|
|
|
|
ExitData - returned directly from gBS->StartImage ()
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - Status from gBS->StartImage (),
|
|
or BootByDiskSignatureAndPartition ()
|
|
|
|
EFI_NOT_FOUND - If the Device Path is not found in the system
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN BlockIoHandleCount;
|
|
EFI_HANDLE *BlockIoBuffer;
|
|
EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL *BlockIoHdDevicePath;
|
|
HARDDRIVE_DEVICE_PATH *TmpHdPath;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
|
|
UINTN Index;
|
|
BOOLEAN DevicePathMatch;
|
|
HARDDRIVE_DEVICE_PATH *TempPath;
|
|
|
|
*ExitDataSize = 0;
|
|
*ExitData = NULL;
|
|
|
|
if ( !((DevicePathType (&HardDriveDevicePath->Header) == MEDIA_DEVICE_PATH) &&
|
|
(DevicePathSubType (&HardDriveDevicePath->Header) == MEDIA_HARDDRIVE_DP))
|
|
) {
|
|
//
|
|
// If the HardDriveDevicePath does not start with a Hard Drive Device Path
|
|
// exit.
|
|
//
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
//
|
|
// The boot device have already been connected
|
|
//
|
|
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);
|
|
if (EFI_ERROR (Status) || BlockIoHandleCount == 0) {
|
|
//
|
|
// If there was an error or there are no device handles that support
|
|
// the BLOCK_IO Protocol, then return.
|
|
//
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
//
|
|
// Loop through all the device handles that support the BLOCK_IO Protocol
|
|
//
|
|
for (Index = 0; Index < BlockIoHandleCount; Index++) {
|
|
|
|
Status = gBS->HandleProtocol (BlockIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &BlockIoDevicePath);
|
|
if (EFI_ERROR (Status) || BlockIoDevicePath == NULL) {
|
|
continue;
|
|
}
|
|
//
|
|
// Make PreviousDevicePath == the device path node before the end node
|
|
//
|
|
DevicePath = BlockIoDevicePath;
|
|
BlockIoHdDevicePath = NULL;
|
|
|
|
//
|
|
// find HardDriver device path node
|
|
//
|
|
while (!IsDevicePathEnd (DevicePath)) {
|
|
if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
|
|
(DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)
|
|
) {
|
|
BlockIoHdDevicePath = DevicePath;
|
|
break;
|
|
}
|
|
|
|
DevicePath = NextDevicePathNode (DevicePath);
|
|
}
|
|
|
|
if (BlockIoHdDevicePath == NULL) {
|
|
continue;
|
|
}
|
|
//
|
|
// See if the harddrive device path in blockio matches the orig Hard Drive Node
|
|
//
|
|
DevicePathMatch = FALSE;
|
|
|
|
TmpHdPath = (HARDDRIVE_DEVICE_PATH *) BlockIoHdDevicePath;
|
|
TempPath = (HARDDRIVE_DEVICE_PATH *) BdsLibUnpackDevicePath ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);
|
|
|
|
//
|
|
// Only several fields will be checked. NOT whole NODE
|
|
//
|
|
if ( TmpHdPath->PartitionNumber == TempPath->PartitionNumber &&
|
|
TmpHdPath->MBRType == TempPath->MBRType &&
|
|
TmpHdPath->SignatureType == TempPath->SignatureType &&
|
|
CompareGuid ((EFI_GUID *) TmpHdPath->Signature, (EFI_GUID *) TempPath->Signature)) {
|
|
//
|
|
// Get the matched device path
|
|
//
|
|
DevicePathMatch = TRUE;
|
|
}
|
|
//
|
|
// Only do the boot, when devicepath match
|
|
//
|
|
if (DevicePathMatch) {
|
|
//
|
|
// Combine the Block IO and Hard Drive Device path together and try
|
|
// to boot from it.
|
|
//
|
|
DevicePath = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);
|
|
NewDevicePath = AppendDevicePath (BlockIoDevicePath, DevicePath);
|
|
|
|
//
|
|
// Recursive boot with new device path
|
|
//
|
|
Status = BdsLibBootViaBootOption (Option, NewDevicePath, ExitDataSize, ExitData);
|
|
if (!EFI_ERROR (Status)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
FreePool (BlockIoBuffer);
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
BdsLibDeleteOptionFromHandle (
|
|
IN EFI_HANDLE Handle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Delete the boot option associated with the handle passed in
|
|
|
|
Arguments:
|
|
|
|
Handle - The handle which present the device path to create boot option
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - Delete the boot option success
|
|
|
|
EFI_NOT_FOUND - If the Device Path is not found in the system
|
|
|
|
EFI_OUT_OF_RESOURCES - Lack of memory resource
|
|
|
|
Other - Error return value from SetVariable()
|
|
|
|
--*/
|
|
{
|
|
UINT16 *BootOrder;
|
|
UINT8 *BootOptionVar;
|
|
UINTN BootOrderSize;
|
|
UINTN BootOptionSize;
|
|
EFI_STATUS Status;
|
|
UINTN Index;
|
|
UINT16 BootOption[BOOT_OPTION_MAX_CHAR];
|
|
UINTN DevicePathSize;
|
|
UINTN OptionDevicePathSize;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;
|
|
UINT8 *TempPtr;
|
|
CHAR16 *Description;
|
|
|
|
Status = EFI_SUCCESS;
|
|
BootOrder = NULL;
|
|
BootOrderSize = 0;
|
|
|
|
BootOrder = BdsLibGetVariableAndSize (
|
|
L"BootOrder",
|
|
&gEfiGlobalVariableGuid,
|
|
&BootOrderSize
|
|
);
|
|
if (NULL == BootOrder) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
DevicePath = DevicePathFromHandle (Handle);
|
|
if (DevicePath == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
DevicePathSize = GetDevicePathSize (DevicePath);
|
|
|
|
Index = 0;
|
|
while (Index < BootOrderSize / sizeof (UINT16)) {
|
|
UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
|
|
BootOptionVar = BdsLibGetVariableAndSize (
|
|
BootOption,
|
|
&gEfiGlobalVariableGuid,
|
|
&BootOptionSize
|
|
);
|
|
if (NULL == BootOptionVar) {
|
|
FreePool (BootOrder);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
TempPtr = BootOptionVar;
|
|
TempPtr += sizeof (UINT32) + sizeof (UINT16);
|
|
Description = (CHAR16 *) TempPtr;
|
|
TempPtr += StrSize ((CHAR16 *) TempPtr);
|
|
OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
|
|
OptionDevicePathSize = GetDevicePathSize (OptionDevicePath);
|
|
|
|
//
|
|
// Check whether the device path match
|
|
//
|
|
if ((OptionDevicePathSize == DevicePathSize) &&
|
|
(CompareMem (DevicePath, OptionDevicePath, DevicePathSize) == 0)) {
|
|
BdsDeleteBootOption (BootOrder[Index], BootOrder, &BootOrderSize);
|
|
FreePool (BootOptionVar);
|
|
break;
|
|
}
|
|
|
|
FreePool (BootOptionVar);
|
|
Index++;
|
|
}
|
|
|
|
Status = gRT->SetVariable (
|
|
L"BootOrder",
|
|
&gEfiGlobalVariableGuid,
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
|
|
BootOrderSize,
|
|
BootOrder
|
|
);
|
|
|
|
FreePool (BootOrder);
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
BdsDeleteAllInvalidEfiBootOption (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Delete all invalid EFI boot options. The probable invalid boot option could
|
|
be Removable media or Network boot device.
|
|
|
|
Arguments:
|
|
|
|
VOID
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - Delete all invalid boot option success
|
|
|
|
EFI_NOT_FOUND - Variable "BootOrder" is not found
|
|
|
|
EFI_OUT_OF_RESOURCES - Lack of memory resource
|
|
|
|
Other - Error return value from SetVariable()
|
|
|
|
--*/
|
|
{
|
|
UINT16 *BootOrder;
|
|
UINT8 *BootOptionVar;
|
|
UINTN BootOrderSize;
|
|
UINTN BootOptionSize;
|
|
EFI_STATUS Status;
|
|
UINTN Index;
|
|
UINTN Index2;
|
|
UINT16 BootOption[BOOT_OPTION_MAX_CHAR];
|
|
UINTN OptionDevicePathSize;
|
|
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;
|
|
EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;
|
|
UINT8 *TempPtr;
|
|
CHAR16 *Description;
|
|
EFI_HANDLE Handle;
|
|
BOOLEAN NeedDelete;
|
|
|
|
Status = EFI_SUCCESS;
|
|
BootOrder = NULL;
|
|
BootOrderSize = 0;
|
|
|
|
BootOrder = BdsLibGetVariableAndSize (
|
|
L"BootOrder",
|
|
&gEfiGlobalVariableGuid,
|
|
&BootOrderSize
|
|
);
|
|
if (NULL == BootOrder) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
Index = 0;
|
|
while (Index < BootOrderSize / sizeof (UINT16)) {
|
|
UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
|
|
BootOptionVar = BdsLibGetVariableAndSize (
|
|
BootOption,
|
|
&gEfiGlobalVariableGuid,
|
|
&BootOptionSize
|
|
);
|
|
if (NULL == BootOptionVar) {
|
|
FreePool (BootOrder);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
TempPtr = BootOptionVar;
|
|
TempPtr += sizeof (UINT32) + sizeof (UINT16);
|
|
Description = (CHAR16 *) TempPtr;
|
|
TempPtr += StrSize ((CHAR16 *) TempPtr);
|
|
OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
|
|
OptionDevicePathSize = GetDevicePathSize (OptionDevicePath);
|
|
|
|
//
|
|
// Skip legacy boot option (BBS boot device)
|
|
//
|
|
if ((DevicePathType (OptionDevicePath) == BBS_DEVICE_PATH) &&
|
|
(DevicePathSubType (OptionDevicePath) == BBS_BBS_DP)) {
|
|
FreePool (BootOptionVar);
|
|
Index++;
|
|
continue;
|
|
}
|
|
|
|
TempDevicePath = OptionDevicePath;
|
|
LastDeviceNode = OptionDevicePath;
|
|
while (!EfiIsDevicePathEnd (TempDevicePath)) {
|
|
LastDeviceNode = TempDevicePath;
|
|
TempDevicePath = EfiNextDevicePathNode (TempDevicePath);
|
|
}
|
|
//
|
|
// Skip the boot option that point to a file, since the device path in
|
|
// removable media boot option doesn't contains a file name.
|
|
//
|
|
if (((DevicePathType (LastDeviceNode) == MEDIA_DEVICE_PATH) &&
|
|
(DevicePathSubType (LastDeviceNode) == MEDIA_FILEPATH_DP)) ||
|
|
//
|
|
// Skip boot option for internal Shell, it's always valid
|
|
//
|
|
(EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode) != NULL)) {
|
|
FreePool (BootOptionVar);
|
|
Index++;
|
|
continue;
|
|
}
|
|
|
|
NeedDelete = TRUE;
|
|
//
|
|
// Check if it's a valid boot option for removable media
|
|
//
|
|
TempDevicePath = OptionDevicePath;
|
|
Status = gBS->LocateDevicePath (
|
|
&gEfiSimpleFileSystemProtocolGuid,
|
|
&TempDevicePath,
|
|
&Handle
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
NeedDelete = FALSE;
|
|
}
|
|
//
|
|
// Check if it's a valid boot option for network boot device
|
|
//
|
|
TempDevicePath = OptionDevicePath;
|
|
Status = gBS->LocateDevicePath (
|
|
&gEfiLoadFileProtocolGuid,
|
|
&TempDevicePath,
|
|
&Handle
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
NeedDelete = FALSE;
|
|
}
|
|
|
|
if (NeedDelete) {
|
|
//
|
|
// Delete this invalid boot option "Boot####"
|
|
//
|
|
Status = gRT->SetVariable (
|
|
BootOption,
|
|
&gEfiGlobalVariableGuid,
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
|
|
0,
|
|
NULL
|
|
);
|
|
//
|
|
// Mark this boot option in boot order as deleted
|
|
//
|
|
BootOrder[Index] = 0xffff;
|
|
}
|
|
|
|
FreePool (BootOptionVar);
|
|
Index++;
|
|
}
|
|
|
|
//
|
|
// Adjust boot order array
|
|
//
|
|
Index2 = 0;
|
|
for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
|
|
if (BootOrder[Index] != 0xffff) {
|
|
BootOrder[Index2] = BootOrder[Index];
|
|
Index2 ++;
|
|
}
|
|
}
|
|
Status = gRT->SetVariable (
|
|
L"BootOrder",
|
|
&gEfiGlobalVariableGuid,
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
|
|
Index2 * sizeof (UINT16),
|
|
BootOrder
|
|
);
|
|
|
|
FreePool (BootOrder);
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
BdsLibEnumerateAllBootOption (
|
|
IN OUT LIST_ENTRY *BdsBootOptionList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function will enumerate all possible boot device in the system,
|
|
it will only excute once of every boot.
|
|
|
|
Arguments:
|
|
|
|
BdsBootOptionList - The header of the link list which indexed all
|
|
current boot options
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - Finished all the boot device enumerate and create
|
|
the boot option base on that boot device
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT16 BootOptionNumber;
|
|
UINTN NumberFileSystemHandles;
|
|
EFI_HANDLE *FileSystemHandles;
|
|
EFI_BLOCK_IO_PROTOCOL *BlkIo;
|
|
UINTN Index;
|
|
UINTN NumberLoadFileHandles;
|
|
EFI_HANDLE *LoadFileHandles;
|
|
VOID *ProtocolInstance;
|
|
EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
|
|
UINTN FvHandleCount;
|
|
EFI_HANDLE *FvHandleBuffer;
|
|
EFI_FV_FILETYPE Type;
|
|
UINTN Size;
|
|
EFI_FV_FILE_ATTRIBUTES Attributes;
|
|
UINT32 AuthenticationStatus;
|
|
EFI_DEVICE_PATH_PROTOCOL *FilePath;
|
|
EFI_HANDLE ImageHandle;
|
|
EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
|
|
BOOLEAN NeedDelete;
|
|
|
|
BootOptionNumber = 0;
|
|
|
|
//
|
|
// If the boot device enumerate happened, just get the boot
|
|
// device from the boot order variable
|
|
//
|
|
if (mEnumBootDevice) {
|
|
BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");
|
|
return EFI_SUCCESS;
|
|
}
|
|
//
|
|
// Notes: this dirty code is to get the legacy boot option from the
|
|
// BBS table and create to variable as the EFI boot option, it should
|
|
// be removed after the CSM can provide legacy boot option directly
|
|
//
|
|
REFRESH_LEGACY_BOOT_OPTIONS;
|
|
|
|
//
|
|
// Delete invalid boot option
|
|
//
|
|
BdsDeleteAllInvalidEfiBootOption ();
|
|
//
|
|
// Parse removable media
|
|
//
|
|
gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiSimpleFileSystemProtocolGuid,
|
|
NULL,
|
|
&NumberFileSystemHandles,
|
|
&FileSystemHandles
|
|
);
|
|
for (Index = 0; Index < NumberFileSystemHandles; Index++) {
|
|
Status = gBS->HandleProtocol (
|
|
FileSystemHandles[Index],
|
|
&gEfiBlockIoProtocolGuid,
|
|
(VOID **) &BlkIo
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
if (!BlkIo->Media->RemovableMedia) {
|
|
//
|
|
// If the file system handle supports a BlkIo protocol,
|
|
// skip the removable media devices
|
|
//
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Do the removable Media thing. \EFI\BOOT\boot{machinename}.EFI
|
|
// machinename is ia32, ia64, x64, ...
|
|
//
|
|
FilePath = FileDevicePath (FileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME);
|
|
NeedDelete = TRUE;
|
|
Status = gBS->LoadImage (
|
|
TRUE,
|
|
mBdsImageHandle,
|
|
FilePath,
|
|
NULL,
|
|
0,
|
|
&ImageHandle
|
|
);
|
|
if (!EFI_ERROR(Status)) {
|
|
//
|
|
// Verify the image is a EFI application (and not a driver)
|
|
//
|
|
Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
|
|
ASSERT (!EFI_ERROR(Status));
|
|
|
|
if (ImageInfo->ImageCodeType == EfiLoaderCode) {
|
|
NeedDelete = FALSE;
|
|
}
|
|
}
|
|
|
|
if (NeedDelete) {
|
|
//
|
|
// No such file or the file is not a EFI application, delete this boot option
|
|
//
|
|
BdsLibDeleteOptionFromHandle (FileSystemHandles[Index]);
|
|
} else {
|
|
BdsLibBuildOptionFromHandle (FileSystemHandles[Index], BdsBootOptionList);
|
|
BootOptionNumber++;
|
|
}
|
|
}
|
|
|
|
if (NumberFileSystemHandles) {
|
|
FreePool (FileSystemHandles);
|
|
}
|
|
//
|
|
// Parse Network Boot Device
|
|
//
|
|
gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiSimpleNetworkProtocolGuid,
|
|
NULL,
|
|
&NumberLoadFileHandles,
|
|
&LoadFileHandles
|
|
);
|
|
for (Index = 0; Index < NumberLoadFileHandles; Index++) {
|
|
Status = gBS->HandleProtocol (
|
|
LoadFileHandles[Index],
|
|
&gEfiLoadFileProtocolGuid,
|
|
(VOID **) &ProtocolInstance
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
BdsLibBuildOptionFromHandle (LoadFileHandles[Index], BdsBootOptionList);
|
|
BootOptionNumber++;
|
|
}
|
|
|
|
if (NumberLoadFileHandles) {
|
|
FreePool (LoadFileHandles);
|
|
}
|
|
//
|
|
// Check if we have on flash shell
|
|
//
|
|
gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiFirmwareVolume2ProtocolGuid,
|
|
NULL,
|
|
&FvHandleCount,
|
|
&FvHandleBuffer
|
|
);
|
|
for (Index = 0; Index < FvHandleCount; Index++) {
|
|
gBS->HandleProtocol (
|
|
FvHandleBuffer[Index],
|
|
&gEfiFirmwareVolume2ProtocolGuid,
|
|
(VOID **) &Fv
|
|
);
|
|
|
|
Status = Fv->ReadFile (
|
|
Fv,
|
|
&gEfiShellFileGuid,
|
|
NULL,
|
|
&Size,
|
|
&Type,
|
|
&Attributes,
|
|
&AuthenticationStatus
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// Skip if no shell file in the FV
|
|
//
|
|
continue;
|
|
}
|
|
//
|
|
// Build the shell boot option
|
|
//
|
|
BdsLibBuildOptionFromShell (FvHandleBuffer[Index], BdsBootOptionList);
|
|
BootOptionNumber++;
|
|
}
|
|
|
|
if (FvHandleCount) {
|
|
FreePool (FvHandleBuffer);
|
|
}
|
|
//
|
|
// Make sure every boot only have one time
|
|
// boot device enumerate
|
|
//
|
|
BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");
|
|
mEnumBootDevice = TRUE;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
BdsLibBuildOptionFromHandle (
|
|
IN EFI_HANDLE Handle,
|
|
IN LIST_ENTRY *BdsBootOptionList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Build the boot option with the handle parsed in
|
|
|
|
Arguments:
|
|
|
|
Handle - The handle which present the device path to create boot option
|
|
|
|
BdsBootOptionList - The header of the link list which indexed all current
|
|
boot options
|
|
|
|
Returns:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
{
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
CHAR16 *TempString;
|
|
|
|
DevicePath = DevicePathFromHandle (Handle);
|
|
TempString = DevicePathToStr (DevicePath);
|
|
|
|
//
|
|
// Create and register new boot option
|
|
//
|
|
BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, TempString, L"BootOrder");
|
|
}
|
|
|
|
VOID
|
|
BdsLibBuildOptionFromShell (
|
|
IN EFI_HANDLE Handle,
|
|
IN OUT LIST_ENTRY *BdsBootOptionList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Build the on flash shell boot option with the handle parsed in
|
|
|
|
Arguments:
|
|
|
|
Handle - The handle which present the device path to create on flash shell
|
|
boot option
|
|
|
|
BdsBootOptionList - The header of the link list which indexed all current
|
|
boot options
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
MEDIA_FW_VOL_FILEPATH_DEVICE_PATH ShellNode;
|
|
|
|
DevicePath = DevicePathFromHandle (Handle);
|
|
|
|
//
|
|
// Build the shell device path
|
|
//
|
|
EfiInitializeFwVolDevicepathNode (&ShellNode, &gEfiShellFileGuid);
|
|
DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &ShellNode);
|
|
|
|
//
|
|
// Create and register the shell boot option
|
|
//
|
|
BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, L"Internal EFI Shell", L"BootOrder");
|
|
|
|
}
|
|
|
|
VOID
|
|
BdsLibBootNext (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Boot from the EFI1.1 spec defined "BootNext" variable
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
UINT16 *BootNext;
|
|
UINTN BootNextSize;
|
|
CHAR16 Buffer[20];
|
|
BDS_COMMON_OPTION *BootOption;
|
|
LIST_ENTRY TempList;
|
|
UINTN ExitDataSize;
|
|
CHAR16 *ExitData;
|
|
|
|
//
|
|
// Init the boot option name buffer and temp link list
|
|
//
|
|
InitializeListHead (&TempList);
|
|
ZeroMem (Buffer, sizeof (Buffer));
|
|
|
|
BootNext = BdsLibGetVariableAndSize (
|
|
L"BootNext",
|
|
&gEfiGlobalVariableGuid,
|
|
&BootNextSize
|
|
);
|
|
|
|
//
|
|
// Clear the boot next variable first
|
|
//
|
|
if (BootNext != NULL) {
|
|
gRT->SetVariable (
|
|
L"BootNext",
|
|
&gEfiGlobalVariableGuid,
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
|
|
0,
|
|
BootNext
|
|
);
|
|
|
|
//
|
|
// Start to build the boot option and try to boot
|
|
//
|
|
UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *BootNext);
|
|
BootOption = BdsLibVariableToOption (&TempList, Buffer);
|
|
BdsLibConnectDevicePath (BootOption->DevicePath);
|
|
BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);
|
|
}
|
|
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UpdateFvFileDevicePath (
|
|
IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
|
|
IN EFI_GUID *FileGuid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
According to a file guild, check a Fv file device path is valid. If it is invalid,
|
|
try to return the valid device path.
|
|
FV address maybe changes for memory layout adjust from time to time, use this funciton
|
|
could promise the Fv file device path is right.
|
|
|
|
Arguments:
|
|
DevicePath - on input, the Fv file device path need to check
|
|
on output, the updated valid Fv file device path
|
|
|
|
FileGuid - the Fv file guild
|
|
|
|
Returns:
|
|
EFI_INVALID_PARAMETER - the input DevicePath or FileGuid is invalid parameter
|
|
EFI_UNSUPPORTED - the input DevicePath does not contain Fv file guild at all
|
|
EFI_ALREADY_STARTED - the input DevicePath has pointed to Fv file, it is valid
|
|
EFI_SUCCESS - has successfully updated the invalid DevicePath, and return the updated
|
|
device path in DevicePath
|
|
|
|
--*/
|
|
{
|
|
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;
|
|
EFI_STATUS Status;
|
|
EFI_GUID *GuidPoint;
|
|
UINTN Index;
|
|
UINTN FvHandleCount;
|
|
EFI_HANDLE *FvHandleBuffer;
|
|
EFI_FV_FILETYPE Type;
|
|
UINTN Size;
|
|
EFI_FV_FILE_ATTRIBUTES Attributes;
|
|
UINT32 AuthenticationStatus;
|
|
BOOLEAN FindFvFile;
|
|
EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
|
|
EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
|
|
MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FvFileNode;
|
|
EFI_HANDLE FoundFvHandle;
|
|
EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
|
|
|
|
if ((DevicePath == NULL) || (*DevicePath == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
if (FileGuid == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
//
|
|
// Check whether the device path point to the default the input Fv file
|
|
//
|
|
TempDevicePath = *DevicePath;
|
|
LastDeviceNode = TempDevicePath;
|
|
while (!EfiIsDevicePathEnd (TempDevicePath)) {
|
|
LastDeviceNode = TempDevicePath;
|
|
TempDevicePath = EfiNextDevicePathNode (TempDevicePath);
|
|
}
|
|
|
|
GuidPoint = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)LastDeviceNode);
|
|
|
|
if (GuidPoint == NULL) {
|
|
//
|
|
// if this option does not points to a Fv file, just return EFI_UNSUPPORTED
|
|
//
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
if (!CompareGuid (GuidPoint, FileGuid)) {
|
|
//
|
|
// If the Fv file is not the input file guid, just return EFI_UNSUPPORTED
|
|
//
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// Check whether the input Fv file device path is valid
|
|
//
|
|
TempDevicePath = *DevicePath;
|
|
FoundFvHandle = NULL;
|
|
Status = gBS->LocateDevicePath (
|
|
&gEfiFirmwareVolume2ProtocolGuid,
|
|
&TempDevicePath,
|
|
&FoundFvHandle
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = gBS->HandleProtocol (
|
|
FoundFvHandle,
|
|
&gEfiFirmwareVolume2ProtocolGuid,
|
|
(VOID **) &Fv
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
//
|
|
// Set FV ReadFile Buffer as NULL, only need to check whether input Fv file exist there
|
|
//
|
|
Status = Fv->ReadFile (
|
|
Fv,
|
|
FileGuid,
|
|
NULL,
|
|
&Size,
|
|
&Type,
|
|
&Attributes,
|
|
&AuthenticationStatus
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
return EFI_ALREADY_STARTED;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Look for the input wanted FV file in current FV
|
|
// First, try to look for in Bds own FV. Bds and input wanted FV file usually are in the same FV
|
|
//
|
|
FindFvFile = FALSE;
|
|
FoundFvHandle = NULL;
|
|
Status = gBS->HandleProtocol (
|
|
mBdsImageHandle,
|
|
&gEfiLoadedImageProtocolGuid,
|
|
&LoadedImage
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = gBS->HandleProtocol (
|
|
LoadedImage->DeviceHandle,
|
|
&gEfiFirmwareVolume2ProtocolGuid,
|
|
(VOID **) &Fv
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = Fv->ReadFile (
|
|
Fv,
|
|
FileGuid,
|
|
NULL,
|
|
&Size,
|
|
&Type,
|
|
&Attributes,
|
|
&AuthenticationStatus
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
FindFvFile = TRUE;
|
|
FoundFvHandle = LoadedImage->DeviceHandle;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// Second, if fail to find, try to enumerate all FV
|
|
//
|
|
if (!FindFvFile) {
|
|
gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiFirmwareVolume2ProtocolGuid,
|
|
NULL,
|
|
&FvHandleCount,
|
|
&FvHandleBuffer
|
|
);
|
|
for (Index = 0; Index < FvHandleCount; Index++) {
|
|
gBS->HandleProtocol (
|
|
FvHandleBuffer[Index],
|
|
&gEfiFirmwareVolume2ProtocolGuid,
|
|
(VOID **) &Fv
|
|
);
|
|
|
|
Status = Fv->ReadFile (
|
|
Fv,
|
|
FileGuid,
|
|
NULL,
|
|
&Size,
|
|
&Type,
|
|
&Attributes,
|
|
&AuthenticationStatus
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// Skip if input Fv file not in the FV
|
|
//
|
|
continue;
|
|
}
|
|
FindFvFile = TRUE;
|
|
FoundFvHandle = FvHandleBuffer[Index];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (FindFvFile) {
|
|
//
|
|
// Build the shell device path
|
|
//
|
|
NewDevicePath = DevicePathFromHandle (FoundFvHandle);
|
|
EfiInitializeFwVolDevicepathNode (&FvFileNode, FileGuid);
|
|
NewDevicePath = AppendDevicePathNode (NewDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &FvFileNode);
|
|
*DevicePath = NewDevicePath;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|