* [PATCH] MdeModulePkg/UefiBootManagerLib: Enhance short-form expanding logic
@ 2017-04-06 9:44 Ruiyu Ni
2017-04-07 2:48 ` Tian, Feng
0 siblings, 1 reply; 2+ messages in thread
From: Ruiyu Ni @ 2017-04-06 9:44 UTC (permalink / raw)
To: edk2-devel; +Cc: Feng Tian, Eric Dong, Jeff Fan
Old implementation only finds first matched full device path for a
given short-form device path.
The patch adds internal function BmGetNextLoadOptionBuffer() to finds
all matched full device path for a given short-form device path.
There are 6 kinds of device paths. Some of them match to multiple
load options, some of them don't.
1. Media device path:
Returns multiple load options: The media device path may point
to a physical BlockIo which contains multiple logic partitions,
each logic partitions contains \EFI\BOOT\BOOT${ARCH}.EFI.
2. Short-form hard-drive device path:
Returns one load option because the partition signature is unique.
3. Short-form file-path device path:
Returns multiple load options: There are multiple SimpleFileSystem
instances and each contains the same file.
4. Short-form URI device path:
Returns multiple load options: There are multiple LoadFile
instances and each can boot.
5. Short-form USB device path:
Returns multiple load options: There are multiple UsbIo instances
and each contains the boot-able file.
6. FV device path, device path pointing to SimpleFileSystem, device
path pointing to LoadFile
Returns one load option.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Jeff Fan <jeff.fan@intel.com>
---
MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c | 470 ++++++++++++---------
.../Library/UefiBootManagerLib/BmLoadOption.c | 173 ++++++--
.../Library/UefiBootManagerLib/InternalBm.h | 100 +++--
3 files changed, 475 insertions(+), 268 deletions(-)
diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c b/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
index 8a3a402..aa79c90 100644
--- a/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
+++ b/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
@@ -131,21 +131,16 @@ BmFindBootOptionInVariable (
}
/**
- Get the file buffer using a Memory Mapped Device Path.
-
+ Return the correct FV file path.
FV address may change across reboot. This routine promises the FV file device path is right.
@param FilePath The Memory Mapped Device Path to get the file buffer.
- @param FullPath Receive the updated FV Device Path pointint to the file.
- @param FileSize Receive the file buffer size.
- @return The file buffer.
+ @return The updated FV Device Path pointint to the file.
**/
-VOID *
-BmGetFileBufferByFvFilePath (
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
- OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
- OUT UINTN *FileSize
+EFI_DEVICE_PATH_PROTOCOL *
+BmAdjustFvFilePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
)
{
EFI_STATUS Status;
@@ -153,11 +148,10 @@ BmGetFileBufferByFvFilePath (
EFI_DEVICE_PATH_PROTOCOL *FvFileNode;
EFI_HANDLE FvHandle;
EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
- UINT32 AuthenticationStatus;
UINTN FvHandleCount;
EFI_HANDLE *FvHandles;
EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
- VOID *FileBuffer;
+ EFI_DEVICE_PATH_PROTOCOL *FullPath;
//
// Get the file buffer by using the exactly FilePath.
@@ -165,11 +159,7 @@ BmGetFileBufferByFvFilePath (
FvFileNode = FilePath;
Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &FvFileNode, &FvHandle);
if (!EFI_ERROR (Status)) {
- FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus);
- if (FileBuffer != NULL) {
- *FullPath = DuplicateDevicePath (FilePath);
- }
- return FileBuffer;
+ return DuplicateDevicePath (FilePath);
}
//
@@ -190,11 +180,10 @@ BmGetFileBufferByFvFilePath (
(VOID **) &LoadedImage
);
NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (LoadedImage->DeviceHandle), FvFileNode);
- FileBuffer = BmGetFileBufferByFvFilePath (NewDevicePath, FullPath, FileSize);
+ FullPath = BmAdjustFvFilePath (NewDevicePath);
FreePool (NewDevicePath);
-
- if (FileBuffer != NULL) {
- return FileBuffer;
+ if (FullPath != NULL) {
+ return FullPath;
}
//
@@ -207,22 +196,25 @@ BmGetFileBufferByFvFilePath (
&FvHandleCount,
&FvHandles
);
- for (Index = 0; (Index < FvHandleCount) && (FileBuffer == NULL); Index++) {
+ for (Index = 0; Index < FvHandleCount; Index++) {
if (FvHandles[Index] == LoadedImage->DeviceHandle) {
//
- // Skip current FV
+ // Skip current FV, it was handed in first step.
//
continue;
}
NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (FvHandles[Index]), FvFileNode);
- FileBuffer = BmGetFileBufferByFvFilePath (NewDevicePath, FullPath, FileSize);
+ FullPath = BmAdjustFvFilePath (NewDevicePath);
FreePool (NewDevicePath);
+ if (FullPath != NULL) {
+ break;
+ }
}
if (FvHandles != NULL) {
FreePool (FvHandles);
}
- return FileBuffer;
+ return FullPath;
}
/**
@@ -555,46 +547,64 @@ BmFindUsbDevice (
@param FilePath The device path pointing to a load option.
It could be a short-form device path.
- @param FullPath Return the full device path of the load option after
- short-form device path expanding.
- Caller is responsible to free it.
- @param FileSize Return the load option size.
+ @param FullPath The full path returned by the routine in last call.
+ Set to NULL in first call.
@param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer.
- @return The load option buffer. Caller is responsible to free the memory.
+ @return The next possible full path pointing to the load option.
+ Caller is responsible to free the memory.
**/
-VOID *
+EFI_DEVICE_PATH_PROTOCOL *
BmExpandUsbDevicePath (
IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
- OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
- OUT UINTN *FileSize,
- IN EFI_DEVICE_PATH_PROTOCOL *ShortformNode
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath,
+ IN EFI_DEVICE_PATH_PROTOCOL *ShortformNode
)
{
UINTN ParentDevicePathSize;
EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
- EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *NextFullPath;
EFI_HANDLE *Handles;
UINTN HandleCount;
UINTN Index;
- VOID *FileBuffer;
+ BOOLEAN GetNext;
+ NextFullPath = NULL;
+ GetNext = (BOOLEAN)(FullPath == NULL);
ParentDevicePathSize = (UINTN) ShortformNode - (UINTN) FilePath;
RemainingDevicePath = NextDevicePathNode (ShortformNode);
- FileBuffer = NULL;
Handles = BmFindUsbDevice (FilePath, ParentDevicePathSize, &HandleCount);
- for (Index = 0; (Index < HandleCount) && (FileBuffer == NULL); Index++) {
- FullDevicePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), RemainingDevicePath);
- FileBuffer = EfiBootManagerGetLoadOptionBuffer (FullDevicePath, FullPath, FileSize);
- FreePool (FullDevicePath);
+ for (Index = 0; Index < HandleCount; Index++) {
+ FilePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), RemainingDevicePath);
+ if (FilePath == NULL) {
+ //
+ // Out of memory.
+ //
+ continue;
+ }
+ NextFullPath = BmGetNextLoadOptionDevicePath (FilePath, NULL);
+ FreePool (FilePath);
+ if (NextFullPath == NULL) {
+ //
+ // No BlockIo or SimpleFileSystem under FilePath.
+ //
+ continue;
+ }
+ if (GetNext) {
+ break;
+ } else {
+ GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);
+ FreePool (NextFullPath);
+ NextFullPath = NULL;
+ }
}
if (Handles != NULL) {
FreePool (Handles);
}
- return FileBuffer;
+ return NextFullPath;
}
/**
@@ -602,18 +612,16 @@ BmExpandUsbDevicePath (
@param FilePath The device path pointing to a load option.
It could be a short-form device path.
- @param FullPath Return the full device path of the load option after
- short-form device path expanding.
- Caller is responsible to free it.
- @param FileSize Return the load option size.
+ @param FullPath The full path returned by the routine in last call.
+ Set to NULL in first call.
- @return The load option buffer. Caller is responsible to free the memory.
+ @return The next possible full path pointing to the load option.
+ Caller is responsible to free the memory.
**/
-VOID *
+EFI_DEVICE_PATH_PROTOCOL *
BmExpandFileDevicePath (
IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
- OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
- OUT UINTN *FileSize
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath
)
{
EFI_STATUS Status;
@@ -622,9 +630,8 @@ BmExpandFileDevicePath (
EFI_HANDLE *Handles;
EFI_BLOCK_IO_PROTOCOL *BlockIo;
UINTN MediaType;
- EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
- VOID *FileBuffer;
- UINT32 AuthenticationStatus;
+ EFI_DEVICE_PATH_PROTOCOL *NextFullPath;
+ BOOLEAN GetNext;
EfiBootManagerConnectAll ();
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &HandleCount, &Handles);
@@ -633,6 +640,8 @@ BmExpandFileDevicePath (
Handles = NULL;
}
+ GetNext = (BOOLEAN)(FullPath == NULL);
+ NextFullPath = NULL;
//
// Enumerate all removable media devices followed by all fixed media devices,
// followed by media devices which don't layer on block io.
@@ -647,24 +656,26 @@ BmExpandFileDevicePath (
(MediaType == 1 && BlockIo != NULL && !BlockIo->Media->RemovableMedia) ||
(MediaType == 2 && BlockIo == NULL)
) {
- FullDevicePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), FilePath);
- FileBuffer = GetFileBufferByFilePath (TRUE, FullDevicePath, FileSize, &AuthenticationStatus);
- if (FileBuffer != NULL) {
- *FullPath = FullDevicePath;
- FreePool (Handles);
- return FileBuffer;
+ NextFullPath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), FilePath);
+ if (GetNext) {
+ break;
+ } else {
+ GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);
+ FreePool (NextFullPath);
+ NextFullPath = NULL;
}
- FreePool (FullDevicePath);
}
}
+ if (NextFullPath != NULL) {
+ break;
+ }
}
if (Handles != NULL) {
FreePool (Handles);
}
- *FullPath = NULL;
- return NULL;
+ return NextFullPath;
}
/**
@@ -672,25 +683,25 @@ BmExpandFileDevicePath (
@param FilePath The device path pointing to a load option.
It could be a short-form device path.
- @param FullPath Return the full device path of the load option after
- short-form device path expanding.
- Caller is responsible to free it.
- @param FileSize Return the load option size.
+ @param FullPath The full path returned by the routine in last call.
+ Set to NULL in first call.
- @return The load option buffer. Caller is responsible to free the memory.
+ @return The next possible full path pointing to the load option.
+ Caller is responsible to free the memory.
**/
-VOID *
+EFI_DEVICE_PATH_PROTOCOL *
BmExpandUriDevicePath (
IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
- OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
- OUT UINTN *FileSize
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath
)
{
EFI_STATUS Status;
UINTN Index;
UINTN HandleCount;
EFI_HANDLE *Handles;
- VOID *FileBuffer;
+ EFI_DEVICE_PATH_PROTOCOL *NextFullPath;
+ EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath;
+ BOOLEAN GetNext;
EfiBootManagerConnectAll ();
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiLoadFileProtocolGuid, NULL, &HandleCount, &Handles);
@@ -699,11 +710,29 @@ BmExpandUriDevicePath (
Handles = NULL;
}
- FileBuffer = NULL;
+ NextFullPath = NULL;
+ GetNext = (BOOLEAN)(FullPath == NULL);
for (Index = 0; Index < HandleCount; Index++) {
- FileBuffer = BmGetFileBufferFromLoadFile (Handles[Index], FilePath, FullPath, FileSize);
- if (FileBuffer != NULL) {
+ NextFullPath = BmExpandLoadFile (Handles[Index], FilePath);
+
+ if (NextFullPath == NULL) {
+ continue;
+ }
+
+ if (GetNext) {
break;
+ } else {
+ GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);
+ //
+ // Free the resource occupied by the RAM disk.
+ //
+ RamDiskDevicePath = BmGetRamDiskDevicePath (NextFullPath);
+ if (RamDiskDevicePath != NULL) {
+ BmDestroyRamDisk (RamDiskDevicePath);
+ FreePool (RamDiskDevicePath);
+ }
+ FreePool (NextFullPath);
+ NextFullPath = NULL;
}
}
@@ -711,7 +740,7 @@ BmExpandUriDevicePath (
FreePool (Handles);
}
- return FileBuffer;
+ return NextFullPath;
}
/**
@@ -781,35 +810,28 @@ BmCachePartitionDevicePath (
@param FilePath The device path pointing to a load option.
It could be a short-form device path.
- @param FullPath Return the full device path of the load option after
- short-form device path expanding.
- Caller is responsible to free it.
- @param FileSize Return the load option size.
- @return The load option buffer. Caller is responsible to free the memory.
+ @return The full device path pointing to the load option.
**/
-VOID *
+EFI_DEVICE_PATH_PROTOCOL *
BmExpandPartitionDevicePath (
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
- OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
- OUT UINTN *FileSize
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
)
{
EFI_STATUS Status;
UINTN BlockIoHandleCount;
EFI_HANDLE *BlockIoBuffer;
- VOID *FileBuffer;
EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;
UINTN Index;
EFI_DEVICE_PATH_PROTOCOL *CachedDevicePath;
EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *FullPath;
UINTN CachedDevicePathSize;
BOOLEAN NeedAdjust;
EFI_DEVICE_PATH_PROTOCOL *Instance;
UINTN Size;
- FileBuffer = NULL;
//
// Check if there is prestore 'HDDP' variable.
// If exist, search the front path which point to partition node in the variable instants.
@@ -833,6 +855,7 @@ BmExpandPartitionDevicePath (
ASSERT_EFI_ERROR (Status);
}
+ FullPath = NULL;
if (CachedDevicePath != NULL) {
TempNewDevicePath = CachedDevicePath;
NeedAdjust = FALSE;
@@ -851,10 +874,20 @@ BmExpandPartitionDevicePath (
Status = EfiBootManagerConnectDevicePath (Instance, NULL);
if (!EFI_ERROR (Status)) {
TempDevicePath = AppendDevicePath (Instance, NextDevicePathNode (FilePath));
- FileBuffer = EfiBootManagerGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);
+ //
+ // TempDevicePath = ACPI()/PCI()/ATA()/Partition()
+ // or = ACPI()/PCI()/ATA()/Partition()/.../A.EFI
+ //
+ // When TempDevicePath = ACPI()/PCI()/ATA()/Partition(),
+ // it may expand to two potienal full paths (nested partition, rarely happen):
+ // 1. ACPI()/PCI()/ATA()/Partition()/Partition(A1)/EFI/BootX64.EFI
+ // 2. ACPI()/PCI()/ATA()/Partition()/Partition(A2)/EFI/BootX64.EFI
+ // For simplicity, only #1 is returned.
+ //
+ FullPath = BmGetNextLoadOptionDevicePath (TempDevicePath, NULL);
FreePool (TempDevicePath);
- if (FileBuffer != NULL) {
+ if (FullPath != NULL) {
//
// Adjust the 'HDDP' instances sequence if the matched one is not first one.
//
@@ -875,7 +908,7 @@ BmExpandPartitionDevicePath (
FreePool (Instance);
FreePool (CachedDevicePath);
- return FileBuffer;
+ return FullPath;
}
}
}
@@ -911,10 +944,10 @@ BmExpandPartitionDevicePath (
// Find the matched partition device path
//
TempDevicePath = AppendDevicePath (BlockIoDevicePath, NextDevicePathNode (FilePath));
- FileBuffer = EfiBootManagerGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);
+ FullPath = BmGetNextLoadOptionDevicePath (TempDevicePath, NULL);
FreePool (TempDevicePath);
- if (FileBuffer != NULL) {
+ if (FullPath != NULL) {
BmCachePartitionDevicePath (&CachedDevicePath, BlockIoDevicePath);
//
@@ -940,7 +973,7 @@ BmExpandPartitionDevicePath (
if (BlockIoBuffer != NULL) {
FreePool (BlockIoBuffer);
}
- return FileBuffer;
+ return FullPath;
}
/**
@@ -948,16 +981,16 @@ BmExpandPartitionDevicePath (
by appending EFI_REMOVABLE_MEDIA_FILE_NAME.
@param DevicePath The media device path pointing to a BlockIo or SimpleFileSystem instance.
- @param FullPath Return the full device path pointing to the load option.
- @param FileSize Return the size of the load option.
+ @param FullPath The full path returned by the routine in last call.
+ Set to NULL in first call.
- @return The load option buffer.
+ @return The next possible full path pointing to the load option.
+ Caller is responsible to free the memory.
**/
-VOID *
+EFI_DEVICE_PATH_PROTOCOL *
BmExpandMediaDevicePath (
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
- OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
- OUT UINTN *FileSize
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath
)
{
EFI_STATUS Status;
@@ -965,14 +998,15 @@ BmExpandMediaDevicePath (
EFI_BLOCK_IO_PROTOCOL *BlockIo;
VOID *Buffer;
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *NextFullPath;
UINTN Size;
UINTN TempSize;
EFI_HANDLE *SimpleFileSystemHandles;
UINTN NumberSimpleFileSystemHandles;
UINTN Index;
- VOID *FileBuffer;
- UINT32 AuthenticationStatus;
+ BOOLEAN GetNext;
+ GetNext = (BOOLEAN)(FullPath == NULL);
//
// Check whether the device is connected
//
@@ -981,14 +1015,16 @@ BmExpandMediaDevicePath (
if (!EFI_ERROR (Status)) {
ASSERT (IsDevicePathEnd (TempDevicePath));
- TempDevicePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
- FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus);
- if (FileBuffer == NULL) {
- FreePool (TempDevicePath);
- TempDevicePath = NULL;
+ NextFullPath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
+ //
+ // For device path pointing to simple file system, it only expands to one full path.
+ //
+ if (GetNext) {
+ return NextFullPath;
+ } else {
+ FreePool (NextFullPath);
+ return NULL;
}
- *FullPath = TempDevicePath;
- return FileBuffer;
}
Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
@@ -1025,8 +1061,7 @@ BmExpandMediaDevicePath (
//
// Detect the the default boot file from removable Media
//
- FileBuffer = NULL;
- *FullPath = NULL;
+ NextFullPath = NULL;
Size = GetDevicePathSize (DevicePath) - END_DEVICE_PATH_LENGTH;
gBS->LocateHandleBuffer (
ByProtocol,
@@ -1045,13 +1080,14 @@ BmExpandMediaDevicePath (
// Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
//
if ((Size <= TempSize) && (CompareMem (TempDevicePath, DevicePath, Size) == 0)) {
- TempDevicePath = FileDevicePath (SimpleFileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME);
- FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus);
- if (FileBuffer != NULL) {
- *FullPath = TempDevicePath;
+ NextFullPath = FileDevicePath (SimpleFileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME);
+ if (GetNext) {
break;
+ } else {
+ GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);
+ FreePool (NextFullPath);
+ NextFullPath = NULL;
}
- FreePool (TempDevicePath);
}
}
@@ -1059,7 +1095,7 @@ BmExpandMediaDevicePath (
FreePool (SimpleFileSystemHandles);
}
- return FileBuffer;
+ return NextFullPath;
}
/**
@@ -1098,17 +1134,14 @@ BmMatchHttpBootDevicePath (
Get the file buffer from the file system produced by Load File instance.
@param LoadFileHandle The handle of LoadFile instance.
- @param FullPath Return the full device path pointing to the load option.
- @param FileSize Return the size of the load option.
@param RamDiskHandle Return the RAM Disk handle.
- @return The load option buffer.
+ @return The next possible full path pointing to the load option.
+ Caller is responsible to free the memory.
**/
-VOID *
-BmGetFileBufferFromLoadFileSystem (
+EFI_DEVICE_PATH_PROTOCOL *
+BmExpandNetworkFileSystem (
IN EFI_HANDLE LoadFileHandle,
- OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
- OUT UINTN *FileSize,
OUT EFI_HANDLE *RamDiskHandle
)
{
@@ -1138,6 +1171,9 @@ BmGetFileBufferFromLoadFileSystem (
if (!EFI_ERROR (Status) &&
(Handle == LoadFileHandle) &&
(DevicePathType (Node) == MEDIA_DEVICE_PATH) && (DevicePathSubType (Node) == MEDIA_RAM_DISK_DP)) {
+ //
+ // Find the BlockIo instance populated from the LoadFile.
+ //
Handle = Handles[Index];
break;
}
@@ -1154,13 +1190,16 @@ BmGetFileBufferFromLoadFileSystem (
*RamDiskHandle = Handle;
if (Handle != NULL) {
- return BmExpandMediaDevicePath (DevicePathFromHandle (Handle), FullPath, FileSize);
+ //
+ // Re-use BmExpandMediaDevicePath() to get the full device path of load option.
+ // But assume only one SimpleFileSystem can be found under the BlockIo.
+ //
+ return BmExpandMediaDevicePath (DevicePathFromHandle (Handle), NULL);
} else {
return NULL;
}
}
-
/**
Return the RAM Disk device path created by LoadFile.
@@ -1274,27 +1313,21 @@ BmDestroyRamDisk (
@param LoadFileHandle The specified Load File instance.
@param FilePath The file path which will pass to LoadFile().
- @param FullPath Return the full device path pointing to the load option.
- @param FileSize Return the size of the load option.
- @return The load option buffer or NULL if fails.
+ @return The full device path pointing to the load option buffer.
**/
-VOID *
-BmGetFileBufferFromLoadFile (
+EFI_DEVICE_PATH_PROTOCOL *
+BmExpandLoadFile (
IN EFI_HANDLE LoadFileHandle,
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
- OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
- OUT UINTN *FileSize
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
)
{
EFI_STATUS Status;
EFI_LOAD_FILE_PROTOCOL *LoadFile;
VOID *FileBuffer;
- BOOLEAN LoadFileSystem;
EFI_HANDLE RamDiskHandle;
UINTN BufferSize;
-
- *FileSize = 0;
+ EFI_DEVICE_PATH_PROTOCOL *FullPath;
Status = gBS->OpenProtocol (
LoadFileHandle,
@@ -1313,52 +1346,60 @@ BmGetFileBufferFromLoadFile (
return NULL;
}
- LoadFileSystem = (BOOLEAN) (Status == EFI_WARN_FILE_SYSTEM);
- FileBuffer = LoadFileSystem ? AllocateReservedPages (EFI_SIZE_TO_PAGES (BufferSize)) : AllocatePool (BufferSize);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ //
+ // The load option buffer is directly returned by LoadFile.
+ //
+ return DuplicateDevicePath (DevicePathFromHandle (LoadFileHandle));
+ }
+
+ //
+ // The load option resides in a RAM disk.
+ //
+ FileBuffer = AllocateReservedPages (EFI_SIZE_TO_PAGES (BufferSize));
if (FileBuffer == NULL) {
return NULL;
}
Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);
if (EFI_ERROR (Status)) {
- if (LoadFileSystem) {
- FreePages (FileBuffer, EFI_SIZE_TO_PAGES (BufferSize));
- } else {
- FreePool (FileBuffer);
- }
+ FreePages (FileBuffer, EFI_SIZE_TO_PAGES (BufferSize));
return NULL;
}
- if (LoadFileSystem) {
- FileBuffer = BmGetFileBufferFromLoadFileSystem (LoadFileHandle, FullPath, FileSize, &RamDiskHandle);
- if (FileBuffer == NULL) {
- //
- // If there is no bootable executable in the populated
- //
- BmDestroyRamDisk (DevicePathFromHandle (RamDiskHandle));
- }
- } else {
- *FileSize = BufferSize;
- *FullPath = DuplicateDevicePath (DevicePathFromHandle (LoadFileHandle));
+ FullPath = BmExpandNetworkFileSystem (LoadFileHandle, &RamDiskHandle);
+ if (FullPath == NULL) {
+ //
+ // Free the memory occupied by the RAM disk if there is no BlockIo or SimpleFileSystem instance.
+ //
+ BmDestroyRamDisk (DevicePathFromHandle (RamDiskHandle));
}
- return FileBuffer;
+ return FullPath;
}
/**
- Get the file buffer from all the Load File instances.
+ Return the full device path pointing to the load option.
+
+ FilePath may:
+ 1. Exactly matches to a LoadFile instance.
+ 2. Cannot match to any LoadFile instance. Wide match is required.
+ In either case, the routine may return:
+ 1. A copy of FilePath when FilePath matches to a LoadFile instance and
+ the LoadFile returns a load option buffer.
+ 2. A new device path with IP and URI information updated when wide match
+ happens.
+ 3. A new device path pointing to a load option in RAM disk.
+ In either case, only one full device path is returned for a specified
+ FilePath.
@param FilePath The media device path pointing to a LoadFile instance.
- @param FullPath Return the full device path pointing to the load option.
- @param FileSize Return the size of the load option.
@return The load option buffer.
**/
-VOID *
-BmGetFileBufferFromLoadFiles (
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
- OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
- OUT UINTN *FileSize
+EFI_DEVICE_PATH_PROTOCOL *
+BmExpandLoadFiles (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
)
{
EFI_STATUS Status;
@@ -1411,7 +1452,7 @@ BmGetFileBufferFromLoadFiles (
return NULL;
}
- return BmGetFileBufferFromLoadFile (Handle, FilePath, FullPath, FileSize);
+ return BmExpandLoadFile (Handle, FilePath);
}
/**
@@ -1434,19 +1475,37 @@ EfiBootManagerGetLoadOptionBuffer (
OUT UINTN *FileSize
)
{
+ *FullPath = NULL;
+
+ EfiBootManagerConnectDevicePath (FilePath, NULL);
+ return BmGetNextLoadOptionBuffer (LoadOptionTypeMax, FilePath, FullPath, FileSize);
+}
+
+/**
+ Get the next possible full path pointing to the load option.
+ The routine doesn't guarantee the returned full path points to an existing
+ file, and it also doesn't guarantee the existing file is a valid load option.
+ BmGetNextLoadOptionBuffer() guarantees.
+
+ @param FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+ @param FullPath The full path returned by the routine in last call.
+ Set to NULL in first call.
+
+ @return The next possible full path pointing to the load option.
+ Caller is responsible to free the memory.
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+BmGetNextLoadOptionDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath
+ )
+{
EFI_HANDLE Handle;
- VOID *FileBuffer;
- UINT32 AuthenticationStatus;
EFI_DEVICE_PATH_PROTOCOL *Node;
EFI_STATUS Status;
- ASSERT ((FilePath != NULL) && (FullPath != NULL) && (FileSize != NULL));
-
- EfiBootManagerConnectDevicePath (FilePath, NULL);
-
- *FullPath = NULL;
- *FileSize = 0;
- FileBuffer = NULL;
+ ASSERT (FilePath != NULL);
//
// Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI
@@ -1458,7 +1517,7 @@ EfiBootManagerGetLoadOptionBuffer (
}
if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {
- return BmExpandMediaDevicePath (FilePath, FullPath, FileSize);
+ return BmExpandMediaDevicePath (FilePath, FullPath);
}
//
@@ -1469,19 +1528,23 @@ EfiBootManagerGetLoadOptionBuffer (
//
// Expand the Harddrive device path
//
- return BmExpandPartitionDevicePath (FilePath, FullPath, FileSize);
+ if (FullPath == NULL) {
+ return BmExpandPartitionDevicePath (FilePath);
+ } else {
+ return NULL;
+ }
} else if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) &&
(DevicePathSubType (FilePath) == MEDIA_FILEPATH_DP)) {
//
// Expand the File-path device path
//
- return BmExpandFileDevicePath (FilePath, FullPath, FileSize);
+ return BmExpandFileDevicePath (FilePath, FullPath);
} else if ((DevicePathType (FilePath) == MESSAGING_DEVICE_PATH) &&
(DevicePathSubType (FilePath) == MSG_URI_DP)) {
//
// Expand the URI device path
//
- return BmExpandUriDevicePath (FilePath, FullPath, FileSize);
+ return BmExpandUriDevicePath (FilePath, FullPath);
} else {
for (Node = FilePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) {
if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) &&
@@ -1490,45 +1553,50 @@ EfiBootManagerGetLoadOptionBuffer (
}
}
+ //
+ // Expand the USB WWID/Class device path
+ //
if (!IsDevicePathEnd (Node)) {
- //
- // Expand the USB WWID/Class device path
- //
- FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node);
- if ((FileBuffer == NULL) && (FilePath == Node)) {
+ if (FilePath == Node) {
//
// Boot Option device path starts with USB Class or USB WWID device path.
// For Boot Option device path which doesn't begin with the USB Class or
// USB WWID device path, it's not needed to connect again here.
//
BmConnectUsbShortFormDevicePath (FilePath);
- FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node);
}
- return FileBuffer;
+ return BmExpandUsbDevicePath (FilePath, FullPath, Node);
}
}
//
- // Get file buffer from FV file path.
+ // For the below cases, FilePath only expands to one Full path.
+ // So just handle the case when FullPath == NULL.
+ //
+ if (FullPath != NULL) {
+ return NULL;
+ }
+
+ //
+ // Load option resides in FV.
//
if (BmIsFvFilePath (FilePath)) {
- return BmGetFileBufferByFvFilePath (FilePath, FullPath, FileSize);
+ return BmAdjustFvFilePath (FilePath);
}
//
- // Get file buffer from simple file system.
+ // Load option resides in Simple File System.
//
Node = FilePath;
Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle);
if (!EFI_ERROR (Status)) {
- FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus);
- if (FileBuffer != NULL) {
- *FullPath = DuplicateDevicePath (FilePath);
- }
- return FileBuffer;
+ return DuplicateDevicePath (FilePath);
}
- return BmGetFileBufferFromLoadFiles (FilePath, FullPath, FileSize);
+ //
+ // Last chance to try: Load option may be loaded through LoadFile.
+ //
+ return BmExpandLoadFiles (FilePath);
}
/**
@@ -1686,21 +1754,13 @@ EfiBootManagerBoot (
ImageHandle = NULL;
RamDiskDevicePath = NULL;
if (DevicePathType (BootOption->FilePath) != BBS_DEVICE_PATH) {
- Status = EFI_NOT_FOUND;
- FileBuffer = EfiBootManagerGetLoadOptionBuffer (BootOption->FilePath, &FilePath, &FileSize);
+ Status = EFI_NOT_FOUND;
+ FilePath = NULL;
+ EfiBootManagerConnectDevicePath (BootOption->FilePath, NULL);
+ FileBuffer = BmGetNextLoadOptionBuffer (LoadOptionTypeBoot, BootOption->FilePath, &FilePath, &FileSize);
if (FileBuffer != NULL) {
RamDiskDevicePath = BmGetRamDiskDevicePath (FilePath);
- }
- DEBUG_CODE (
- if (FileBuffer != NULL && CompareMem (BootOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) {
- DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: "));
- BmPrintDp (BootOption->FilePath);
- DEBUG ((EFI_D_INFO, " -> "));
- BmPrintDp (FilePath);
- DEBUG ((EFI_D_INFO, "\n"));
- }
- );
- if (BmIsLoadOptionPeHeaderValid (BootOption->OptionType, FileBuffer, FileSize)) {
+
REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));
Status = gBS->LoadImage (
TRUE,
diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c b/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c
index 116cf28..b0a3505 100644
--- a/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c
+++ b/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c
@@ -1167,6 +1167,10 @@ EfiBootManagerFreeLoadOptions (
Return whether the PE header of the load option is valid or not.
@param[in] Type The load option type.
+ It's used to check whether the load option is valid.
+ When it's LoadOptionTypeMax, the routine only guarantees
+ the load option is a valid PE image but doesn't guarantee
+ the PE's subsystem type is valid.
@param[in] FileBuffer The PE file buffer of the load option.
@param[in] FileSize The size of the load option file.
@@ -1217,7 +1221,8 @@ BmIsLoadOptionPeHeaderValid (
// SysPrep####, Boot####, OsRecovery####, PlatformRecovery#### must be of type Application
//
Subsystem = OptionalHeader->Subsystem;
- if ((Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||
+ if ((Type == LoadOptionTypeMax) ||
+ (Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||
(Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) ||
(Type == LoadOptionTypeSysPrep && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) ||
(Type == LoadOptionTypeBoot && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) ||
@@ -1233,6 +1238,91 @@ BmIsLoadOptionPeHeaderValid (
}
/**
+ Return the next matched load option buffer.
+ The routine keeps calling BmGetNextLoadOptionDevicePath() until a valid
+ load option is read.
+
+ @param Type The load option type.
+ It's used to check whether the load option is valid.
+ When it's LoadOptionTypeMax, the routine only guarantees
+ the load option is a valid PE image but doesn't guarantee
+ the PE's subsystem type is valid.
+ @param FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+ @param FullPath Return the next full device path of the load option after
+ short-form device path expanding.
+ Caller is responsible to free it.
+ NULL to return the first matched full device path.
+ @param FileSize Return the load option size.
+
+ @return The load option buffer. Caller is responsible to free the memory.
+**/
+VOID *
+BmGetNextLoadOptionBuffer (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
+ OUT UINTN *FileSize
+ )
+{
+ VOID *FileBuffer;
+ EFI_DEVICE_PATH_PROTOCOL *PreFullPath;
+ EFI_DEVICE_PATH_PROTOCOL *CurFullPath;
+ UINTN LocalFileSize;
+ UINT32 AuthenticationStatus;
+ EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath;
+
+ LocalFileSize = 0;
+ FileBuffer = NULL;
+ CurFullPath = *FullPath;
+ do {
+ PreFullPath = CurFullPath;
+ CurFullPath = BmGetNextLoadOptionDevicePath (FilePath, CurFullPath);
+ //
+ // Only free the full path created *inside* this routine
+ //
+ if ((PreFullPath != NULL) && (PreFullPath != *FullPath)) {
+ FreePool (PreFullPath);
+ }
+ if (CurFullPath == NULL) {
+ break;
+ }
+ FileBuffer = GetFileBufferByFilePath (TRUE, CurFullPath, &LocalFileSize, &AuthenticationStatus);
+ if ((FileBuffer != NULL) && !BmIsLoadOptionPeHeaderValid (Type, FileBuffer, LocalFileSize)) {
+ //
+ // Free the RAM disk file system if the load option is invalid.
+ //
+ RamDiskDevicePath = BmGetRamDiskDevicePath (FilePath);
+ if (RamDiskDevicePath != NULL) {
+ BmDestroyRamDisk (RamDiskDevicePath);
+ FreePool (RamDiskDevicePath);
+ }
+
+ //
+ // Free the invalid load option buffer.
+ //
+ FreePool (FileBuffer);
+ FileBuffer = NULL;
+ }
+ } while (FileBuffer == NULL);
+
+ if (FileBuffer == NULL) {
+ CurFullPath = NULL;
+ LocalFileSize = 0;
+ }
+
+ DEBUG ((DEBUG_INFO, "[Bds] Expand "));
+ BmPrintDp (FilePath);
+ DEBUG ((DEBUG_INFO, " -> "));
+ BmPrintDp (CurFullPath);
+ DEBUG ((DEBUG_INFO, "\n"));
+
+ *FullPath = CurFullPath;
+ *FileSize = LocalFileSize;
+ return FileBuffer;
+}
+
+/**
Process (load and execute) the load option.
@param LoadOption Pointer to the load option.
@@ -1249,7 +1339,8 @@ EfiBootManagerProcessLoadOption (
)
{
EFI_STATUS Status;
- EFI_DEVICE_PATH_PROTOCOL *FilePath;
+ EFI_DEVICE_PATH_PROTOCOL *PreFullPath;
+ EFI_DEVICE_PATH_PROTOCOL *CurFullPath;
EFI_HANDLE ImageHandle;
EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
VOID *FileBuffer;
@@ -1271,8 +1362,6 @@ EfiBootManagerProcessLoadOption (
return EFI_SUCCESS;
}
- Status = EFI_INVALID_PARAMETER;
-
//
// Load and start the load option.
//
@@ -1282,54 +1371,62 @@ EfiBootManagerProcessLoadOption (
LoadOption->Description
));
ImageHandle = NULL;
- FileBuffer = EfiBootManagerGetLoadOptionBuffer (LoadOption->FilePath, &FilePath, &FileSize);
- DEBUG_CODE (
- if (FileBuffer != NULL && CompareMem (LoadOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) {
- DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: "));
- BmPrintDp (LoadOption->FilePath);
- DEBUG ((EFI_D_INFO, " -> "));
- BmPrintDp (FilePath);
- DEBUG ((EFI_D_INFO, "\n"));
+ CurFullPath = NULL;
+ EfiBootManagerConnectDevicePath (LoadOption->FilePath, NULL);
+
+ //
+ // while() loop is to keep starting next matched load option if the PlatformRecovery#### returns failure status.
+ //
+ while (TRUE) {
+ Status = EFI_INVALID_PARAMETER;
+ PreFullPath = CurFullPath;
+ FileBuffer = BmGetNextLoadOptionBuffer (LoadOption->OptionType, LoadOption->FilePath, &CurFullPath, &FileSize);
+ if (PreFullPath != NULL) {
+ FreePool (PreFullPath);
+ }
+ if (FileBuffer == NULL) {
+ break;
}
- );
- if (BmIsLoadOptionPeHeaderValid (LoadOption->OptionType, FileBuffer, FileSize)) {
Status = gBS->LoadImage (
FALSE,
gImageHandle,
- FilePath,
+ CurFullPath,
FileBuffer,
FileSize,
&ImageHandle
);
- }
- if (FilePath != NULL) {
- FreePool (FilePath);
- }
- if (FileBuffer != NULL) {
FreePool (FileBuffer);
- }
- if (!EFI_ERROR (Status)) {
- Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
- ASSERT_EFI_ERROR (Status);
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&ImageInfo);
+ ASSERT_EFI_ERROR (Status);
- ImageInfo->LoadOptionsSize = LoadOption->OptionalDataSize;
- ImageInfo->LoadOptions = LoadOption->OptionalData;
- //
- // Before calling the image, enable the Watchdog Timer for the 5-minute period
- //
- gBS->SetWatchdogTimer (5 * 60, 0, 0, NULL);
+ ImageInfo->LoadOptionsSize = LoadOption->OptionalDataSize;
+ ImageInfo->LoadOptions = LoadOption->OptionalData;
+ //
+ // Before calling the image, enable the Watchdog Timer for the 5-minute period
+ //
+ gBS->SetWatchdogTimer (5 * 60, 0, 0, NULL);
- LoadOption->Status = gBS->StartImage (ImageHandle, &LoadOption->ExitDataSize, &LoadOption->ExitData);
- DEBUG ((
- DEBUG_INFO | DEBUG_LOAD, "%s%04x Return Status = %r\n",
- mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber, LoadOption->Status
+ LoadOption->Status = gBS->StartImage (ImageHandle, &LoadOption->ExitDataSize, &LoadOption->ExitData);
+ DEBUG ((
+ DEBUG_INFO | DEBUG_LOAD, "%s%04x Return Status = %r\n",
+ mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber, LoadOption->Status
));
- //
- // Clear the Watchdog Timer after the image returns
- //
- gBS->SetWatchdogTimer (0, 0, 0, NULL);
+ //
+ // Clear the Watchdog Timer after the image returns
+ //
+ gBS->SetWatchdogTimer (0, 0, 0, NULL);
+
+ if ((LoadOption->OptionType != LoadOptionTypePlatformRecovery) || (LoadOption->Status == EFI_SUCCESS)) {
+ break;
+ }
+ }
+ }
+
+ if (CurFullPath != NULL) {
+ FreePool (CurFullPath);
}
return Status;
diff --git a/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h b/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h
index 8d7215a..ef09050 100644
--- a/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h
+++ b/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h
@@ -310,23 +310,6 @@ BmSetVariableAndReportStatusCodeOnError (
);
/**
- Return whether the PE header of the load option is valid or not.
-
- @param[in] Type The load option type.
- @param[in] FileBuffer The PE file buffer of the load option.
- @param[in] FileSize The size of the load option file.
-
- @retval TRUE The PE header of the load option is valid.
- @retval FALSE The PE header of the load option is not valid.
-**/
-BOOLEAN
-BmIsLoadOptionPeHeaderValid (
- IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type,
- IN VOID *FileBuffer,
- IN UINTN FileSize
- );
-
-/**
Function compares a device path data structure to that of all the nodes of a
second device path instance.
@@ -425,16 +408,83 @@ BmMakeBootOptionDescriptionUnique (
@param LoadFileHandle The specified Load File instance.
@param FilePath The file path which will pass to LoadFile().
- @param FullPath Return the full device path pointing to the load option.
- @param FileSize Return the size of the load option.
- @return The load option buffer or NULL if fails.
+ @return The full device path pointing to the load option buffer.
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+BmExpandLoadFile (
+ IN EFI_HANDLE LoadFileHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ );
+
+/**
+ Return the RAM Disk device path created by LoadFile.
+
+ @param FilePath The source file path.
+
+ @return Callee-to-free RAM Disk device path
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+BmGetRamDiskDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ );
+
+/**
+ Destroy the RAM Disk.
+
+ The destroy operation includes to call RamDisk.Unregister to
+ unregister the RAM DISK from RAM DISK driver, free the memory
+ allocated for the RAM Disk.
+
+ @param RamDiskDevicePath RAM Disk device path.
+**/
+VOID
+BmDestroyRamDisk (
+ IN EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath
+ );
+
+/**
+ Get the next possible full path pointing to the load option.
+
+ @param FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+ @param FullPath The full path returned by the routine in last call.
+ Set to NULL in first call.
+
+ @return The next possible full path pointing to the load option.
+ Caller is responsible to free the memory.
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+BmGetNextLoadOptionDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath
+ );
+
+/**
+ Return the next matched load option buffer.
+ The routine keeps calling BmGetNextLoadOptionDevicePath() until a valid
+ load option is read.
+
+ @param Type The load option type.
+ It's used to check whether the load option is valid.
+ When it's LoadOptionTypeMax, the routine only guarantees
+ the load option is a valid PE image but doesn't guarantee
+ the PE's subsystem type is valid.
+ @param FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+ @param FullPath Return the next full device path of the load option after
+ short-form device path expanding.
+ Caller is responsible to free it.
+ NULL to return the first matched full device path.
+ @param FileSize Return the load option size.
+
+ @return The load option buffer. Caller is responsible to free the memory.
**/
VOID *
-BmGetFileBufferFromLoadFile (
- EFI_HANDLE LoadFileHandle,
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
- OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
- OUT UINTN *FileSize
+BmGetNextLoadOptionBuffer (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
+ OUT UINTN *FileSize
);
#endif // _INTERNAL_BM_H_
--
2.9.0.windows.1
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] MdeModulePkg/UefiBootManagerLib: Enhance short-form expanding logic
2017-04-06 9:44 [PATCH] MdeModulePkg/UefiBootManagerLib: Enhance short-form expanding logic Ruiyu Ni
@ 2017-04-07 2:48 ` Tian, Feng
0 siblings, 0 replies; 2+ messages in thread
From: Tian, Feng @ 2017-04-07 2:48 UTC (permalink / raw)
To: Ni, Ruiyu, edk2-devel@lists.01.org; +Cc: Dong, Eric, Fan, Jeff, Tian, Feng
Reviewed-by: Feng Tian <feng.tian@intel.com>
Thanks
Feng
-----Original Message-----
From: Ni, Ruiyu
Sent: Thursday, April 6, 2017 5:45 PM
To: edk2-devel@lists.01.org
Cc: Tian, Feng <feng.tian@intel.com>; Dong, Eric <eric.dong@intel.com>; Fan, Jeff <jeff.fan@intel.com>
Subject: [PATCH] MdeModulePkg/UefiBootManagerLib: Enhance short-form expanding logic
Old implementation only finds first matched full device path for a given short-form device path.
The patch adds internal function BmGetNextLoadOptionBuffer() to finds all matched full device path for a given short-form device path.
There are 6 kinds of device paths. Some of them match to multiple load options, some of them don't.
1. Media device path:
Returns multiple load options: The media device path may point
to a physical BlockIo which contains multiple logic partitions,
each logic partitions contains \EFI\BOOT\BOOT${ARCH}.EFI.
2. Short-form hard-drive device path:
Returns one load option because the partition signature is unique.
3. Short-form file-path device path:
Returns multiple load options: There are multiple SimpleFileSystem
instances and each contains the same file.
4. Short-form URI device path:
Returns multiple load options: There are multiple LoadFile
instances and each can boot.
5. Short-form USB device path:
Returns multiple load options: There are multiple UsbIo instances
and each contains the boot-able file.
6. FV device path, device path pointing to SimpleFileSystem, device
path pointing to LoadFile
Returns one load option.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Jeff Fan <jeff.fan@intel.com>
---
MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c | 470 ++++++++++++---------
.../Library/UefiBootManagerLib/BmLoadOption.c | 173 ++++++--
.../Library/UefiBootManagerLib/InternalBm.h | 100 +++--
3 files changed, 475 insertions(+), 268 deletions(-)
diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c b/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
index 8a3a402..aa79c90 100644
--- a/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
+++ b/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
@@ -131,21 +131,16 @@ BmFindBootOptionInVariable ( }
/**
- Get the file buffer using a Memory Mapped Device Path.
-
+ Return the correct FV file path.
FV address may change across reboot. This routine promises the FV file device path is right.
@param FilePath The Memory Mapped Device Path to get the file buffer.
- @param FullPath Receive the updated FV Device Path pointint to the file.
- @param FileSize Receive the file buffer size.
- @return The file buffer.
+ @return The updated FV Device Path pointint to the file.
**/
-VOID *
-BmGetFileBufferByFvFilePath (
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
- OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
- OUT UINTN *FileSize
+EFI_DEVICE_PATH_PROTOCOL *
+BmAdjustFvFilePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
)
{
EFI_STATUS Status;
@@ -153,11 +148,10 @@ BmGetFileBufferByFvFilePath (
EFI_DEVICE_PATH_PROTOCOL *FvFileNode;
EFI_HANDLE FvHandle;
EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
- UINT32 AuthenticationStatus;
UINTN FvHandleCount;
EFI_HANDLE *FvHandles;
EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
- VOID *FileBuffer;
+ EFI_DEVICE_PATH_PROTOCOL *FullPath;
//
// Get the file buffer by using the exactly FilePath.
@@ -165,11 +159,7 @@ BmGetFileBufferByFvFilePath (
FvFileNode = FilePath;
Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &FvFileNode, &FvHandle);
if (!EFI_ERROR (Status)) {
- FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus);
- if (FileBuffer != NULL) {
- *FullPath = DuplicateDevicePath (FilePath);
- }
- return FileBuffer;
+ return DuplicateDevicePath (FilePath);
}
//
@@ -190,11 +180,10 @@ BmGetFileBufferByFvFilePath (
(VOID **) &LoadedImage
);
NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (LoadedImage->DeviceHandle), FvFileNode);
- FileBuffer = BmGetFileBufferByFvFilePath (NewDevicePath, FullPath, FileSize);
+ FullPath = BmAdjustFvFilePath (NewDevicePath);
FreePool (NewDevicePath);
-
- if (FileBuffer != NULL) {
- return FileBuffer;
+ if (FullPath != NULL) {
+ return FullPath;
}
//
@@ -207,22 +196,25 @@ BmGetFileBufferByFvFilePath (
&FvHandleCount,
&FvHandles
);
- for (Index = 0; (Index < FvHandleCount) && (FileBuffer == NULL); Index++) {
+ for (Index = 0; Index < FvHandleCount; Index++) {
if (FvHandles[Index] == LoadedImage->DeviceHandle) {
//
- // Skip current FV
+ // Skip current FV, it was handed in first step.
//
continue;
}
NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (FvHandles[Index]), FvFileNode);
- FileBuffer = BmGetFileBufferByFvFilePath (NewDevicePath, FullPath, FileSize);
+ FullPath = BmAdjustFvFilePath (NewDevicePath);
FreePool (NewDevicePath);
+ if (FullPath != NULL) {
+ break;
+ }
}
if (FvHandles != NULL) {
FreePool (FvHandles);
}
- return FileBuffer;
+ return FullPath;
}
/**
@@ -555,46 +547,64 @@ BmFindUsbDevice (
@param FilePath The device path pointing to a load option.
It could be a short-form device path.
- @param FullPath Return the full device path of the load option after
- short-form device path expanding.
- Caller is responsible to free it.
- @param FileSize Return the load option size.
+ @param FullPath The full path returned by the routine in last call.
+ Set to NULL in first call.
@param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer.
- @return The load option buffer. Caller is responsible to free the memory.
+ @return The next possible full path pointing to the load option.
+ Caller is responsible to free the memory.
**/
-VOID *
+EFI_DEVICE_PATH_PROTOCOL *
BmExpandUsbDevicePath (
IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
- OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
- OUT UINTN *FileSize,
- IN EFI_DEVICE_PATH_PROTOCOL *ShortformNode
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath, IN
+ EFI_DEVICE_PATH_PROTOCOL *ShortformNode
)
{
UINTN ParentDevicePathSize;
EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
- EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *NextFullPath;
EFI_HANDLE *Handles;
UINTN HandleCount;
UINTN Index;
- VOID *FileBuffer;
+ BOOLEAN GetNext;
+ NextFullPath = NULL;
+ GetNext = (BOOLEAN)(FullPath == NULL);
ParentDevicePathSize = (UINTN) ShortformNode - (UINTN) FilePath;
RemainingDevicePath = NextDevicePathNode (ShortformNode);
- FileBuffer = NULL;
Handles = BmFindUsbDevice (FilePath, ParentDevicePathSize, &HandleCount);
- for (Index = 0; (Index < HandleCount) && (FileBuffer == NULL); Index++) {
- FullDevicePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), RemainingDevicePath);
- FileBuffer = EfiBootManagerGetLoadOptionBuffer (FullDevicePath, FullPath, FileSize);
- FreePool (FullDevicePath);
+ for (Index = 0; Index < HandleCount; Index++) {
+ FilePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), RemainingDevicePath);
+ if (FilePath == NULL) {
+ //
+ // Out of memory.
+ //
+ continue;
+ }
+ NextFullPath = BmGetNextLoadOptionDevicePath (FilePath, NULL);
+ FreePool (FilePath);
+ if (NextFullPath == NULL) {
+ //
+ // No BlockIo or SimpleFileSystem under FilePath.
+ //
+ continue;
+ }
+ if (GetNext) {
+ break;
+ } else {
+ GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);
+ FreePool (NextFullPath);
+ NextFullPath = NULL;
+ }
}
if (Handles != NULL) {
FreePool (Handles);
}
- return FileBuffer;
+ return NextFullPath;
}
/**
@@ -602,18 +612,16 @@ BmExpandUsbDevicePath (
@param FilePath The device path pointing to a load option.
It could be a short-form device path.
- @param FullPath Return the full device path of the load option after
- short-form device path expanding.
- Caller is responsible to free it.
- @param FileSize Return the load option size.
+ @param FullPath The full path returned by the routine in last call.
+ Set to NULL in first call.
- @return The load option buffer. Caller is responsible to free the memory.
+ @return The next possible full path pointing to the load option.
+ Caller is responsible to free the memory.
**/
-VOID *
+EFI_DEVICE_PATH_PROTOCOL *
BmExpandFileDevicePath (
IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
- OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
- OUT UINTN *FileSize
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath
)
{
EFI_STATUS Status;
@@ -622,9 +630,8 @@ BmExpandFileDevicePath (
EFI_HANDLE *Handles;
EFI_BLOCK_IO_PROTOCOL *BlockIo;
UINTN MediaType;
- EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
- VOID *FileBuffer;
- UINT32 AuthenticationStatus;
+ EFI_DEVICE_PATH_PROTOCOL *NextFullPath;
+ BOOLEAN GetNext;
EfiBootManagerConnectAll ();
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &HandleCount, &Handles); @@ -633,6 +640,8 @@ BmExpandFileDevicePath (
Handles = NULL;
}
+ GetNext = (BOOLEAN)(FullPath == NULL); NextFullPath = NULL;
//
// Enumerate all removable media devices followed by all fixed media devices,
// followed by media devices which don't layer on block io.
@@ -647,24 +656,26 @@ BmExpandFileDevicePath (
(MediaType == 1 && BlockIo != NULL && !BlockIo->Media->RemovableMedia) ||
(MediaType == 2 && BlockIo == NULL)
) {
- FullDevicePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), FilePath);
- FileBuffer = GetFileBufferByFilePath (TRUE, FullDevicePath, FileSize, &AuthenticationStatus);
- if (FileBuffer != NULL) {
- *FullPath = FullDevicePath;
- FreePool (Handles);
- return FileBuffer;
+ NextFullPath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), FilePath);
+ if (GetNext) {
+ break;
+ } else {
+ GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);
+ FreePool (NextFullPath);
+ NextFullPath = NULL;
}
- FreePool (FullDevicePath);
}
}
+ if (NextFullPath != NULL) {
+ break;
+ }
}
if (Handles != NULL) {
FreePool (Handles);
}
- *FullPath = NULL;
- return NULL;
+ return NextFullPath;
}
/**
@@ -672,25 +683,25 @@ BmExpandFileDevicePath (
@param FilePath The device path pointing to a load option.
It could be a short-form device path.
- @param FullPath Return the full device path of the load option after
- short-form device path expanding.
- Caller is responsible to free it.
- @param FileSize Return the load option size.
+ @param FullPath The full path returned by the routine in last call.
+ Set to NULL in first call.
- @return The load option buffer. Caller is responsible to free the memory.
+ @return The next possible full path pointing to the load option.
+ Caller is responsible to free the memory.
**/
-VOID *
+EFI_DEVICE_PATH_PROTOCOL *
BmExpandUriDevicePath (
IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
- OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
- OUT UINTN *FileSize
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath
)
{
EFI_STATUS Status;
UINTN Index;
UINTN HandleCount;
EFI_HANDLE *Handles;
- VOID *FileBuffer;
+ EFI_DEVICE_PATH_PROTOCOL *NextFullPath;
+ EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath;
+ BOOLEAN GetNext;
EfiBootManagerConnectAll ();
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiLoadFileProtocolGuid, NULL, &HandleCount, &Handles); @@ -699,11 +710,29 @@ BmExpandUriDevicePath (
Handles = NULL;
}
- FileBuffer = NULL;
+ NextFullPath = NULL;
+ GetNext = (BOOLEAN)(FullPath == NULL);
for (Index = 0; Index < HandleCount; Index++) {
- FileBuffer = BmGetFileBufferFromLoadFile (Handles[Index], FilePath, FullPath, FileSize);
- if (FileBuffer != NULL) {
+ NextFullPath = BmExpandLoadFile (Handles[Index], FilePath);
+
+ if (NextFullPath == NULL) {
+ continue;
+ }
+
+ if (GetNext) {
break;
+ } else {
+ GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);
+ //
+ // Free the resource occupied by the RAM disk.
+ //
+ RamDiskDevicePath = BmGetRamDiskDevicePath (NextFullPath);
+ if (RamDiskDevicePath != NULL) {
+ BmDestroyRamDisk (RamDiskDevicePath);
+ FreePool (RamDiskDevicePath);
+ }
+ FreePool (NextFullPath);
+ NextFullPath = NULL;
}
}
@@ -711,7 +740,7 @@ BmExpandUriDevicePath (
FreePool (Handles);
}
- return FileBuffer;
+ return NextFullPath;
}
/**
@@ -781,35 +810,28 @@ BmCachePartitionDevicePath (
@param FilePath The device path pointing to a load option.
It could be a short-form device path.
- @param FullPath Return the full device path of the load option after
- short-form device path expanding.
- Caller is responsible to free it.
- @param FileSize Return the load option size.
- @return The load option buffer. Caller is responsible to free the memory.
+ @return The full device path pointing to the load option.
**/
-VOID *
+EFI_DEVICE_PATH_PROTOCOL *
BmExpandPartitionDevicePath (
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
- OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
- OUT UINTN *FileSize
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
)
{
EFI_STATUS Status;
UINTN BlockIoHandleCount;
EFI_HANDLE *BlockIoBuffer;
- VOID *FileBuffer;
EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;
UINTN Index;
EFI_DEVICE_PATH_PROTOCOL *CachedDevicePath;
EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *FullPath;
UINTN CachedDevicePathSize;
BOOLEAN NeedAdjust;
EFI_DEVICE_PATH_PROTOCOL *Instance;
UINTN Size;
- FileBuffer = NULL;
//
// Check if there is prestore 'HDDP' variable.
// If exist, search the front path which point to partition node in the variable instants.
@@ -833,6 +855,7 @@ BmExpandPartitionDevicePath (
ASSERT_EFI_ERROR (Status);
}
+ FullPath = NULL;
if (CachedDevicePath != NULL) {
TempNewDevicePath = CachedDevicePath;
NeedAdjust = FALSE;
@@ -851,10 +874,20 @@ BmExpandPartitionDevicePath (
Status = EfiBootManagerConnectDevicePath (Instance, NULL);
if (!EFI_ERROR (Status)) {
TempDevicePath = AppendDevicePath (Instance, NextDevicePathNode (FilePath));
- FileBuffer = EfiBootManagerGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);
+ //
+ // TempDevicePath = ACPI()/PCI()/ATA()/Partition()
+ // or = ACPI()/PCI()/ATA()/Partition()/.../A.EFI
+ //
+ // When TempDevicePath = ACPI()/PCI()/ATA()/Partition(),
+ // it may expand to two potienal full paths (nested partition, rarely happen):
+ // 1. ACPI()/PCI()/ATA()/Partition()/Partition(A1)/EFI/BootX64.EFI
+ // 2. ACPI()/PCI()/ATA()/Partition()/Partition(A2)/EFI/BootX64.EFI
+ // For simplicity, only #1 is returned.
+ //
+ FullPath = BmGetNextLoadOptionDevicePath (TempDevicePath,
+ NULL);
FreePool (TempDevicePath);
- if (FileBuffer != NULL) {
+ if (FullPath != NULL) {
//
// Adjust the 'HDDP' instances sequence if the matched one is not first one.
//
@@ -875,7 +908,7 @@ BmExpandPartitionDevicePath (
FreePool (Instance);
FreePool (CachedDevicePath);
- return FileBuffer;
+ return FullPath;
}
}
}
@@ -911,10 +944,10 @@ BmExpandPartitionDevicePath (
// Find the matched partition device path
//
TempDevicePath = AppendDevicePath (BlockIoDevicePath, NextDevicePathNode (FilePath));
- FileBuffer = EfiBootManagerGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);
+ FullPath = BmGetNextLoadOptionDevicePath (TempDevicePath, NULL);
FreePool (TempDevicePath);
- if (FileBuffer != NULL) {
+ if (FullPath != NULL) {
BmCachePartitionDevicePath (&CachedDevicePath, BlockIoDevicePath);
//
@@ -940,7 +973,7 @@ BmExpandPartitionDevicePath (
if (BlockIoBuffer != NULL) {
FreePool (BlockIoBuffer);
}
- return FileBuffer;
+ return FullPath;
}
/**
@@ -948,16 +981,16 @@ BmExpandPartitionDevicePath (
by appending EFI_REMOVABLE_MEDIA_FILE_NAME.
@param DevicePath The media device path pointing to a BlockIo or SimpleFileSystem instance.
- @param FullPath Return the full device path pointing to the load option.
- @param FileSize Return the size of the load option.
+ @param FullPath The full path returned by the routine in last call.
+ Set to NULL in first call.
- @return The load option buffer.
+ @return The next possible full path pointing to the load option.
+ Caller is responsible to free the memory.
**/
-VOID *
+EFI_DEVICE_PATH_PROTOCOL *
BmExpandMediaDevicePath (
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
- OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
- OUT UINTN *FileSize
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath
)
{
EFI_STATUS Status;
@@ -965,14 +998,15 @@ BmExpandMediaDevicePath (
EFI_BLOCK_IO_PROTOCOL *BlockIo;
VOID *Buffer;
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *NextFullPath;
UINTN Size;
UINTN TempSize;
EFI_HANDLE *SimpleFileSystemHandles;
UINTN NumberSimpleFileSystemHandles;
UINTN Index;
- VOID *FileBuffer;
- UINT32 AuthenticationStatus;
+ BOOLEAN GetNext;
+ GetNext = (BOOLEAN)(FullPath == NULL);
//
// Check whether the device is connected
//
@@ -981,14 +1015,16 @@ BmExpandMediaDevicePath (
if (!EFI_ERROR (Status)) {
ASSERT (IsDevicePathEnd (TempDevicePath));
- TempDevicePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
- FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus);
- if (FileBuffer == NULL) {
- FreePool (TempDevicePath);
- TempDevicePath = NULL;
+ NextFullPath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
+ //
+ // For device path pointing to simple file system, it only expands to one full path.
+ //
+ if (GetNext) {
+ return NextFullPath;
+ } else {
+ FreePool (NextFullPath);
+ return NULL;
}
- *FullPath = TempDevicePath;
- return FileBuffer;
}
Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle); @@ -1025,8 +1061,7 @@ BmExpandMediaDevicePath (
//
// Detect the the default boot file from removable Media
//
- FileBuffer = NULL;
- *FullPath = NULL;
+ NextFullPath = NULL;
Size = GetDevicePathSize (DevicePath) - END_DEVICE_PATH_LENGTH;
gBS->LocateHandleBuffer (
ByProtocol,
@@ -1045,13 +1080,14 @@ BmExpandMediaDevicePath (
// Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
//
if ((Size <= TempSize) && (CompareMem (TempDevicePath, DevicePath, Size) == 0)) {
- TempDevicePath = FileDevicePath (SimpleFileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME);
- FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus);
- if (FileBuffer != NULL) {
- *FullPath = TempDevicePath;
+ NextFullPath = FileDevicePath (SimpleFileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME);
+ if (GetNext) {
break;
+ } else {
+ GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);
+ FreePool (NextFullPath);
+ NextFullPath = NULL;
}
- FreePool (TempDevicePath);
}
}
@@ -1059,7 +1095,7 @@ BmExpandMediaDevicePath (
FreePool (SimpleFileSystemHandles);
}
- return FileBuffer;
+ return NextFullPath;
}
/**
@@ -1098,17 +1134,14 @@ BmMatchHttpBootDevicePath (
Get the file buffer from the file system produced by Load File instance.
@param LoadFileHandle The handle of LoadFile instance.
- @param FullPath Return the full device path pointing to the load option.
- @param FileSize Return the size of the load option.
@param RamDiskHandle Return the RAM Disk handle.
- @return The load option buffer.
+ @return The next possible full path pointing to the load option.
+ Caller is responsible to free the memory.
**/
-VOID *
-BmGetFileBufferFromLoadFileSystem (
+EFI_DEVICE_PATH_PROTOCOL *
+BmExpandNetworkFileSystem (
IN EFI_HANDLE LoadFileHandle,
- OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
- OUT UINTN *FileSize,
OUT EFI_HANDLE *RamDiskHandle
)
{
@@ -1138,6 +1171,9 @@ BmGetFileBufferFromLoadFileSystem (
if (!EFI_ERROR (Status) &&
(Handle == LoadFileHandle) &&
(DevicePathType (Node) == MEDIA_DEVICE_PATH) && (DevicePathSubType (Node) == MEDIA_RAM_DISK_DP)) {
+ //
+ // Find the BlockIo instance populated from the LoadFile.
+ //
Handle = Handles[Index];
break;
}
@@ -1154,13 +1190,16 @@ BmGetFileBufferFromLoadFileSystem (
*RamDiskHandle = Handle;
if (Handle != NULL) {
- return BmExpandMediaDevicePath (DevicePathFromHandle (Handle), FullPath, FileSize);
+ //
+ // Re-use BmExpandMediaDevicePath() to get the full device path of load option.
+ // But assume only one SimpleFileSystem can be found under the BlockIo.
+ //
+ return BmExpandMediaDevicePath (DevicePathFromHandle (Handle),
+ NULL);
} else {
return NULL;
}
}
-
/**
Return the RAM Disk device path created by LoadFile.
@@ -1274,27 +1313,21 @@ BmDestroyRamDisk (
@param LoadFileHandle The specified Load File instance.
@param FilePath The file path which will pass to LoadFile().
- @param FullPath Return the full device path pointing to the load option.
- @param FileSize Return the size of the load option.
- @return The load option buffer or NULL if fails.
+ @return The full device path pointing to the load option buffer.
**/
-VOID *
-BmGetFileBufferFromLoadFile (
+EFI_DEVICE_PATH_PROTOCOL *
+BmExpandLoadFile (
IN EFI_HANDLE LoadFileHandle,
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
- OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
- OUT UINTN *FileSize
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
)
{
EFI_STATUS Status;
EFI_LOAD_FILE_PROTOCOL *LoadFile;
VOID *FileBuffer;
- BOOLEAN LoadFileSystem;
EFI_HANDLE RamDiskHandle;
UINTN BufferSize;
-
- *FileSize = 0;
+ EFI_DEVICE_PATH_PROTOCOL *FullPath;
Status = gBS->OpenProtocol (
LoadFileHandle,
@@ -1313,52 +1346,60 @@ BmGetFileBufferFromLoadFile (
return NULL;
}
- LoadFileSystem = (BOOLEAN) (Status == EFI_WARN_FILE_SYSTEM);
- FileBuffer = LoadFileSystem ? AllocateReservedPages (EFI_SIZE_TO_PAGES (BufferSize)) : AllocatePool (BufferSize);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ //
+ // The load option buffer is directly returned by LoadFile.
+ //
+ return DuplicateDevicePath (DevicePathFromHandle (LoadFileHandle));
+ }
+
+ //
+ // The load option resides in a RAM disk.
+ //
+ FileBuffer = AllocateReservedPages (EFI_SIZE_TO_PAGES (BufferSize));
if (FileBuffer == NULL) {
return NULL;
}
Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);
if (EFI_ERROR (Status)) {
- if (LoadFileSystem) {
- FreePages (FileBuffer, EFI_SIZE_TO_PAGES (BufferSize));
- } else {
- FreePool (FileBuffer);
- }
+ FreePages (FileBuffer, EFI_SIZE_TO_PAGES (BufferSize));
return NULL;
}
- if (LoadFileSystem) {
- FileBuffer = BmGetFileBufferFromLoadFileSystem (LoadFileHandle, FullPath, FileSize, &RamDiskHandle);
- if (FileBuffer == NULL) {
- //
- // If there is no bootable executable in the populated
- //
- BmDestroyRamDisk (DevicePathFromHandle (RamDiskHandle));
- }
- } else {
- *FileSize = BufferSize;
- *FullPath = DuplicateDevicePath (DevicePathFromHandle (LoadFileHandle));
+ FullPath = BmExpandNetworkFileSystem (LoadFileHandle,
+ &RamDiskHandle); if (FullPath == NULL) {
+ //
+ // Free the memory occupied by the RAM disk if there is no BlockIo or SimpleFileSystem instance.
+ //
+ BmDestroyRamDisk (DevicePathFromHandle (RamDiskHandle));
}
- return FileBuffer;
+ return FullPath;
}
/**
- Get the file buffer from all the Load File instances.
+ Return the full device path pointing to the load option.
+
+ FilePath may:
+ 1. Exactly matches to a LoadFile instance.
+ 2. Cannot match to any LoadFile instance. Wide match is required.
+ In either case, the routine may return:
+ 1. A copy of FilePath when FilePath matches to a LoadFile instance and
+ the LoadFile returns a load option buffer.
+ 2. A new device path with IP and URI information updated when wide match
+ happens.
+ 3. A new device path pointing to a load option in RAM disk.
+ In either case, only one full device path is returned for a specified
+ FilePath.
@param FilePath The media device path pointing to a LoadFile instance.
- @param FullPath Return the full device path pointing to the load option.
- @param FileSize Return the size of the load option.
@return The load option buffer.
**/
-VOID *
-BmGetFileBufferFromLoadFiles (
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
- OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
- OUT UINTN *FileSize
+EFI_DEVICE_PATH_PROTOCOL *
+BmExpandLoadFiles (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
)
{
EFI_STATUS Status;
@@ -1411,7 +1452,7 @@ BmGetFileBufferFromLoadFiles (
return NULL;
}
- return BmGetFileBufferFromLoadFile (Handle, FilePath, FullPath, FileSize);
+ return BmExpandLoadFile (Handle, FilePath);
}
/**
@@ -1434,19 +1475,37 @@ EfiBootManagerGetLoadOptionBuffer (
OUT UINTN *FileSize
)
{
+ *FullPath = NULL;
+
+ EfiBootManagerConnectDevicePath (FilePath, NULL);
+ return BmGetNextLoadOptionBuffer (LoadOptionTypeMax, FilePath,
+FullPath, FileSize); }
+
+/**
+ Get the next possible full path pointing to the load option.
+ The routine doesn't guarantee the returned full path points to an
+existing
+ file, and it also doesn't guarantee the existing file is a valid load option.
+ BmGetNextLoadOptionBuffer() guarantees.
+
+ @param FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+ @param FullPath The full path returned by the routine in last call.
+ Set to NULL in first call.
+
+ @return The next possible full path pointing to the load option.
+ Caller is responsible to free the memory.
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+BmGetNextLoadOptionDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath
+ )
+{
EFI_HANDLE Handle;
- VOID *FileBuffer;
- UINT32 AuthenticationStatus;
EFI_DEVICE_PATH_PROTOCOL *Node;
EFI_STATUS Status;
- ASSERT ((FilePath != NULL) && (FullPath != NULL) && (FileSize != NULL));
-
- EfiBootManagerConnectDevicePath (FilePath, NULL);
-
- *FullPath = NULL;
- *FileSize = 0;
- FileBuffer = NULL;
+ ASSERT (FilePath != NULL);
//
// Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI @@ -1458,7 +1517,7 @@ EfiBootManagerGetLoadOptionBuffer (
}
if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {
- return BmExpandMediaDevicePath (FilePath, FullPath, FileSize);
+ return BmExpandMediaDevicePath (FilePath, FullPath);
}
//
@@ -1469,19 +1528,23 @@ EfiBootManagerGetLoadOptionBuffer (
//
// Expand the Harddrive device path
//
- return BmExpandPartitionDevicePath (FilePath, FullPath, FileSize);
+ if (FullPath == NULL) {
+ return BmExpandPartitionDevicePath (FilePath);
+ } else {
+ return NULL;
+ }
} else if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) &&
(DevicePathSubType (FilePath) == MEDIA_FILEPATH_DP)) {
//
// Expand the File-path device path
//
- return BmExpandFileDevicePath (FilePath, FullPath, FileSize);
+ return BmExpandFileDevicePath (FilePath, FullPath);
} else if ((DevicePathType (FilePath) == MESSAGING_DEVICE_PATH) &&
(DevicePathSubType (FilePath) == MSG_URI_DP)) {
//
// Expand the URI device path
//
- return BmExpandUriDevicePath (FilePath, FullPath, FileSize);
+ return BmExpandUriDevicePath (FilePath, FullPath);
} else {
for (Node = FilePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) {
if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && @@ -1490,45 +1553,50 @@ EfiBootManagerGetLoadOptionBuffer (
}
}
+ //
+ // Expand the USB WWID/Class device path
+ //
if (!IsDevicePathEnd (Node)) {
- //
- // Expand the USB WWID/Class device path
- //
- FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node);
- if ((FileBuffer == NULL) && (FilePath == Node)) {
+ if (FilePath == Node) {
//
// Boot Option device path starts with USB Class or USB WWID device path.
// For Boot Option device path which doesn't begin with the USB Class or
// USB WWID device path, it's not needed to connect again here.
//
BmConnectUsbShortFormDevicePath (FilePath);
- FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node);
}
- return FileBuffer;
+ return BmExpandUsbDevicePath (FilePath, FullPath, Node);
}
}
//
- // Get file buffer from FV file path.
+ // For the below cases, FilePath only expands to one Full path.
+ // So just handle the case when FullPath == NULL.
+ //
+ if (FullPath != NULL) {
+ return NULL;
+ }
+
+ //
+ // Load option resides in FV.
//
if (BmIsFvFilePath (FilePath)) {
- return BmGetFileBufferByFvFilePath (FilePath, FullPath, FileSize);
+ return BmAdjustFvFilePath (FilePath);
}
//
- // Get file buffer from simple file system.
+ // Load option resides in Simple File System.
//
Node = FilePath;
Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle);
if (!EFI_ERROR (Status)) {
- FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus);
- if (FileBuffer != NULL) {
- *FullPath = DuplicateDevicePath (FilePath);
- }
- return FileBuffer;
+ return DuplicateDevicePath (FilePath);
}
- return BmGetFileBufferFromLoadFiles (FilePath, FullPath, FileSize);
+ //
+ // Last chance to try: Load option may be loaded through LoadFile.
+ //
+ return BmExpandLoadFiles (FilePath);
}
/**
@@ -1686,21 +1754,13 @@ EfiBootManagerBoot (
ImageHandle = NULL;
RamDiskDevicePath = NULL;
if (DevicePathType (BootOption->FilePath) != BBS_DEVICE_PATH) {
- Status = EFI_NOT_FOUND;
- FileBuffer = EfiBootManagerGetLoadOptionBuffer (BootOption->FilePath, &FilePath, &FileSize);
+ Status = EFI_NOT_FOUND;
+ FilePath = NULL;
+ EfiBootManagerConnectDevicePath (BootOption->FilePath, NULL);
+ FileBuffer = BmGetNextLoadOptionBuffer (LoadOptionTypeBoot,
+ BootOption->FilePath, &FilePath, &FileSize);
if (FileBuffer != NULL) {
RamDiskDevicePath = BmGetRamDiskDevicePath (FilePath);
- }
- DEBUG_CODE (
- if (FileBuffer != NULL && CompareMem (BootOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) {
- DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: "));
- BmPrintDp (BootOption->FilePath);
- DEBUG ((EFI_D_INFO, " -> "));
- BmPrintDp (FilePath);
- DEBUG ((EFI_D_INFO, "\n"));
- }
- );
- if (BmIsLoadOptionPeHeaderValid (BootOption->OptionType, FileBuffer, FileSize)) {
+
REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));
Status = gBS->LoadImage (
TRUE,
diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c b/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c
index 116cf28..b0a3505 100644
--- a/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c
+++ b/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c
@@ -1167,6 +1167,10 @@ EfiBootManagerFreeLoadOptions (
Return whether the PE header of the load option is valid or not.
@param[in] Type The load option type.
+ It's used to check whether the load option is valid.
+ When it's LoadOptionTypeMax, the routine only guarantees
+ the load option is a valid PE image but doesn't guarantee
+ the PE's subsystem type is valid.
@param[in] FileBuffer The PE file buffer of the load option.
@param[in] FileSize The size of the load option file.
@@ -1217,7 +1221,8 @@ BmIsLoadOptionPeHeaderValid (
// SysPrep####, Boot####, OsRecovery####, PlatformRecovery#### must be of type Application
//
Subsystem = OptionalHeader->Subsystem;
- if ((Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||
+ if ((Type == LoadOptionTypeMax) ||
+ (Type == LoadOptionTypeDriver && Subsystem ==
+ EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||
(Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) ||
(Type == LoadOptionTypeSysPrep && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) ||
(Type == LoadOptionTypeBoot && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) || @@ -1233,6 +1238,91 @@ BmIsLoadOptionPeHeaderValid ( }
/**
+ Return the next matched load option buffer.
+ The routine keeps calling BmGetNextLoadOptionDevicePath() until a
+ valid load option is read.
+
+ @param Type The load option type.
+ It's used to check whether the load option is valid.
+ When it's LoadOptionTypeMax, the routine only guarantees
+ the load option is a valid PE image but doesn't guarantee
+ the PE's subsystem type is valid.
+ @param FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+ @param FullPath Return the next full device path of the load option after
+ short-form device path expanding.
+ Caller is responsible to free it.
+ NULL to return the first matched full device path.
+ @param FileSize Return the load option size.
+
+ @return The load option buffer. Caller is responsible to free the memory.
+**/
+VOID *
+BmGetNextLoadOptionBuffer (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
+ OUT UINTN *FileSize
+ )
+{
+ VOID *FileBuffer;
+ EFI_DEVICE_PATH_PROTOCOL *PreFullPath;
+ EFI_DEVICE_PATH_PROTOCOL *CurFullPath;
+ UINTN LocalFileSize;
+ UINT32 AuthenticationStatus;
+ EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath;
+
+ LocalFileSize = 0;
+ FileBuffer = NULL;
+ CurFullPath = *FullPath;
+ do {
+ PreFullPath = CurFullPath;
+ CurFullPath = BmGetNextLoadOptionDevicePath (FilePath, CurFullPath);
+ //
+ // Only free the full path created *inside* this routine
+ //
+ if ((PreFullPath != NULL) && (PreFullPath != *FullPath)) {
+ FreePool (PreFullPath);
+ }
+ if (CurFullPath == NULL) {
+ break;
+ }
+ FileBuffer = GetFileBufferByFilePath (TRUE, CurFullPath, &LocalFileSize, &AuthenticationStatus);
+ if ((FileBuffer != NULL) && !BmIsLoadOptionPeHeaderValid (Type, FileBuffer, LocalFileSize)) {
+ //
+ // Free the RAM disk file system if the load option is invalid.
+ //
+ RamDiskDevicePath = BmGetRamDiskDevicePath (FilePath);
+ if (RamDiskDevicePath != NULL) {
+ BmDestroyRamDisk (RamDiskDevicePath);
+ FreePool (RamDiskDevicePath);
+ }
+
+ //
+ // Free the invalid load option buffer.
+ //
+ FreePool (FileBuffer);
+ FileBuffer = NULL;
+ }
+ } while (FileBuffer == NULL);
+
+ if (FileBuffer == NULL) {
+ CurFullPath = NULL;
+ LocalFileSize = 0;
+ }
+
+ DEBUG ((DEBUG_INFO, "[Bds] Expand ")); BmPrintDp (FilePath); DEBUG
+ ((DEBUG_INFO, " -> ")); BmPrintDp (CurFullPath); DEBUG ((DEBUG_INFO,
+ "\n"));
+
+ *FullPath = CurFullPath;
+ *FileSize = LocalFileSize;
+ return FileBuffer;
+}
+
+/**
Process (load and execute) the load option.
@param LoadOption Pointer to the load option.
@@ -1249,7 +1339,8 @@ EfiBootManagerProcessLoadOption (
)
{
EFI_STATUS Status;
- EFI_DEVICE_PATH_PROTOCOL *FilePath;
+ EFI_DEVICE_PATH_PROTOCOL *PreFullPath;
+ EFI_DEVICE_PATH_PROTOCOL *CurFullPath;
EFI_HANDLE ImageHandle;
EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
VOID *FileBuffer;
@@ -1271,8 +1362,6 @@ EfiBootManagerProcessLoadOption (
return EFI_SUCCESS;
}
- Status = EFI_INVALID_PARAMETER;
-
//
// Load and start the load option.
//
@@ -1282,54 +1371,62 @@ EfiBootManagerProcessLoadOption (
LoadOption->Description
));
ImageHandle = NULL;
- FileBuffer = EfiBootManagerGetLoadOptionBuffer (LoadOption->FilePath, &FilePath, &FileSize);
- DEBUG_CODE (
- if (FileBuffer != NULL && CompareMem (LoadOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) {
- DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: "));
- BmPrintDp (LoadOption->FilePath);
- DEBUG ((EFI_D_INFO, " -> "));
- BmPrintDp (FilePath);
- DEBUG ((EFI_D_INFO, "\n"));
+ CurFullPath = NULL;
+ EfiBootManagerConnectDevicePath (LoadOption->FilePath, NULL);
+
+ //
+ // while() loop is to keep starting next matched load option if the PlatformRecovery#### returns failure status.
+ //
+ while (TRUE) {
+ Status = EFI_INVALID_PARAMETER;
+ PreFullPath = CurFullPath;
+ FileBuffer = BmGetNextLoadOptionBuffer (LoadOption->OptionType, LoadOption->FilePath, &CurFullPath, &FileSize);
+ if (PreFullPath != NULL) {
+ FreePool (PreFullPath);
+ }
+ if (FileBuffer == NULL) {
+ break;
}
- );
- if (BmIsLoadOptionPeHeaderValid (LoadOption->OptionType, FileBuffer, FileSize)) {
Status = gBS->LoadImage (
FALSE,
gImageHandle,
- FilePath,
+ CurFullPath,
FileBuffer,
FileSize,
&ImageHandle
);
- }
- if (FilePath != NULL) {
- FreePool (FilePath);
- }
- if (FileBuffer != NULL) {
FreePool (FileBuffer);
- }
- if (!EFI_ERROR (Status)) {
- Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
- ASSERT_EFI_ERROR (Status);
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&ImageInfo);
+ ASSERT_EFI_ERROR (Status);
- ImageInfo->LoadOptionsSize = LoadOption->OptionalDataSize;
- ImageInfo->LoadOptions = LoadOption->OptionalData;
- //
- // Before calling the image, enable the Watchdog Timer for the 5-minute period
- //
- gBS->SetWatchdogTimer (5 * 60, 0, 0, NULL);
+ ImageInfo->LoadOptionsSize = LoadOption->OptionalDataSize;
+ ImageInfo->LoadOptions = LoadOption->OptionalData;
+ //
+ // Before calling the image, enable the Watchdog Timer for the 5-minute period
+ //
+ gBS->SetWatchdogTimer (5 * 60, 0, 0, NULL);
- LoadOption->Status = gBS->StartImage (ImageHandle, &LoadOption->ExitDataSize, &LoadOption->ExitData);
- DEBUG ((
- DEBUG_INFO | DEBUG_LOAD, "%s%04x Return Status = %r\n",
- mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber, LoadOption->Status
+ LoadOption->Status = gBS->StartImage (ImageHandle, &LoadOption->ExitDataSize, &LoadOption->ExitData);
+ DEBUG ((
+ DEBUG_INFO | DEBUG_LOAD, "%s%04x Return Status = %r\n",
+ mBmLoadOptionName[LoadOption->OptionType],
+ LoadOption->OptionNumber, LoadOption->Status
));
- //
- // Clear the Watchdog Timer after the image returns
- //
- gBS->SetWatchdogTimer (0, 0, 0, NULL);
+ //
+ // Clear the Watchdog Timer after the image returns
+ //
+ gBS->SetWatchdogTimer (0, 0, 0, NULL);
+
+ if ((LoadOption->OptionType != LoadOptionTypePlatformRecovery) || (LoadOption->Status == EFI_SUCCESS)) {
+ break;
+ }
+ }
+ }
+
+ if (CurFullPath != NULL) {
+ FreePool (CurFullPath);
}
return Status;
diff --git a/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h b/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h
index 8d7215a..ef09050 100644
--- a/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h
+++ b/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h
@@ -310,23 +310,6 @@ BmSetVariableAndReportStatusCodeOnError (
);
/**
- Return whether the PE header of the load option is valid or not.
-
- @param[in] Type The load option type.
- @param[in] FileBuffer The PE file buffer of the load option.
- @param[in] FileSize The size of the load option file.
-
- @retval TRUE The PE header of the load option is valid.
- @retval FALSE The PE header of the load option is not valid.
-**/
-BOOLEAN
-BmIsLoadOptionPeHeaderValid (
- IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type,
- IN VOID *FileBuffer,
- IN UINTN FileSize
- );
-
-/**
Function compares a device path data structure to that of all the nodes of a
second device path instance.
@@ -425,16 +408,83 @@ BmMakeBootOptionDescriptionUnique (
@param LoadFileHandle The specified Load File instance.
@param FilePath The file path which will pass to LoadFile().
- @param FullPath Return the full device path pointing to the load option.
- @param FileSize Return the size of the load option.
- @return The load option buffer or NULL if fails.
+ @return The full device path pointing to the load option buffer.
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+BmExpandLoadFile (
+ IN EFI_HANDLE LoadFileHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ );
+
+/**
+ Return the RAM Disk device path created by LoadFile.
+
+ @param FilePath The source file path.
+
+ @return Callee-to-free RAM Disk device path **/
+EFI_DEVICE_PATH_PROTOCOL * BmGetRamDiskDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ );
+
+/**
+ Destroy the RAM Disk.
+
+ The destroy operation includes to call RamDisk.Unregister to
+ unregister the RAM DISK from RAM DISK driver, free the memory
+ allocated for the RAM Disk.
+
+ @param RamDiskDevicePath RAM Disk device path.
+**/
+VOID
+BmDestroyRamDisk (
+ IN EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath
+ );
+
+/**
+ Get the next possible full path pointing to the load option.
+
+ @param FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+ @param FullPath The full path returned by the routine in last call.
+ Set to NULL in first call.
+
+ @return The next possible full path pointing to the load option.
+ Caller is responsible to free the memory.
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+BmGetNextLoadOptionDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath
+ );
+
+/**
+ Return the next matched load option buffer.
+ The routine keeps calling BmGetNextLoadOptionDevicePath() until a
+valid
+ load option is read.
+
+ @param Type The load option type.
+ It's used to check whether the load option is valid.
+ When it's LoadOptionTypeMax, the routine only guarantees
+ the load option is a valid PE image but doesn't guarantee
+ the PE's subsystem type is valid.
+ @param FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+ @param FullPath Return the next full device path of the load option after
+ short-form device path expanding.
+ Caller is responsible to free it.
+ NULL to return the first matched full device path.
+ @param FileSize Return the load option size.
+
+ @return The load option buffer. Caller is responsible to free the memory.
**/
VOID *
-BmGetFileBufferFromLoadFile (
- EFI_HANDLE LoadFileHandle,
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
- OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
- OUT UINTN *FileSize
+BmGetNextLoadOptionBuffer (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
+ OUT UINTN *FileSize
);
#endif // _INTERNAL_BM_H_
--
2.9.0.windows.1
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2017-04-07 2:49 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-04-06 9:44 [PATCH] MdeModulePkg/UefiBootManagerLib: Enhance short-form expanding logic Ruiyu Ni
2017-04-07 2:48 ` Tian, Feng
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox