MdeModulePkg: Enable PlatformRecovery in BdsDxe driver

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
Reviewed-by: Sunny Wang <sunnywang@hpe.com>

git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@18863 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
Ruiyu Ni 2015-11-17 10:15:09 +00:00 committed by niruiyu
parent d175f4e612
commit 68456d8ac1
2 changed files with 95 additions and 314 deletions

View File

@ -24,9 +24,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <Protocol/Bds.h> #include <Protocol/Bds.h>
#include <Protocol/LoadedImage.h> #include <Protocol/LoadedImage.h>
#include <Protocol/VariableLock.h> #include <Protocol/VariableLock.h>
#include <Protocol/BlockIo.h>
#include <Protocol/LoadFile.h>
#include <Protocol/SimpleFileSystem.h>
#include <Library/UefiDriverEntryPoint.h> #include <Library/UefiDriverEntryPoint.h>
#include <Library/DebugLib.h> #include <Library/DebugLib.h>

View File

@ -51,10 +51,10 @@ CHAR16 *mReadOnlyVariables[] = {
CHAR16 *mBdsLoadOptionName[] = { CHAR16 *mBdsLoadOptionName[] = {
L"Driver", L"Driver",
L"SysPrep", L"SysPrep",
L"Boot" L"Boot",
L"PlatformRecovery"
}; };
CHAR16 mRecoveryBoot[] = L"Recovery Boot";
/** /**
Event to Connect ConIn. Event to Connect ConIn.
@ -121,187 +121,6 @@ BdsInitialize (
return Status; return Status;
} }
/**
Emuerate all possible bootable medias in the following order:
1. Removable BlockIo - The boot option only points to the removable media
device, like USB key, DVD, Floppy etc.
2. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
like HardDisk.
3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
SimpleFileSystem Protocol, but not supporting BlockIo
protocol.
4. LoadFile - The boot option points to the media supporting
LoadFile protocol.
Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior
@param BootOptionCount Return the boot option count which has been found.
@retval Pointer to the boot option array.
**/
EFI_BOOT_MANAGER_LOAD_OPTION *
BdsEnumerateBootOptions (
UINTN *BootOptionCount
)
{
EFI_STATUS Status;
EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
UINTN HandleCount;
EFI_HANDLE *Handles;
EFI_BLOCK_IO_PROTOCOL *BlkIo;
UINTN Removable;
UINTN Index;
ASSERT (BootOptionCount != NULL);
*BootOptionCount = 0;
BootOptions = NULL;
//
// Parse removable block io followed by fixed block io
//
gBS->LocateHandleBuffer (
ByProtocol,
&gEfiBlockIoProtocolGuid,
NULL,
&HandleCount,
&Handles
);
for (Removable = 0; Removable < 2; Removable++) {
for (Index = 0; Index < HandleCount; Index++) {
Status = gBS->HandleProtocol (
Handles[Index],
&gEfiBlockIoProtocolGuid,
(VOID **) &BlkIo
);
if (EFI_ERROR (Status)) {
continue;
}
//
// Skip the logical partitions
//
if (BlkIo->Media->LogicalPartition) {
continue;
}
//
// Skip the fixed block io then the removable block io
//
if (BlkIo->Media->RemovableMedia == ((Removable == 0) ? FALSE : TRUE)) {
continue;
}
BootOptions = ReallocatePool (
sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
BootOptions
);
ASSERT (BootOptions != NULL);
Status = EfiBootManagerInitializeLoadOption (
&BootOptions[(*BootOptionCount)++],
LoadOptionNumberUnassigned,
LoadOptionTypeBoot,
LOAD_OPTION_ACTIVE,
mRecoveryBoot,
DevicePathFromHandle (Handles[Index]),
NULL,
0
);
ASSERT_EFI_ERROR (Status);
}
}
if (HandleCount != 0) {
FreePool (Handles);
}
//
// Parse simple file system not based on block io
//
gBS->LocateHandleBuffer (
ByProtocol,
&gEfiSimpleFileSystemProtocolGuid,
NULL,
&HandleCount,
&Handles
);
for (Index = 0; Index < HandleCount; Index++) {
Status = gBS->HandleProtocol (
Handles[Index],
&gEfiBlockIoProtocolGuid,
(VOID **) &BlkIo
);
if (!EFI_ERROR (Status)) {
//
// Skip if the file system handle supports a BlkIo protocol, which we've handled in above
//
continue;
}
BootOptions = ReallocatePool (
sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
BootOptions
);
ASSERT (BootOptions != NULL);
Status = EfiBootManagerInitializeLoadOption (
&BootOptions[(*BootOptionCount)++],
LoadOptionNumberUnassigned,
LoadOptionTypeBoot,
LOAD_OPTION_ACTIVE,
mRecoveryBoot,
DevicePathFromHandle (Handles[Index]),
NULL,
0
);
ASSERT_EFI_ERROR (Status);
}
if (HandleCount != 0) {
FreePool (Handles);
}
//
// Parse load file, assuming UEFI Network boot option
//
gBS->LocateHandleBuffer (
ByProtocol,
&gEfiLoadFileProtocolGuid,
NULL,
&HandleCount,
&Handles
);
for (Index = 0; Index < HandleCount; Index++) {
BootOptions = ReallocatePool (
sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
BootOptions
);
ASSERT (BootOptions != NULL);
Status = EfiBootManagerInitializeLoadOption (
&BootOptions[(*BootOptionCount)++],
LoadOptionNumberUnassigned,
LoadOptionTypeBoot,
LOAD_OPTION_ACTIVE,
mRecoveryBoot,
DevicePathFromHandle (Handles[Index]),
NULL,
0
);
ASSERT_EFI_ERROR (Status);
}
if (HandleCount != 0) {
FreePool (Handles);
}
return BootOptions;
}
/** /**
Function waits for a given event to fire, or for an optional timeout to expire. Function waits for a given event to fire, or for an optional timeout to expire.
@ -445,14 +264,16 @@ BdsWait (
@param BootOptions Input boot option array. @param BootOptions Input boot option array.
@param BootOptionCount Input boot option count. @param BootOptionCount Input boot option count.
@param BootManagerMenu Input boot manager menu.
@retval TRUE Successfully boot one of the boot options. @retval TRUE Successfully boot one of the boot options.
@retval FALSE Failed boot any of the boot options. @retval FALSE Failed boot any of the boot options.
**/ **/
BOOLEAN BOOLEAN
BootAllBootOptions ( BootBootOptions (
IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions, IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions,
IN UINTN BootOptionCount IN UINTN BootOptionCount,
IN EFI_BOOT_MANAGER_LOAD_OPTION *BootManagerMenu
) )
{ {
UINTN Index; UINTN Index;
@ -486,9 +307,10 @@ BootAllBootOptions (
EfiBootManagerBoot (&BootOptions[Index]); EfiBootManagerBoot (&BootOptions[Index]);
// //
// Successful boot breaks the loop, otherwise tries next boot option // If the boot via Boot#### returns with a status of EFI_SUCCESS, platform firmware // supports boot manager menu, and if firmware is configured to boot in an // interactive mode, the boot manager will stop processing the BootOrder variable and // present a boot manager menu to the user.
// //
if (BootOptions[Index].Status == EFI_SUCCESS) { if (BootOptions[Index].Status == EFI_SUCCESS) {
EfiBootManagerBoot (BootManagerMenu);
break; break;
} }
} }
@ -497,72 +319,10 @@ BootAllBootOptions (
} }
/** /**
This function attempts to boot per the boot order specified by platform policy. The function will load and start every Driver####, SysPrep#### or PlatformRecovery####.
If the boot via Boot#### returns with a status of EFI_SUCCESS the boot manager will stop
processing the BootOrder variable and present a boot manager menu to the user. If a boot via
Boot#### returns a status other than EFI_SUCCESS, the boot has failed and the next Boot####
in the BootOrder variable will be tried until all possibilities are exhausted.
-- Chapter 3.1.1 Boot Manager Programming, the 4th paragraph
**/
VOID
DefaultBootBehavior (
VOID
)
{
UINTN BootOptionCount;
EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;
EfiBootManagerGetBootManagerMenu (&BootManagerMenu);
//
// BootManagerMenu always contains the correct information even the above function returns failure.
//
BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
if (BootAllBootOptions (BootOptions, BootOptionCount)) {
//
// Follow generic rule, Call BdsDxeOnConnectConInCallBack to connect ConIn before enter UI
//
if (PcdGetBool (PcdConInConnectOnDemand)) {
BdsDxeOnConnectConInCallBack (NULL, NULL);
}
//
// Show the Boot Manager Menu after successful boot
//
EfiBootManagerBoot (&BootManagerMenu);
} else {
EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
//
// Re-scan all EFI boot options in case all the boot#### are deleted or failed to boot
//
// If no valid boot options exist, the boot manager will enumerate all removable media
// devices followed by all fixed media devices. The order within each group is undefined.
// These new default boot options are not saved to non volatile storage.The boot manger
// will then attempt toboot from each boot option.
// -- Chapter 3.3 Boot Manager Programming, the 2nd paragraph
//
EfiBootManagerConnectAll ();
BootOptions = BdsEnumerateBootOptions (&BootOptionCount);
if (!BootAllBootOptions (BootOptions, BootOptionCount)) {
DEBUG ((EFI_D_ERROR, "[Bds]No bootable device!\n"));
EfiBootManagerBoot (&BootManagerMenu);
}
}
EfiBootManagerFreeLoadOption (&BootManagerMenu);
EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
}
/**
The function will load and start every Driver####/SysPrep####.
@param LoadOptions Load option array. @param LoadOptions Load option array.
@param LoadOptionCount Load option count. @param LoadOptionCount Load option count.
**/ **/
VOID VOID
ProcessLoadOptions ( ProcessLoadOptions (
@ -575,7 +335,7 @@ ProcessLoadOptions (
BOOLEAN ReconnectAll; BOOLEAN ReconnectAll;
EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType; EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType;
ReconnectAll = FALSE; ReconnectAll = FALSE;
LoadOptionType = LoadOptionTypeMax; LoadOptionType = LoadOptionTypeMax;
// //
@ -585,16 +345,23 @@ ProcessLoadOptions (
// //
// All the load options in the array should be of the same type. // All the load options in the array should be of the same type.
// //
if (LoadOptionType == LoadOptionTypeMax) { if (Index == 0) {
LoadOptionType = LoadOptions[Index].OptionType; LoadOptionType = LoadOptions[Index].OptionType;
} }
ASSERT (LoadOptionType == LoadOptions[Index].OptionType); ASSERT (LoadOptionType == LoadOptions[Index].OptionType);
ASSERT (LoadOptionType == LoadOptionTypeDriver || LoadOptionType == LoadOptionTypeSysPrep);
Status = EfiBootManagerProcessLoadOption (&LoadOptions[Index]); Status = EfiBootManagerProcessLoadOption (&LoadOptions[Index]);
if (!EFI_ERROR (Status) && ((LoadOptions[Index].Attributes & LOAD_OPTION_FORCE_RECONNECT) != 0)) { if (!EFI_ERROR (Status)) {
ReconnectAll = TRUE; if (LoadOptionType == LoadOptionTypePlatformRecovery) {
//
// Stop processing if any entry is successful
//
break;
}
if ((LoadOptions[Index].Attributes & LOAD_OPTION_FORCE_RECONNECT) != 0) {
ReconnectAll = TRUE;
}
} }
} }
@ -670,7 +437,7 @@ BdsFormalizeOSIndicationVariable (
// //
// OS indicater support variable // OS indicater support variable
// //
OsIndicationSupport = EFI_OS_INDICATIONS_BOOT_TO_FW_UI; OsIndicationSupport = EFI_OS_INDICATIONS_BOOT_TO_FW_UI | EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY;
Status = gRT->SetVariable ( Status = gRT->SetVariable (
EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME, EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME,
&gEfiGlobalVariableGuid, &gEfiGlobalVariableGuid,
@ -828,10 +595,13 @@ BdsEntry (
CHAR16 BootNextVariableName[sizeof ("Boot####")]; CHAR16 BootNextVariableName[sizeof ("Boot####")];
EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu; EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;
BOOLEAN BootFwUi; BOOLEAN BootFwUi;
BOOLEAN PlatformRecovery;
BOOLEAN BootSuccess;
EFI_DEVICE_PATH_PROTOCOL *FilePath; EFI_DEVICE_PATH_PROTOCOL *FilePath;
HotkeyTriggered = NULL; HotkeyTriggered = NULL;
Status = EFI_SUCCESS; Status = EFI_SUCCESS;
BootSuccess = FALSE;
// //
// Insert the performance probe // Insert the performance probe
@ -1038,9 +808,24 @@ BdsEntry (
PERF_START (NULL, "PlatformBootManagerAfterConsole", "BDS", 0); PERF_START (NULL, "PlatformBootManagerAfterConsole", "BDS", 0);
PlatformBootManagerAfterConsole (); PlatformBootManagerAfterConsole ();
PERF_END (NULL, "PlatformBootManagerAfterConsole", "BDS", 0); PERF_END (NULL, "PlatformBootManagerAfterConsole", "BDS", 0);
//
// Boot to Boot Manager Menu when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot
//
DataSize = sizeof (UINT64);
Status = gRT->GetVariable (
EFI_OS_INDICATIONS_VARIABLE_NAME,
&gEfiGlobalVariableGuid,
NULL,
&DataSize,
&OsIndication
);
if (EFI_ERROR (Status)) {
OsIndication = 0;
}
DEBUG_CODE ( DEBUG_CODE (
EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType; EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType;
DEBUG ((EFI_D_INFO, "[Bds]OsIndication: %016x\n", OsIndication));
DEBUG ((EFI_D_INFO, "[Bds]=============Begin Load Options Dumping ...=============\n")); DEBUG ((EFI_D_INFO, "[Bds]=============Begin Load Options Dumping ...=============\n"));
for (LoadOptionType = 0; LoadOptionType < LoadOptionTypeMax; LoadOptionType++) { for (LoadOptionType = 0; LoadOptionType < LoadOptionTypeMax; LoadOptionType++) {
DEBUG (( DEBUG ((
@ -1063,26 +848,17 @@ BdsEntry (
); );
// //
// Boot to Boot Manager Menu when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot // BootManagerMenu always contains the correct information even call fails.
// //
DataSize = sizeof (UINT64); EfiBootManagerGetBootManagerMenu (&BootManagerMenu);
Status = gRT->GetVariable (
EFI_OS_INDICATIONS_VARIABLE_NAME,
&gEfiGlobalVariableGuid,
NULL,
&DataSize,
&OsIndication
);
if (EFI_ERROR (Status)) {
OsIndication = 0;
}
BootFwUi = (BOOLEAN) ((OsIndication & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) != 0); BootFwUi = (BOOLEAN) ((OsIndication & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) != 0);
PlatformRecovery = (BOOLEAN) ((OsIndication & EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY) != 0);
// //
// Clear EFI_OS_INDICATIONS_BOOT_TO_FW_UI to acknowledge OS // Clear EFI_OS_INDICATIONS_BOOT_TO_FW_UI to acknowledge OS
// //
if (BootFwUi) { if (BootFwUi || PlatformRecovery) {
OsIndication &= ~((UINT64) EFI_OS_INDICATIONS_BOOT_TO_FW_UI); OsIndication &= ~((UINT64) (EFI_OS_INDICATIONS_BOOT_TO_FW_UI | EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY));
Status = gRT->SetVariable ( Status = gRT->SetVariable (
EFI_OS_INDICATIONS_VARIABLE_NAME, EFI_OS_INDICATIONS_VARIABLE_NAME,
&gEfiGlobalVariableGuid, &gEfiGlobalVariableGuid,
@ -1109,62 +885,70 @@ BdsEntry (
// //
// Directly enter the setup page. // Directly enter the setup page.
// BootManagerMenu always contains the correct information even call fails.
// //
EfiBootManagerGetBootManagerMenu (&BootManagerMenu);
EfiBootManagerBoot (&BootManagerMenu); EfiBootManagerBoot (&BootManagerMenu);
EfiBootManagerFreeLoadOption (&BootManagerMenu);
} }
// if (!PlatformRecovery) {
// Execute SysPrep#### //
// // Execute SysPrep####
LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeSysPrep); //
ProcessLoadOptions (LoadOptions, LoadOptionCount); LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeSysPrep);
EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount); ProcessLoadOptions (LoadOptions, LoadOptionCount);
EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);
// //
// Execute Key#### // Execute Key####
// //
PERF_START (NULL, "BdsWait", "BDS", 0); PERF_START (NULL, "BdsWait", "BDS", 0);
BdsWait (HotkeyTriggered); BdsWait (HotkeyTriggered);
PERF_END (NULL, "BdsWait", "BDS", 0); PERF_END (NULL, "BdsWait", "BDS", 0);
// //
// BdsReadKeys() be removed after all keyboard drivers invoke callback in timer callback. // BdsReadKeys() can be removed after all keyboard drivers invoke callback in timer callback.
// //
BdsReadKeys (); BdsReadKeys ();
EfiBootManagerHotkeyBoot (); EfiBootManagerHotkeyBoot ();
// //
// Boot to "BootNext" // Boot to "BootNext"
// //
if (BootNext != NULL) { if (BootNext != NULL) {
UnicodeSPrint (BootNextVariableName, sizeof (BootNextVariableName), L"Boot%04x", *BootNext); UnicodeSPrint (BootNextVariableName, sizeof (BootNextVariableName), L"Boot%04x", *BootNext);
Status = EfiBootManagerVariableToLoadOption (BootNextVariableName, &LoadOption); Status = EfiBootManagerVariableToLoadOption (BootNextVariableName, &LoadOption);
if (!EFI_ERROR (Status)) { if (!EFI_ERROR (Status)) {
EfiBootManagerBoot (&LoadOption);
EfiBootManagerFreeLoadOption (&LoadOption);
if (LoadOption.Status == EFI_SUCCESS) {
//
// Boot to Boot Manager Menu upon EFI_SUCCESS
//
EfiBootManagerGetBootManagerMenu (&LoadOption);
EfiBootManagerBoot (&LoadOption); EfiBootManagerBoot (&LoadOption);
EfiBootManagerFreeLoadOption (&LoadOption); EfiBootManagerFreeLoadOption (&LoadOption);
if (LoadOption.Status == EFI_SUCCESS) {
//
// Boot to Boot Manager Menu upon EFI_SUCCESS
//
EfiBootManagerBoot (&BootManagerMenu);
}
} }
} }
do {
//
// Retry to boot if any of the boot succeeds
//
LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeBoot);
BootSuccess = BootBootOptions (LoadOptions, LoadOptionCount, &BootManagerMenu);
EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);
} while (BootSuccess);
} }
while (TRUE) { EfiBootManagerFreeLoadOption (&BootManagerMenu);
//
// BDS select the boot device to load OS if (!BootSuccess) {
// Try next upon boot failure LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypePlatformRecovery);
// Show Boot Manager Menu upon boot success ProcessLoadOptions (LoadOptions, LoadOptionCount);
// EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);
DefaultBootBehavior ();
} }
DEBUG ((EFI_D_ERROR, "[Bds] Unable to boot!\n"));
CpuDeadLoop ();
} }
/** /**