summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c
diff options
context:
space:
mode:
Diffstat (limited to 'MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c')
-rw-r--r--MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c173
1 files changed, 135 insertions, 38 deletions
diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c b/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c
index 116cf28fe3..b0a35058d0 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;