/** @file\r
- This module produce main entry for BDS phase - BdsEntry. \r
+ This module produce main entry for BDS phase - BdsEntry.\r
When this module was dispatched by DxeCore, gEfiBdsArchProtocolGuid will be installed\r
which contains interface of BdsEntry.\r
After DxeCore finish DXE phase, gEfiBdsArchProtocolGuid->BdsEntry will be invoked\r
to enter BDS phase.\r
\r
-Copyright (c) 2004 - 2008, Intel Corporation. <BR>\r
-All rights reserved. This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution. The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>\r
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
+(C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
#include "Bds.h"\r
#include "Language.h"\r
-#include "FrontPage.h"\r
-#include "Hotkey.h"\r
#include "HwErrRecSupport.h"\r
\r
+#define SET_BOOT_OPTION_SUPPORT_KEY_COUNT(a, c) { \\r
+ (a) = ((a) & ~EFI_BOOT_OPTION_SUPPORT_COUNT) | (((c) << LowBitSet32 (EFI_BOOT_OPTION_SUPPORT_COUNT)) & EFI_BOOT_OPTION_SUPPORT_COUNT); \\r
+ }\r
+\r
///\r
/// BDS arch protocol instance initial value.\r
///\r
-/// Note: Current BDS not directly get the BootMode, DefaultBoot,\r
-/// TimeoutDefault, MemoryTestLevel value from the BDS arch protocol.\r
-/// Please refer to the library useage of BdsLibGetBootMode, BdsLibGetTimeout \r
-/// and PlatformBdsDiagnostics in BdsPlatform.c\r
+EFI_BDS_ARCH_PROTOCOL gBds = {\r
+ BdsEntry\r
+};\r
+\r
+//\r
+// gConnectConInEvent - Event which is signaled when ConIn connection is required\r
+//\r
+EFI_EVENT gConnectConInEvent = NULL;\r
+\r
+///\r
+/// The read-only variables defined in UEFI Spec.\r
///\r
-EFI_BDS_ARCH_PROTOCOL_INSTANCE gBdsInstanceTemplate = {\r
- EFI_BDS_ARCH_PROTOCOL_INSTANCE_SIGNATURE,\r
- NULL,\r
- {BdsEntry},\r
- 0xFFFF,\r
- TRUE,\r
- 0,\r
- EXTENSIVE\r
+CHAR16 *mReadOnlyVariables[] = {\r
+ EFI_PLATFORM_LANG_CODES_VARIABLE_NAME,\r
+ EFI_LANG_CODES_VARIABLE_NAME,\r
+ EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME,\r
+ EFI_HW_ERR_REC_SUPPORT_VARIABLE_NAME,\r
+ EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME\r
+ };\r
+\r
+CHAR16 *mBdsLoadOptionName[] = {\r
+ L"Driver",\r
+ L"SysPrep",\r
+ L"Boot",\r
+ L"PlatformRecovery"\r
};\r
\r
-UINT16 *mBootNext = NULL;\r
+/**\r
+ Event to Connect ConIn.\r
+\r
+ @param Event Event whose notification function is being invoked.\r
+ @param Context Pointer to the notification function's context,\r
+ which is implementation-dependent.\r
\r
-EFI_HANDLE mBdsImageHandle;\r
+**/\r
+VOID\r
+EFIAPI\r
+BdsDxeOnConnectConInCallBack (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // When Osloader call ReadKeyStroke to signal this event\r
+ // no driver dependency is assumed existing. So use a non-dispatch version\r
+ //\r
+ Status = EfiBootManagerConnectConsoleVariable (ConIn);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Should not enter this case, if enter, the keyboard will not work.\r
+ // May need platfrom policy to connect keyboard.\r
+ //\r
+ DEBUG ((EFI_D_WARN, "[Bds] Connect ConIn failed - %r!!!\n", Status));\r
+ }\r
+}\r
+/**\r
+ Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT. This is used to\r
+ check whether there is remaining deferred load images.\r
+\r
+ @param[in] Event The Event that is being processed.\r
+ @param[in] Context The Event Context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+CheckDeferredLoadImageOnReadyToBoot (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_DEFERRED_IMAGE_LOAD_PROTOCOL *DeferredImage;\r
+ UINTN HandleCount;\r
+ EFI_HANDLE *Handles;\r
+ UINTN Index;\r
+ UINTN ImageIndex;\r
+ EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath;\r
+ VOID *Image;\r
+ UINTN ImageSize;\r
+ BOOLEAN BootOption;\r
+ CHAR16 *DevicePathStr;\r
+\r
+ //\r
+ // Find all the deferred image load protocols.\r
+ //\r
+ HandleCount = 0;\r
+ Handles = NULL;\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiDeferredImageLoadProtocolGuid,\r
+ NULL,\r
+ &HandleCount,\r
+ &Handles\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return;\r
+ }\r
+\r
+ for (Index = 0; Index < HandleCount; Index++) {\r
+ Status = gBS->HandleProtocol (Handles[Index], &gEfiDeferredImageLoadProtocolGuid, (VOID **) &DeferredImage);\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ for (ImageIndex = 0; ; ImageIndex++) {\r
+ //\r
+ // Load all the deferred images in this protocol instance.\r
+ //\r
+ Status = DeferredImage->GetImageInfo (\r
+ DeferredImage,\r
+ ImageIndex,\r
+ &ImageDevicePath,\r
+ (VOID **) &Image,\r
+ &ImageSize,\r
+ &BootOption\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ DevicePathStr = ConvertDevicePathToText (ImageDevicePath, FALSE, FALSE);\r
+ DEBUG ((DEBUG_LOAD, "[Bds] Image was deferred but not loaded: %s.\n", DevicePathStr));\r
+ if (DevicePathStr != NULL) {\r
+ FreePool (DevicePathStr);\r
+ }\r
+ }\r
+ }\r
+ if (Handles != NULL) {\r
+ FreePool (Handles);\r
+ }\r
+}\r
\r
/**\r
\r
)\r
{\r
EFI_STATUS Status;\r
-\r
- mBdsImageHandle = ImageHandle;\r
-\r
+ EFI_HANDLE Handle;\r
//\r
// Install protocol interface\r
//\r
- Status = gBS->InstallProtocolInterface (\r
- &gBdsInstanceTemplate.Handle,\r
- &gEfiBdsArchProtocolGuid,\r
- EFI_NATIVE_INTERFACE,\r
- &gBdsInstanceTemplate.Bds\r
+ Handle = NULL;\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &Handle,\r
+ &gEfiBdsArchProtocolGuid, &gBds,\r
+ NULL\r
);\r
ASSERT_EFI_ERROR (Status);\r
\r
+ DEBUG_CODE (\r
+ EFI_EVENT Event;\r
+ //\r
+ // Register notify function to check deferred images on ReadyToBoot Event.\r
+ //\r
+ Status = gBS->CreateEventEx (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ CheckDeferredLoadImageOnReadyToBoot,\r
+ NULL,\r
+ &gEfiEventReadyToBootGuid,\r
+ &Event\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ );\r
return Status;\r
}\r
\r
/**\r
+ Function waits for a given event to fire, or for an optional timeout to expire.\r
\r
- This function attempts to boot for the boot order specified\r
- by platform policy.\r
+ @param Event The event to wait for\r
+ @param Timeout An optional timeout value in 100 ns units.\r
+\r
+ @retval EFI_SUCCESS Event fired before Timeout expired.\r
+ @retval EFI_TIME_OUT Timout expired before Event fired..\r
+\r
+**/\r
+EFI_STATUS\r
+BdsWaitForSingleEvent (\r
+ IN EFI_EVENT Event,\r
+ IN UINT64 Timeout OPTIONAL\r
+ )\r
+{\r
+ UINTN Index;\r
+ EFI_STATUS Status;\r
+ EFI_EVENT TimerEvent;\r
+ EFI_EVENT WaitList[2];\r
+\r
+ if (Timeout != 0) {\r
+ //\r
+ // Create a timer event\r
+ //\r
+ Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Set the timer event\r
+ //\r
+ gBS->SetTimer (\r
+ TimerEvent,\r
+ TimerRelative,\r
+ Timeout\r
+ );\r
+\r
+ //\r
+ // Wait for the original event or the timer\r
+ //\r
+ WaitList[0] = Event;\r
+ WaitList[1] = TimerEvent;\r
+ Status = gBS->WaitForEvent (2, WaitList, &Index);\r
+ ASSERT_EFI_ERROR (Status);\r
+ gBS->CloseEvent (TimerEvent);\r
+\r
+ //\r
+ // If the timer expired, change the return to timed out\r
+ //\r
+ if (Index == 1) {\r
+ Status = EFI_TIMEOUT;\r
+ }\r
+ }\r
+ } else {\r
+ //\r
+ // No timeout... just wait on the event\r
+ //\r
+ Status = gBS->WaitForEvent (1, &Event, &Index);\r
+ ASSERT (!EFI_ERROR (Status));\r
+ ASSERT (Index == 0);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ The function reads user inputs.\r
\r
**/\r
VOID\r
-BdsBootDeviceSelect (\r
+BdsReadKeys (\r
VOID\r
)\r
{\r
- EFI_STATUS Status;\r
- LIST_ENTRY *Link;\r
- BDS_COMMON_OPTION *BootOption;\r
- UINTN ExitDataSize;\r
- CHAR16 *ExitData;\r
- UINT16 Timeout;\r
- LIST_ENTRY BootLists;\r
- CHAR16 Buffer[20];\r
- BOOLEAN BootNextExist;\r
- LIST_ENTRY *LinkBootNext;\r
+ EFI_STATUS Status;\r
+ EFI_INPUT_KEY Key;\r
+\r
+ if (PcdGetBool (PcdConInConnectOnDemand)) {\r
+ return;\r
+ }\r
+\r
+ while (gST->ConIn != NULL) {\r
+\r
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // No more keys.\r
+ //\r
+ break;\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ The function waits for the boot manager timeout expires or hotkey is pressed.\r
+\r
+ It calls PlatformBootManagerWaitCallback each second.\r
+\r
+ @param HotkeyTriggered Input hotkey event.\r
+**/\r
+VOID\r
+BdsWait (\r
+ IN EFI_EVENT HotkeyTriggered\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT16 TimeoutRemain;\r
+\r
+ DEBUG ((EFI_D_INFO, "[Bds]BdsWait ...Zzzzzzzzzzzz...\n"));\r
+\r
+ TimeoutRemain = PcdGet16 (PcdPlatformBootTimeOut);\r
+ while (TimeoutRemain != 0) {\r
+ DEBUG ((EFI_D_INFO, "[Bds]BdsWait(%d)..Zzzz...\n", (UINTN) TimeoutRemain));\r
+ PlatformBootManagerWaitCallback (TimeoutRemain);\r
+\r
+ BdsReadKeys (); // BUGBUG: Only reading can signal HotkeyTriggered\r
+ // Can be removed after all keyboard drivers invoke callback in timer callback.\r
+\r
+ if (HotkeyTriggered != NULL) {\r
+ Status = BdsWaitForSingleEvent (HotkeyTriggered, EFI_TIMER_PERIOD_SECONDS (1));\r
+ if (!EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ } else {\r
+ gBS->Stall (1000000);\r
+ }\r
+\r
+ //\r
+ // 0xffff means waiting forever\r
+ // BDS with no hotkey provided and 0xffff as timeout will "hang" in the loop\r
+ //\r
+ if (TimeoutRemain != 0xffff) {\r
+ TimeoutRemain--;\r
+ }\r
+ }\r
+ DEBUG ((EFI_D_INFO, "[Bds]Exit the waiting!\n"));\r
+}\r
+\r
+/**\r
+ Attempt to boot each boot option in the BootOptions array.\r
+\r
+ @param BootOptions Input boot option array.\r
+ @param BootOptionCount Input boot option count.\r
+ @param BootManagerMenu Input boot manager menu.\r
+\r
+ @retval TRUE Successfully boot one of the boot options.\r
+ @retval FALSE Failed boot any of the boot options.\r
+**/\r
+BOOLEAN\r
+BootBootOptions (\r
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions,\r
+ IN UINTN BootOptionCount,\r
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *BootManagerMenu OPTIONAL\r
+ )\r
+{\r
+ UINTN Index;\r
\r
//\r
- // Got the latest boot option\r
+ // Report Status Code to indicate BDS starts attempting booting from the UEFI BootOrder list.\r
//\r
- BootNextExist = FALSE;\r
- LinkBootNext = NULL;\r
- InitializeListHead (&BootLists);\r
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_ATTEMPT_BOOT_ORDER_EVENT));\r
\r
//\r
- // First check the boot next option\r
+ // Attempt boot each boot option\r
//\r
- ZeroMem (Buffer, sizeof (Buffer));\r
-\r
- if (mBootNext != NULL) {\r
+ for (Index = 0; Index < BootOptionCount; Index++) {\r
//\r
- // Indicate we have the boot next variable, so this time\r
- // boot will always have this boot option\r
+ // According to EFI Specification, if a load option is not marked\r
+ // as LOAD_OPTION_ACTIVE, the boot manager will not automatically\r
+ // load the option.\r
//\r
- BootNextExist = TRUE;\r
+ if ((BootOptions[Index].Attributes & LOAD_OPTION_ACTIVE) == 0) {\r
+ continue;\r
+ }\r
\r
//\r
- // Clear the this variable so it's only exist in this time boot\r
+ // Boot#### load options with LOAD_OPTION_CATEGORY_APP are executables which are not\r
+ // part of the normal boot processing. Boot options with reserved category values will be\r
+ // ignored by the boot manager.\r
//\r
- gRT->SetVariable (\r
- L"BootNext",\r
- &gEfiGlobalVariableGuid,\r
- EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
- 0,\r
- mBootNext\r
- );\r
+ if ((BootOptions[Index].Attributes & LOAD_OPTION_CATEGORY) != LOAD_OPTION_CATEGORY_BOOT) {\r
+ continue;\r
+ }\r
\r
//\r
- // Add the boot next boot option\r
+ // All the driver options should have been processed since\r
+ // now boot will be performed.\r
//\r
- UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *mBootNext);\r
- BootOption = BdsLibVariableToOption (&BootLists, Buffer);\r
- \r
+ EfiBootManagerBoot (&BootOptions[Index]);\r
+\r
//\r
- // If fail to get boot option from variable, just return and do nothing.\r
+ // If the boot via Boot#### returns with a status of EFI_SUCCESS, platform firmware\r
+ // supports boot manager menu, and if firmware is configured to boot in an\r
+ // interactive mode, the boot manager will stop processing the BootOrder variable and\r
+ // present a boot manager menu to the user.\r
//\r
- if (BootOption == NULL) {\r
- return;\r
+ if ((BootManagerMenu != NULL) && (BootOptions[Index].Status == EFI_SUCCESS)) {\r
+ EfiBootManagerBoot (BootManagerMenu);\r
+ break;\r
}\r
- \r
- BootOption->BootCurrent = *mBootNext;\r
}\r
- //\r
- // Parse the boot order to get boot option\r
- //\r
- BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");\r
- Link = BootLists.ForwardLink;\r
+\r
+ return (BOOLEAN) (Index < BootOptionCount);\r
+}\r
+\r
+/**\r
+ The function will load and start every Driver####, SysPrep#### or PlatformRecovery####.\r
+\r
+ @param LoadOptions Load option array.\r
+ @param LoadOptionCount Load option count.\r
+**/\r
+VOID\r
+ProcessLoadOptions (\r
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *LoadOptions,\r
+ IN UINTN LoadOptionCount\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ BOOLEAN ReconnectAll;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType;\r
+\r
+ ReconnectAll = FALSE;\r
+ LoadOptionType = LoadOptionTypeMax;\r
\r
//\r
- // Parameter check, make sure the loop will be valid\r
- //\r
- if (Link == NULL) {\r
- return ;\r
- }\r
- //\r
- // Here we make the boot in a loop, every boot success will\r
- // return to the front page\r
+ // Process the driver option\r
//\r
- for (;;) {\r
+ for (Index = 0; Index < LoadOptionCount; Index++) {\r
//\r
- // Check the boot option list first\r
+ // All the load options in the array should be of the same type.\r
//\r
- if (Link == &BootLists) {\r
- //\r
- // There are two ways to enter here:\r
- // 1. There is no active boot option, give user chance to\r
- // add new boot option\r
- // 2. All the active boot option processed, and there is no\r
- // one is success to boot, then we back here to allow user\r
- // add new active boot option\r
- //\r
- Timeout = 0xffff;\r
- PlatformBdsEnterFrontPage (Timeout, FALSE);\r
- InitializeListHead (&BootLists);\r
- BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");\r
- Link = BootLists.ForwardLink;\r
- continue;\r
+ if (Index == 0) {\r
+ LoadOptionType = LoadOptions[Index].OptionType;\r
}\r
- //\r
- // Get the boot option from the link list\r
- //\r
- BootOption = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);\r
+ ASSERT (LoadOptionType == LoadOptions[Index].OptionType);\r
+ ASSERT (LoadOptionType != LoadOptionTypeBoot);\r
+\r
+ Status = EfiBootManagerProcessLoadOption (&LoadOptions[Index]);\r
\r
//\r
- // According to EFI Specification, if a load option is not marked\r
- // as LOAD_OPTION_ACTIVE, the boot manager will not automatically\r
- // load the option.\r
+ // Status indicates whether the load option is loaded and executed\r
+ // LoadOptions[Index].Status is what the load option returns\r
//\r
- if (!IS_LOAD_OPTION_TYPE (BootOption->Attribute, LOAD_OPTION_ACTIVE)) {\r
+ if (!EFI_ERROR (Status)) {\r
//\r
- // skip the header of the link list, becuase it has no boot option\r
+ // Stop processing if any PlatformRecovery#### returns success.\r
//\r
- Link = Link->ForwardLink;\r
- continue;\r
- }\r
- //\r
- // Make sure the boot option device path connected,\r
- // but ignore the BBS device path\r
- //\r
- if (DevicePathType (BootOption->DevicePath) != BBS_DEVICE_PATH) {\r
+ if ((LoadOptions[Index].Status == EFI_SUCCESS) &&\r
+ (LoadOptionType == LoadOptionTypePlatformRecovery)) {\r
+ break;\r
+ }\r
+\r
//\r
- // Notes: the internal shell can not been connected with device path\r
- // so we do not check the status here\r
+ // Only set ReconnectAll flag when the load option executes successfully.\r
//\r
- BdsLibConnectDevicePath (BootOption->DevicePath);\r
+ if (!EFI_ERROR (LoadOptions[Index].Status) &&\r
+ (LoadOptions[Index].Attributes & LOAD_OPTION_FORCE_RECONNECT) != 0) {\r
+ ReconnectAll = TRUE;\r
+ }\r
}\r
+ }\r
+\r
+ //\r
+ // If a driver load option is marked as LOAD_OPTION_FORCE_RECONNECT,\r
+ // then all of the EFI drivers in the system will be disconnected and\r
+ // reconnected after the last driver load option is processed.\r
+ //\r
+ if (ReconnectAll && LoadOptionType == LoadOptionTypeDriver) {\r
+ EfiBootManagerDisconnectAll ();\r
+ EfiBootManagerConnectAll ();\r
+ }\r
+}\r
+\r
+/**\r
+\r
+ Validate input console variable data.\r
+\r
+ If found the device path is not a valid device path, remove the variable.\r
+\r
+ @param VariableName Input console variable name.\r
+\r
+**/\r
+VOID\r
+BdsFormalizeConsoleVariable (\r
+ IN CHAR16 *VariableName\r
+ )\r
+{\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ UINTN VariableSize;\r
+ EFI_STATUS Status;\r
+\r
+ GetEfiGlobalVariable2 (VariableName, (VOID **) &DevicePath, &VariableSize);\r
+ if ((DevicePath != NULL) && !IsDevicePathValid (DevicePath, VariableSize)) {\r
+ Status = gRT->SetVariable (\r
+ VariableName,\r
+ &gEfiGlobalVariableGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+ 0,\r
+ NULL\r
+ );\r
//\r
- // All the driver options should have been processed since\r
- // now boot will be performed.\r
+ // Deleting variable with current variable implementation shouldn't fail.\r
//\r
- Status = BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);\r
- if (EFI_ERROR (Status)) {\r
- //\r
- // Call platform action to indicate the boot fail\r
- //\r
- BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_FAILED));\r
- PlatformBdsBootFail (BootOption, Status, ExitData, ExitDataSize);\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
\r
- //\r
- // Check the next boot option\r
- //\r
- Link = Link->ForwardLink;\r
+ if (DevicePath != NULL) {\r
+ FreePool (DevicePath);\r
+ }\r
+}\r
\r
- } else {\r
- //\r
- // Call platform action to indicate the boot success\r
- //\r
- BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED)); \r
- PlatformBdsBootSuccess (BootOption);\r
+/**\r
+ Formalize OsIndication related variables.\r
\r
- //\r
- // Boot success, then stop process the boot order, and\r
- // present the boot manager menu, front page\r
- //\r
- Timeout = 0xffff;\r
- PlatformBdsEnterFrontPage (Timeout, FALSE);\r
+ For OsIndicationsSupported, Create a BS/RT/UINT64 variable to report caps\r
+ Delete OsIndications variable if it is not NV/BS/RT UINT64.\r
\r
- //\r
- // Rescan the boot option list, avoid pertential risk of the boot\r
- // option change in front page\r
- //\r
- if (BootNextExist) {\r
- LinkBootNext = BootLists.ForwardLink;\r
- }\r
+ Item 3 is used to solve case when OS corrupts OsIndications. Here simply delete this NV variable.\r
\r
- InitializeListHead (&BootLists);\r
- if (LinkBootNext != NULL) {\r
- //\r
- // Reserve the boot next option\r
- //\r
- InsertTailList (&BootLists, LinkBootNext);\r
- }\r
+ Create a boot option for BootManagerMenu if it hasn't been created yet\r
\r
- BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");\r
- Link = BootLists.ForwardLink;\r
- }\r
+**/\r
+VOID\r
+BdsFormalizeOSIndicationVariable (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 OsIndicationSupport;\r
+ UINT64 OsIndication;\r
+ UINTN DataSize;\r
+ UINT32 Attributes;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;\r
+\r
+ //\r
+ // OS indicater support variable\r
+ //\r
+ Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);\r
+ if (Status != EFI_NOT_FOUND) {\r
+ OsIndicationSupport = EFI_OS_INDICATIONS_BOOT_TO_FW_UI | EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY;\r
+ EfiBootManagerFreeLoadOption (&BootManagerMenu);\r
+ } else {\r
+ OsIndicationSupport = EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY;\r
+ }\r
+\r
+ Status = gRT->SetVariable (\r
+ EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+ sizeof(UINT64),\r
+ &OsIndicationSupport\r
+ );\r
+ //\r
+ // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.\r
+ //\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // If OsIndications is invalid, remove it.\r
+ // Invalid case\r
+ // 1. Data size != UINT64\r
+ // 2. OsIndication value inconsistence\r
+ // 3. OsIndication attribute inconsistence\r
+ //\r
+ OsIndication = 0;\r
+ Attributes = 0;\r
+ DataSize = sizeof(UINT64);\r
+ Status = gRT->GetVariable (\r
+ EFI_OS_INDICATIONS_VARIABLE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ &Attributes,\r
+ &DataSize,\r
+ &OsIndication\r
+ );\r
+ if (Status == EFI_NOT_FOUND) {\r
+ return;\r
}\r
\r
+ if ((DataSize != sizeof (OsIndication)) ||\r
+ ((OsIndication & ~OsIndicationSupport) != 0) ||\r
+ (Attributes != (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE))\r
+ ){\r
+\r
+ DEBUG ((EFI_D_ERROR, "[Bds] Unformalized OsIndications variable exists. Delete it\n"));\r
+ Status = gRT->SetVariable (\r
+ EFI_OS_INDICATIONS_VARIABLE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ 0,\r
+ 0,\r
+ NULL\r
+ );\r
+ //\r
+ // Deleting variable with current variable implementation shouldn't fail.\r
+ //\r
+ ASSERT_EFI_ERROR(Status);\r
+ }\r
+}\r
+\r
+/**\r
+\r
+ Validate variables.\r
+\r
+**/\r
+VOID\r
+BdsFormalizeEfiGlobalVariable (\r
+ VOID\r
+ )\r
+{\r
+ //\r
+ // Validate Console variable.\r
+ //\r
+ BdsFormalizeConsoleVariable (EFI_CON_IN_VARIABLE_NAME);\r
+ BdsFormalizeConsoleVariable (EFI_CON_OUT_VARIABLE_NAME);\r
+ BdsFormalizeConsoleVariable (EFI_ERR_OUT_VARIABLE_NAME);\r
+\r
+ //\r
+ // Validate OSIndication related variable.\r
+ //\r
+ BdsFormalizeOSIndicationVariable ();\r
}\r
\r
/**\r
IN EFI_BDS_ARCH_PROTOCOL *This\r
)\r
{\r
- EFI_BDS_ARCH_PROTOCOL_INSTANCE *PrivateData;\r
- LIST_ENTRY DriverOptionList;\r
- LIST_ENTRY BootOptionList;\r
- UINTN BootNextSize;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION *LoadOptions;\r
+ UINTN LoadOptionCount;\r
+ CHAR16 *FirmwareVendor;\r
+ EFI_EVENT HotkeyTriggered;\r
+ UINT64 OsIndication;\r
+ UINTN DataSize;\r
+ EFI_STATUS Status;\r
+ UINT32 BootOptionSupport;\r
+ UINT16 BootTimeOut;\r
+ EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;\r
+ UINTN Index;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION LoadOption;\r
+ UINT16 *BootNext;\r
+ CHAR16 BootNextVariableName[sizeof ("Boot####")];\r
+ EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;\r
+ BOOLEAN BootFwUi;\r
+ BOOLEAN PlatformRecovery;\r
+ BOOLEAN BootSuccess;\r
+ EFI_DEVICE_PATH_PROTOCOL *FilePath;\r
+ EFI_STATUS BootManagerMenuStatus;\r
+\r
+ HotkeyTriggered = NULL;\r
+ Status = EFI_SUCCESS;\r
+ BootSuccess = FALSE;\r
\r
//\r
// Insert the performance probe\r
//\r
- PERF_END (0, DXE_TOK, NULL, 0);\r
- PERF_START (0, BDS_TOK, NULL, 0);\r
+ PERF_CROSSMODULE_END("DXE");\r
+ PERF_CROSSMODULE_BEGIN("BDS");\r
+ DEBUG ((EFI_D_INFO, "[Bds] Entry...\n"));\r
\r
//\r
- // Initialize the global system boot option and driver option\r
+ // Fill in FirmwareVendor and FirmwareRevision from PCDs\r
//\r
- InitializeListHead (&DriverOptionList);\r
- InitializeListHead (&BootOptionList);\r
+ FirmwareVendor = (CHAR16 *) PcdGetPtr (PcdFirmwareVendor);\r
+ gST->FirmwareVendor = AllocateRuntimeCopyPool (StrSize (FirmwareVendor), FirmwareVendor);\r
+ ASSERT (gST->FirmwareVendor != NULL);\r
+ gST->FirmwareRevision = PcdGet32 (PcdFirmwareRevision);\r
\r
//\r
- // Initialize hotkey service\r
+ // Fixup Tasble CRC after we updated Firmware Vendor and Revision\r
//\r
- InitializeHotkeyService ();\r
+ gST->Hdr.CRC32 = 0;\r
+ gBS->CalculateCrc32 ((VOID *) gST, sizeof (EFI_SYSTEM_TABLE), &gST->Hdr.CRC32);\r
\r
//\r
- // Get the BDS private data\r
+ // Validate Variable.\r
//\r
- PrivateData = EFI_BDS_ARCH_PROTOCOL_INSTANCE_FROM_THIS (This);\r
+ BdsFormalizeEfiGlobalVariable ();\r
\r
//\r
- // Do the platform init, can be customized by OEM/IBV\r
+ // Mark the read-only variables if the Variable Lock protocol exists\r
//\r
- PERF_START (0, "PlatformBds", "BDS", 0);\r
- PlatformBdsInit (PrivateData);\r
+ Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);\r
+ DEBUG ((EFI_D_INFO, "[BdsDxe] Locate Variable Lock protocol - %r\n", Status));\r
+ if (!EFI_ERROR (Status)) {\r
+ for (Index = 0; Index < ARRAY_SIZE (mReadOnlyVariables); Index++) {\r
+ Status = VariableLock->RequestToLock (VariableLock, mReadOnlyVariables[Index], &gEfiGlobalVariableGuid);\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+ }\r
+\r
+ InitializeHwErrRecSupport ();\r
\r
- if (FeaturePcdGet (PcdSupportHardwareErrorRecord)) {\r
- InitializeHwErrRecSupport (PcdGet16 (PcdHardwareErrorRecordLevel));\r
+ //\r
+ // Initialize L"Timeout" EFI global variable.\r
+ //\r
+ BootTimeOut = PcdGet16 (PcdPlatformBootTimeOut);\r
+ if (BootTimeOut != 0xFFFF) {\r
+ //\r
+ // If time out value equal 0xFFFF, no need set to 0xFFFF to variable area because UEFI specification\r
+ // define same behavior between no value or 0xFFFF value for L"Timeout".\r
+ //\r
+ BdsDxeSetVariableAndReportStatusCodeOnError (\r
+ EFI_TIME_OUT_VARIABLE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+ sizeof (UINT16),\r
+ &BootTimeOut\r
+ );\r
}\r
+\r
//\r
- // bugbug: platform specific code\r
- // Initialize the platform specific string and language\r
+ // Initialize L"BootOptionSupport" EFI global variable.\r
+ // Lazy-ConIn implictly disables BDS hotkey.\r
+ //\r
+ BootOptionSupport = EFI_BOOT_OPTION_SUPPORT_APP | EFI_BOOT_OPTION_SUPPORT_SYSPREP;\r
+ if (!PcdGetBool (PcdConInConnectOnDemand)) {\r
+ BootOptionSupport |= EFI_BOOT_OPTION_SUPPORT_KEY;\r
+ SET_BOOT_OPTION_SUPPORT_KEY_COUNT (BootOptionSupport, 3);\r
+ }\r
+ Status = gRT->SetVariable (\r
+ EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+ sizeof (BootOptionSupport),\r
+ &BootOptionSupport\r
+ );\r
+ //\r
+ // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.\r
+ //\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Cache the "BootNext" NV variable before calling any PlatformBootManagerLib APIs\r
+ // This could avoid the "BootNext" set by PlatformBootManagerLib be consumed in this boot.\r
+ //\r
+ GetEfiGlobalVariable2 (EFI_BOOT_NEXT_VARIABLE_NAME, (VOID **) &BootNext, &DataSize);\r
+ if (DataSize != sizeof (UINT16)) {\r
+ if (BootNext != NULL) {\r
+ FreePool (BootNext);\r
+ }\r
+ BootNext = NULL;\r
+ }\r
+\r
+ //\r
+ // Initialize the platform language variables\r
//\r
- InitializeStringSupport ();\r
InitializeLanguage (TRUE);\r
- InitializeFrontPage (TRUE);\r
\r
//\r
- // Set up the device list based on EFI 1.1 variables\r
- // process Driver#### and Load the driver's in the\r
- // driver option list\r
+ // System firmware must include a PlatformRecovery#### variable specifying\r
+ // a short-form File Path Media Device Path containing the platform default\r
+ // file path for removable media\r
//\r
- BdsLibBuildOptionFromVar (&DriverOptionList, L"DriverOrder");\r
- if (!IsListEmpty (&DriverOptionList)) {\r
- BdsLibLoadDrivers (&DriverOptionList);\r
+ FilePath = FileDevicePath (NULL, EFI_REMOVABLE_MEDIA_FILE_NAME);\r
+ Status = EfiBootManagerInitializeLoadOption (\r
+ &LoadOption,\r
+ LoadOptionNumberUnassigned,\r
+ LoadOptionTypePlatformRecovery,\r
+ LOAD_OPTION_ACTIVE,\r
+ L"Default PlatformRecovery",\r
+ FilePath,\r
+ NULL,\r
+ 0\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypePlatformRecovery);\r
+ if (EfiBootManagerFindLoadOption (&LoadOption, LoadOptions, LoadOptionCount) == -1) {\r
+ for (Index = 0; Index < LoadOptionCount; Index++) {\r
+ //\r
+ // The PlatformRecovery#### options are sorted by OptionNumber.\r
+ // Find the the smallest unused number as the new OptionNumber.\r
+ //\r
+ if (LoadOptions[Index].OptionNumber != Index) {\r
+ break;\r
+ }\r
+ }\r
+ LoadOption.OptionNumber = Index;\r
+ Status = EfiBootManagerLoadOptionToVariable (&LoadOption);\r
+ ASSERT_EFI_ERROR (Status);\r
}\r
+ EfiBootManagerFreeLoadOption (&LoadOption);\r
+ FreePool (FilePath);\r
+ EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
+\r
//\r
- // Check if we have the boot next option\r
+ // Report Status Code to indicate connecting drivers will happen\r
//\r
- mBootNext = BdsLibGetVariableAndSize (\r
- L"BootNext",\r
- &gEfiGlobalVariableGuid,\r
- &BootNextSize\r
- );\r
+ REPORT_STATUS_CODE (\r
+ EFI_PROGRESS_CODE,\r
+ (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_BEGIN_CONNECTING_DRIVERS)\r
+ );\r
\r
//\r
- // Setup some platform policy here\r
+ // Initialize ConnectConIn event before calling platform code.\r
//\r
- PlatformBdsPolicyBehavior (PrivateData, &DriverOptionList, &BootOptionList);\r
- PERF_END (0, "PlatformBds", "BDS", 0);\r
+ if (PcdGetBool (PcdConInConnectOnDemand)) {\r
+ Status = gBS->CreateEventEx (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ BdsDxeOnConnectConInCallBack,\r
+ NULL,\r
+ &gConnectConInEventGuid,\r
+ &gConnectConInEvent\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ gConnectConInEvent = NULL;\r
+ }\r
+ }\r
\r
//\r
- // BDS select the boot device to load OS\r
+ // Do the platform init, can be customized by OEM/IBV\r
+ // Possible things that can be done in PlatformBootManagerBeforeConsole:\r
+ // > Update console variable: 1. include hot-plug devices; 2. Clear ConIn and add SOL for AMT\r
+ // > Register new Driver#### or Boot####\r
+ // > Register new Key####: e.g.: F12\r
+ // > Signal ReadyToLock event\r
+ // > Authentication action: 1. connect Auth devices; 2. Identify auto logon user.\r
//\r
- BdsBootDeviceSelect ();\r
+ PERF_INMODULE_BEGIN("PlatformBootManagerBeforeConsole");\r
+ PlatformBootManagerBeforeConsole ();\r
+ PERF_INMODULE_END("PlatformBootManagerBeforeConsole");\r
\r
//\r
- // Only assert here since this is the right behavior, we should never\r
- // return back to DxeCore.\r
+ // Initialize hotkey service\r
+ //\r
+ EfiBootManagerStartHotkeyService (&HotkeyTriggered);\r
+\r
+ //\r
+ // Execute Driver Options\r
+ //\r
+ LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeDriver);\r
+ ProcessLoadOptions (LoadOptions, LoadOptionCount);\r
+ EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
+\r
//\r
- ASSERT (FALSE);\r
+ // Connect consoles\r
+ //\r
+ PERF_INMODULE_BEGIN("EfiBootManagerConnectAllDefaultConsoles");\r
+ if (PcdGetBool (PcdConInConnectOnDemand)) {\r
+ EfiBootManagerConnectConsoleVariable (ConOut);\r
+ EfiBootManagerConnectConsoleVariable (ErrOut);\r
+ //\r
+ // Do not connect ConIn devices when lazy ConIn feature is ON.\r
+ //\r
+ } else {\r
+ EfiBootManagerConnectAllDefaultConsoles ();\r
+ }\r
+ PERF_INMODULE_END("EfiBootManagerConnectAllDefaultConsoles");\r
\r
- return ;\r
+ //\r
+ // Do the platform specific action after the console is ready\r
+ // Possible things that can be done in PlatformBootManagerAfterConsole:\r
+ // > Console post action:\r
+ // > Dynamically switch output mode from 100x31 to 80x25 for certain senarino\r
+ // > Signal console ready platform customized event\r
+ // > Run diagnostics like memory testing\r
+ // > Connect certain devices\r
+ // > Dispatch aditional option roms\r
+ // > Special boot: e.g.: USB boot, enter UI\r
+ //\r
+ PERF_INMODULE_BEGIN("PlatformBootManagerAfterConsole");\r
+ PlatformBootManagerAfterConsole ();\r
+ PERF_INMODULE_END("PlatformBootManagerAfterConsole");\r
+\r
+ //\r
+ // If any component set PcdTestKeyUsed to TRUE because use of a test key\r
+ // was detected, then display a warning message on the debug log and the console\r
+ //\r
+ if (PcdGetBool (PcdTestKeyUsed)) {\r
+ DEBUG ((DEBUG_ERROR, "**********************************\n"));\r
+ DEBUG ((DEBUG_ERROR, "** WARNING: Test Key is used. **\n"));\r
+ DEBUG ((DEBUG_ERROR, "**********************************\n"));\r
+ Print (L"** WARNING: Test Key is used. **\n");\r
+ }\r
+\r
+ //\r
+ // Boot to Boot Manager Menu when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot\r
+ //\r
+ DataSize = sizeof (UINT64);\r
+ Status = gRT->GetVariable (\r
+ EFI_OS_INDICATIONS_VARIABLE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ NULL,\r
+ &DataSize,\r
+ &OsIndication\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ OsIndication = 0;\r
+ }\r
+\r
+ DEBUG_CODE (\r
+ EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType;\r
+ DEBUG ((EFI_D_INFO, "[Bds]OsIndication: %016x\n", OsIndication));\r
+ DEBUG ((EFI_D_INFO, "[Bds]=============Begin Load Options Dumping ...=============\n"));\r
+ for (LoadOptionType = 0; LoadOptionType < LoadOptionTypeMax; LoadOptionType++) {\r
+ DEBUG ((\r
+ EFI_D_INFO, " %s Options:\n",\r
+ mBdsLoadOptionName[LoadOptionType]\r
+ ));\r
+ LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionType);\r
+ for (Index = 0; Index < LoadOptionCount; Index++) {\r
+ DEBUG ((\r
+ EFI_D_INFO, " %s%04x: %s \t\t 0x%04x\n",\r
+ mBdsLoadOptionName[LoadOptionType],\r
+ LoadOptions[Index].OptionNumber,\r
+ LoadOptions[Index].Description,\r
+ LoadOptions[Index].Attributes\r
+ ));\r
+ }\r
+ EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
+ }\r
+ DEBUG ((EFI_D_INFO, "[Bds]=============End Load Options Dumping=============\n"));\r
+ );\r
+\r
+ //\r
+ // BootManagerMenu doesn't contain the correct information when return status is EFI_NOT_FOUND.\r
+ //\r
+ BootManagerMenuStatus = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);\r
+\r
+ BootFwUi = (BOOLEAN) ((OsIndication & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) != 0);\r
+ PlatformRecovery = (BOOLEAN) ((OsIndication & EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY) != 0);\r
+ //\r
+ // Clear EFI_OS_INDICATIONS_BOOT_TO_FW_UI to acknowledge OS\r
+ //\r
+ if (BootFwUi || PlatformRecovery) {\r
+ OsIndication &= ~((UINT64) (EFI_OS_INDICATIONS_BOOT_TO_FW_UI | EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY));\r
+ Status = gRT->SetVariable (\r
+ EFI_OS_INDICATIONS_VARIABLE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+ sizeof(UINT64),\r
+ &OsIndication\r
+ );\r
+ //\r
+ // Changing the content without increasing its size with current variable implementation shouldn't fail.\r
+ //\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
+ //\r
+ // Launch Boot Manager Menu directly when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot\r
+ //\r
+ if (BootFwUi && (BootManagerMenuStatus != EFI_NOT_FOUND)) {\r
+ //\r
+ // Follow generic rule, Call BdsDxeOnConnectConInCallBack to connect ConIn before enter UI\r
+ //\r
+ if (PcdGetBool (PcdConInConnectOnDemand)) {\r
+ BdsDxeOnConnectConInCallBack (NULL, NULL);\r
+ }\r
+\r
+ //\r
+ // Directly enter the setup page.\r
+ //\r
+ EfiBootManagerBoot (&BootManagerMenu);\r
+ }\r
+\r
+ if (!PlatformRecovery) {\r
+ //\r
+ // Execute SysPrep####\r
+ //\r
+ LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeSysPrep);\r
+ ProcessLoadOptions (LoadOptions, LoadOptionCount);\r
+ EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
+\r
+ //\r
+ // Execute Key####\r
+ //\r
+ PERF_INMODULE_BEGIN ("BdsWait");\r
+ BdsWait (HotkeyTriggered);\r
+ PERF_INMODULE_END ("BdsWait");\r
+ //\r
+ // BdsReadKeys() can be removed after all keyboard drivers invoke callback in timer callback.\r
+ //\r
+ BdsReadKeys ();\r
+\r
+ EfiBootManagerHotkeyBoot ();\r
+\r
+ if (BootNext != NULL) {\r
+ //\r
+ // Delete "BootNext" NV variable before transferring control to it to prevent loops.\r
+ //\r
+ Status = gRT->SetVariable (\r
+ EFI_BOOT_NEXT_VARIABLE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ 0,\r
+ 0,\r
+ NULL\r
+ );\r
+ //\r
+ // Deleting NV variable shouldn't fail unless it doesn't exist.\r
+ //\r
+ ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);\r
+\r
+ //\r
+ // Boot to "BootNext"\r
+ //\r
+ UnicodeSPrint (BootNextVariableName, sizeof (BootNextVariableName), L"Boot%04x", *BootNext);\r
+ Status = EfiBootManagerVariableToLoadOption (BootNextVariableName, &LoadOption);\r
+ if (!EFI_ERROR (Status)) {\r
+ EfiBootManagerBoot (&LoadOption);\r
+ EfiBootManagerFreeLoadOption (&LoadOption);\r
+ if ((LoadOption.Status == EFI_SUCCESS) &&\r
+ (BootManagerMenuStatus != EFI_NOT_FOUND) &&\r
+ (LoadOption.OptionNumber != BootManagerMenu.OptionNumber)) {\r
+ //\r
+ // Boot to Boot Manager Menu upon EFI_SUCCESS\r
+ // Exception: Do not boot again when the BootNext points to Boot Manager Menu.\r
+ //\r
+ EfiBootManagerBoot (&BootManagerMenu);\r
+ }\r
+ }\r
+ }\r
+\r
+ do {\r
+ //\r
+ // Retry to boot if any of the boot succeeds\r
+ //\r
+ LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeBoot);\r
+ BootSuccess = BootBootOptions (LoadOptions, LoadOptionCount, (BootManagerMenuStatus != EFI_NOT_FOUND) ? &BootManagerMenu : NULL);\r
+ EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
+ } while (BootSuccess);\r
+ }\r
+\r
+ if (BootManagerMenuStatus != EFI_NOT_FOUND) {\r
+ EfiBootManagerFreeLoadOption (&BootManagerMenu);\r
+ }\r
+\r
+ if (!BootSuccess) {\r
+ LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypePlatformRecovery);\r
+ ProcessLoadOptions (LoadOptions, LoadOptionCount);\r
+ EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
+ }\r
+\r
+ DEBUG ((EFI_D_ERROR, "[Bds] Unable to boot!\n"));\r
+ PlatformBootManagerUnableToBoot ();\r
+ CpuDeadLoop ();\r
+}\r
+\r
+/**\r
+ Set the variable and report the error through status code upon failure.\r
+\r
+ @param VariableName A Null-terminated string that is the name of the vendor's variable.\r
+ Each VariableName is unique for each VendorGuid. VariableName must\r
+ contain 1 or more characters. If VariableName is an empty string,\r
+ then EFI_INVALID_PARAMETER is returned.\r
+ @param VendorGuid A unique identifier for the vendor.\r
+ @param Attributes Attributes bitmask to set for the variable.\r
+ @param DataSize The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE,\r
+ or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero\r
+ causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is\r
+ set, then a SetVariable() call with a DataSize of zero will not cause any change to\r
+ the variable value (the timestamp associated with the variable may be updated however\r
+ even if no new data value is provided,see the description of the\r
+ EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not\r
+ be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated).\r
+ @param Data The contents for the variable.\r
+\r
+ @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as\r
+ defined by the Attributes.\r
+ @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, and GUID was supplied, or the\r
+ DataSize exceeds the maximum allowed.\r
+ @retval EFI_INVALID_PARAMETER VariableName is an empty string.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.\r
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.\r
+ @retval EFI_WRITE_PROTECTED The variable in question is read-only.\r
+ @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.\r
+ @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS\r
+ being set, but the AuthInfo does NOT pass the validation check carried out by the firmware.\r
+\r
+ @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.\r
+**/\r
+EFI_STATUS\r
+BdsDxeSetVariableAndReportStatusCodeOnError (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid,\r
+ IN UINT32 Attributes,\r
+ IN UINTN DataSize,\r
+ IN VOID *Data\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EDKII_SET_VARIABLE_STATUS *SetVariableStatus;\r
+ UINTN NameSize;\r
+\r
+ Status = gRT->SetVariable (\r
+ VariableName,\r
+ VendorGuid,\r
+ Attributes,\r
+ DataSize,\r
+ Data\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ NameSize = StrSize (VariableName);\r
+ SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize);\r
+ if (SetVariableStatus != NULL) {\r
+ CopyGuid (&SetVariableStatus->Guid, VendorGuid);\r
+ SetVariableStatus->NameSize = NameSize;\r
+ SetVariableStatus->DataSize = DataSize;\r
+ SetVariableStatus->SetStatus = Status;\r
+ SetVariableStatus->Attributes = Attributes;\r
+ CopyMem (SetVariableStatus + 1, VariableName, NameSize);\r
+ CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Data, DataSize);\r
+\r
+ REPORT_STATUS_CODE_EX (\r
+ EFI_ERROR_CODE,\r
+ PcdGet32 (PcdErrorCodeSetVariable),\r
+ 0,\r
+ NULL,\r
+ &gEdkiiStatusCodeDataTypeVariableGuid,\r
+ SetVariableStatus,\r
+ sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize\r
+ );\r
+\r
+ FreePool (SetVariableStatus);\r
+ }\r
+ }\r
+\r
+ return Status;\r
}\r