After DxeCore finish DXE phase, gEfiBdsArchProtocolGuid->BdsEntry will be invoked\r
to enter BDS phase.\r
\r
-Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>\r
-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
CHAR16 *mBdsLoadOptionName[] = {\r
L"Driver",\r
L"SysPrep",\r
- L"Boot"\r
+ L"Boot",\r
+ L"PlatformRecovery"\r
};\r
\r
-CHAR16 mRecoveryBoot[] = L"Recovery Boot";\r
/**\r
Event to Connect ConIn.\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
ASSERT_EFI_ERROR (Status);\r
\r
- return Status;\r
-}\r
-\r
-/**\r
- Emuerate all possible bootable medias in the following order:\r
- 1. Removable BlockIo - The boot option only points to the removable media\r
- device, like USB key, DVD, Floppy etc.\r
- 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device,\r
- like HardDisk.\r
- 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting\r
- SimpleFileSystem Protocol, but not supporting BlockIo\r
- protocol.\r
- 4. LoadFile - The boot option points to the media supporting \r
- LoadFile protocol.\r
- Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior\r
-\r
- @param BootOptionCount Return the boot option count which has been found.\r
-\r
- @retval Pointer to the boot option array.\r
-**/\r
-EFI_BOOT_MANAGER_LOAD_OPTION *\r
-BdsEnumerateBootOptions (\r
- UINTN *BootOptionCount\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
- UINT16 NonBlockNumber;\r
- UINTN HandleCount;\r
- EFI_HANDLE *Handles;\r
- EFI_BLOCK_IO_PROTOCOL *BlkIo;\r
- UINTN Removable;\r
- UINTN Index;\r
-\r
- ASSERT (BootOptionCount != NULL);\r
-\r
- *BootOptionCount = 0;\r
- BootOptions = NULL;\r
-\r
- //\r
- // Parse removable block io followed by fixed block io\r
- //\r
- gBS->LocateHandleBuffer (\r
- ByProtocol,\r
- &gEfiBlockIoProtocolGuid,\r
- NULL,\r
- &HandleCount,\r
- &Handles\r
- );\r
-\r
- for (Removable = 0; Removable < 2; Removable++) {\r
- for (Index = 0; Index < HandleCount; Index++) {\r
- Status = gBS->HandleProtocol (\r
- Handles[Index],\r
- &gEfiBlockIoProtocolGuid,\r
- (VOID **) &BlkIo\r
- );\r
- if (EFI_ERROR (Status)) {\r
- continue;\r
- }\r
-\r
- //\r
- // Skip the logical partitions\r
- //\r
- if (BlkIo->Media->LogicalPartition) {\r
- continue;\r
- }\r
-\r
- //\r
- // Skip the fixed block io then the removable block io\r
- //\r
- if (BlkIo->Media->RemovableMedia == ((Removable == 0) ? FALSE : TRUE)) {\r
- continue;\r
- }\r
-\r
- BootOptions = ReallocatePool (\r
- sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),\r
- sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),\r
- BootOptions\r
- );\r
- ASSERT (BootOptions != NULL);\r
-\r
- Status = EfiBootManagerInitializeLoadOption (\r
- &BootOptions[(*BootOptionCount)++],\r
- LoadOptionNumberUnassigned,\r
- LoadOptionTypeBoot,\r
- LOAD_OPTION_ACTIVE,\r
- mRecoveryBoot,\r
- DevicePathFromHandle (Handles[Index]),\r
- NULL,\r
- 0\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
- }\r
- }\r
-\r
- if (HandleCount != 0) {\r
- FreePool (Handles);\r
- }\r
-\r
- //\r
- // Parse simple file system not based on block io\r
- //\r
- NonBlockNumber = 0;\r
- gBS->LocateHandleBuffer (\r
- ByProtocol,\r
- &gEfiSimpleFileSystemProtocolGuid,\r
- NULL,\r
- &HandleCount,\r
- &Handles\r
- );\r
- for (Index = 0; Index < HandleCount; Index++) {\r
- Status = gBS->HandleProtocol (\r
- Handles[Index],\r
- &gEfiBlockIoProtocolGuid,\r
- (VOID **) &BlkIo\r
- );\r
- if (!EFI_ERROR (Status)) {\r
- //\r
- // Skip if the file system handle supports a BlkIo protocol, which we've handled in above\r
- //\r
- continue;\r
- }\r
- BootOptions = ReallocatePool (\r
- sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),\r
- sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),\r
- BootOptions\r
- );\r
- ASSERT (BootOptions != NULL);\r
-\r
- Status = EfiBootManagerInitializeLoadOption (\r
- &BootOptions[(*BootOptionCount)++],\r
- LoadOptionNumberUnassigned,\r
- LoadOptionTypeBoot,\r
- LOAD_OPTION_ACTIVE,\r
- mRecoveryBoot,\r
- DevicePathFromHandle (Handles[Index]),\r
- NULL,\r
- 0\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
- }\r
-\r
- if (HandleCount != 0) {\r
- FreePool (Handles);\r
- }\r
-\r
- //\r
- // Parse load file, assuming UEFI Network boot option\r
- //\r
- gBS->LocateHandleBuffer (\r
- ByProtocol,\r
- &gEfiLoadFileProtocolGuid,\r
- NULL,\r
- &HandleCount,\r
- &Handles\r
- );\r
- for (Index = 0; Index < HandleCount; Index++) {\r
-\r
- BootOptions = ReallocatePool (\r
- sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),\r
- sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),\r
- BootOptions\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 (BootOptions != NULL);\r
-\r
- Status = EfiBootManagerInitializeLoadOption (\r
- &BootOptions[(*BootOptionCount)++],\r
- LoadOptionNumberUnassigned,\r
- LoadOptionTypeBoot,\r
- LOAD_OPTION_ACTIVE,\r
- mRecoveryBoot,\r
- DevicePathFromHandle (Handles[Index]),\r
- NULL,\r
- 0\r
- );\r
ASSERT_EFI_ERROR (Status);\r
- }\r
-\r
- if (HandleCount != 0) {\r
- FreePool (Handles);\r
- }\r
-\r
- return BootOptions;\r
+ );\r
+ return Status;\r
}\r
\r
/**\r
}\r
\r
while (gST->ConIn != NULL) {\r
- \r
+\r
Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
- \r
+\r
if (EFI_ERROR (Status)) {\r
//\r
// No more keys.\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
-BootAllBootOptions (\r
+BootBootOptions (\r
IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions,\r
- IN UINTN BootOptionCount\r
+ IN UINTN BootOptionCount,\r
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *BootManagerMenu OPTIONAL\r
)\r
{\r
UINTN Index;\r
\r
+ //\r
+ // Report Status Code to indicate BDS starts attempting booting from the UEFI BootOrder list.\r
+ //\r
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_ATTEMPT_BOOT_ORDER_EVENT));\r
+\r
//\r
// Attempt boot each boot option\r
//\r
EfiBootManagerBoot (&BootOptions[Index]);\r
\r
//\r
- // Successful boot breaks the loop, otherwise tries next boot option\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 (BootOptions[Index].Status == EFI_SUCCESS) {\r
+ if ((BootManagerMenu != NULL) && (BootOptions[Index].Status == EFI_SUCCESS)) {\r
+ EfiBootManagerBoot (BootManagerMenu);\r
break;\r
}\r
}\r
}\r
\r
/**\r
- This function attempts to boot per the boot order specified by platform policy.\r
-\r
- If the boot via Boot#### returns with a status of EFI_SUCCESS the boot manager will stop \r
- processing the BootOrder variable and present a boot manager menu to the user. If a boot via \r
- Boot#### returns a status other than EFI_SUCCESS, the boot has failed and the next Boot####\r
- in the BootOrder variable will be tried until all possibilities are exhausted.\r
- -- Chapter 3.1.1 Boot Manager Programming, the 4th paragraph\r
-**/\r
-VOID\r
-DefaultBootBehavior (\r
- VOID\r
- )\r
-{\r
- UINTN BootOptionCount;\r
- EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
- EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;\r
-\r
- EfiBootManagerGetBootManagerMenu (&BootManagerMenu);\r
- //\r
- // BootManagerMenu always contains the correct information even the above function returns failure.\r
- //\r
-\r
- BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);\r
-\r
- if (BootAllBootOptions (BootOptions, BootOptionCount)) {\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
- // Show the Boot Manager Menu after successful boot\r
- //\r
- EfiBootManagerBoot (&BootManagerMenu);\r
- } else {\r
- EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
- //\r
- // Re-scan all EFI boot options in case all the boot#### are deleted or failed to boot\r
- //\r
- // If no valid boot options exist, the boot manager will enumerate all removable media\r
- // devices followed by all fixed media devices. The order within each group is undefined.\r
- // These new default boot options are not saved to non volatile storage.The boot manger\r
- // will then attempt toboot from each boot option.\r
- // -- Chapter 3.3 Boot Manager Programming, the 2nd paragraph\r
- //\r
- EfiBootManagerConnectAll ();\r
- BootOptions = BdsEnumerateBootOptions (&BootOptionCount);\r
-\r
- if (!BootAllBootOptions (BootOptions, BootOptionCount)) {\r
- DEBUG ((EFI_D_ERROR, "[Bds]No bootable device!\n"));\r
- EfiBootManagerBoot (&BootManagerMenu);\r
- }\r
- }\r
-\r
- EfiBootManagerFreeLoadOption (&BootManagerMenu);\r
- EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
-}\r
-\r
-/**\r
- The function will load and start every Driver####/SysPrep####.\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
**/\r
VOID\r
ProcessLoadOptions (\r
BOOLEAN ReconnectAll;\r
EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType;\r
\r
- ReconnectAll = FALSE;\r
+ ReconnectAll = FALSE;\r
LoadOptionType = LoadOptionTypeMax;\r
\r
//\r
//\r
// All the load options in the array should be of the same type.\r
//\r
- if (LoadOptionType == LoadOptionTypeMax) {\r
+ if (Index == 0) {\r
LoadOptionType = LoadOptions[Index].OptionType;\r
}\r
ASSERT (LoadOptionType == LoadOptions[Index].OptionType);\r
- ASSERT (LoadOptionType == LoadOptionTypeDriver || LoadOptionType == LoadOptionTypeSysPrep);\r
+ ASSERT (LoadOptionType != LoadOptionTypeBoot);\r
\r
Status = EfiBootManagerProcessLoadOption (&LoadOptions[Index]);\r
\r
- if (!EFI_ERROR (Status) && ((LoadOptions[Index].Attributes & LOAD_OPTION_FORCE_RECONNECT) != 0)) {\r
- ReconnectAll = TRUE;\r
+ //\r
+ // Status indicates whether the load option is loaded and executed\r
+ // LoadOptions[Index].Status is what the load option returns\r
+ //\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Stop processing if any PlatformRecovery#### returns success.\r
+ //\r
+ if ((LoadOptions[Index].Status == EFI_SUCCESS) &&\r
+ (LoadOptionType == LoadOptionTypePlatformRecovery)) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Only set ReconnectAll flag when the load option executes successfully.\r
+ //\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
/**\r
\r
- Validate input console variable data. \r
+ Validate input console variable data.\r
\r
If found the device path is not a valid device path, remove the variable.\r
- \r
+\r
@param VariableName Input console variable name.\r
\r
**/\r
EFI_STATUS Status;\r
\r
GetEfiGlobalVariable2 (VariableName, (VOID **) &DevicePath, &VariableSize);\r
- if ((DevicePath != NULL) && !IsDevicePathValid (DevicePath, VariableSize)) { \r
+ if ((DevicePath != NULL) && !IsDevicePathValid (DevicePath, VariableSize)) {\r
Status = gRT->SetVariable (\r
VariableName,\r
&gEfiGlobalVariableGuid,\r
}\r
\r
/**\r
- Formalize OsIndication related variables. \r
- \r
- For OsIndicationsSupported, Create a BS/RT/UINT64 variable to report caps \r
+ Formalize OsIndication related variables.\r
+\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
Item 3 is used to solve case when OS corrupts OsIndications. Here simply delete this NV variable.\r
\r
+ Create a boot option for BootManagerMenu if it hasn't been created yet\r
+\r
**/\r
-VOID \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_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
- OsIndicationSupport = EFI_OS_INDICATIONS_BOOT_TO_FW_UI;\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
- L"OsIndicationsSupported",\r
+ EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME,\r
&gEfiGlobalVariableGuid,\r
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
sizeof(UINT64),\r
Attributes = 0;\r
DataSize = sizeof(UINT64);\r
Status = gRT->GetVariable (\r
- L"OsIndications",\r
+ EFI_OS_INDICATIONS_VARIABLE_NAME,\r
&gEfiGlobalVariableGuid,\r
&Attributes,\r
&DataSize,\r
\r
DEBUG ((EFI_D_ERROR, "[Bds] Unformalized OsIndications variable exists. Delete it\n"));\r
Status = gRT->SetVariable (\r
- L"OsIndications",\r
+ EFI_OS_INDICATIONS_VARIABLE_NAME,\r
&gEfiGlobalVariableGuid,\r
0,\r
0,\r
\r
/**\r
\r
- Validate variables. \r
+ Validate variables.\r
\r
**/\r
-VOID \r
+VOID\r
BdsFormalizeEfiGlobalVariable (\r
VOID\r
)\r
//\r
// Validate Console variable.\r
//\r
- BdsFormalizeConsoleVariable (L"ConIn");\r
- BdsFormalizeConsoleVariable (L"ConOut");\r
- BdsFormalizeConsoleVariable (L"ErrOut");\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
BdsFormalizeOSIndicationVariable ();\r
}\r
\r
-/**\r
-\r
- Allocate a block of memory that will contain performance data to OS.\r
-\r
-**/\r
-VOID\r
-BdsAllocateMemoryForPerformanceData (\r
- VOID\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_PHYSICAL_ADDRESS AcpiLowMemoryBase;\r
- EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;\r
-\r
- AcpiLowMemoryBase = 0x0FFFFFFFFULL;\r
-\r
- //\r
- // Allocate a block of memory that will contain performance data to OS.\r
- //\r
- Status = gBS->AllocatePages (\r
- AllocateMaxAddress,\r
- EfiReservedMemoryType,\r
- EFI_SIZE_TO_PAGES (PERF_DATA_MAX_LENGTH),\r
- &AcpiLowMemoryBase\r
- );\r
- if (!EFI_ERROR (Status)) {\r
- //\r
- // Save the pointer to variable for use in S3 resume.\r
- //\r
- Status = BdsDxeSetVariableAndReportStatusCodeOnError (\r
- L"PerfDataMemAddr",\r
- &gPerformanceProtocolGuid,\r
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
- sizeof (EFI_PHYSICAL_ADDRESS),\r
- &AcpiLowMemoryBase\r
- );\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((EFI_D_ERROR, "[Bds] PerfDataMemAddr (%08x) cannot be saved to NV storage.\n", AcpiLowMemoryBase));\r
- }\r
- //\r
- // Mark L"PerfDataMemAddr" variable to read-only if the Variable Lock protocol exists\r
- // Still lock it even the variable cannot be saved to prevent it's set by 3rd party code.\r
- //\r
- Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);\r
- if (!EFI_ERROR (Status)) {\r
- Status = VariableLock->RequestToLock (VariableLock, L"PerfDataMemAddr", &gPerformanceProtocolGuid);\r
- ASSERT_EFI_ERROR (Status);\r
- }\r
- }\r
-}\r
-\r
/**\r
\r
Service routine for BdsInstance->Entry(). Devices are connected, the\r
UINT16 BootTimeOut;\r
EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;\r
UINTN Index;\r
- EFI_BOOT_MANAGER_LOAD_OPTION BootOption;\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 (NULL, "DXE", NULL, 0);\r
- PERF_START (NULL, "BDS", NULL, 0);\r
+ PERF_CROSSMODULE_END("DXE");\r
+ PERF_CROSSMODULE_BEGIN("BDS");\r
DEBUG ((EFI_D_INFO, "[Bds] Entry...\n"));\r
\r
- PERF_CODE (\r
- BdsAllocateMemoryForPerformanceData ();\r
- );\r
-\r
//\r
// Fill in FirmwareVendor and FirmwareRevision from PCDs\r
//\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 < sizeof (mReadOnlyVariables) / sizeof (mReadOnlyVariables[0]); Index++) {\r
+ for (Index = 0; Index < ARRAY_SIZE (mReadOnlyVariables); Index++) {\r
Status = VariableLock->RequestToLock (VariableLock, mReadOnlyVariables[Index], &gEfiGlobalVariableGuid);\r
ASSERT_EFI_ERROR (Status);\r
}\r
ASSERT_EFI_ERROR (Status);\r
\r
//\r
- // Cache and remove the "BootNext" NV variable.\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
}\r
BootNext = NULL;\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
// Initialize the platform language variables\r
//\r
InitializeLanguage (TRUE);\r
\r
+ //\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
+ 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
// Report Status Code to indicate connecting drivers will happen\r
//\r
(EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_BEGIN_CONNECTING_DRIVERS)\r
);\r
\r
+ //\r
+ // Initialize ConnectConIn event before calling platform code.\r
+ //\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
// 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
+ // > Register new Key####: e.g.: F12\r
// > Signal ReadyToLock event\r
// > Authentication action: 1. connect Auth devices; 2. Identify auto logon user.\r
//\r
- PERF_START (NULL, "PlatformBootManagerBeforeConsole", "BDS", 0);\r
+ PERF_INMODULE_BEGIN("PlatformBootManagerBeforeConsole");\r
PlatformBootManagerBeforeConsole ();\r
- PERF_END (NULL, "PlatformBootManagerBeforeConsole", "BDS", 0);\r
+ PERF_INMODULE_END("PlatformBootManagerBeforeConsole");\r
\r
//\r
// Initialize hotkey service\r
//\r
// Connect consoles\r
//\r
- PERF_START (NULL, "EfiBootManagerConnectAllDefaultConsoles", "BDS", 0);\r
+ PERF_INMODULE_BEGIN("EfiBootManagerConnectAllDefaultConsoles");\r
if (PcdGetBool (PcdConInConnectOnDemand)) {\r
EfiBootManagerConnectConsoleVariable (ConOut);\r
EfiBootManagerConnectConsoleVariable (ErrOut);\r
-\r
//\r
- // Initialize ConnectConIn event\r
+ // Do not connect ConIn devices when lazy ConIn feature is ON.\r
//\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
} else {\r
EfiBootManagerConnectAllDefaultConsoles ();\r
}\r
- PERF_END (NULL, "EfiBootManagerConnectAllDefaultConsoles", "BDS", 0);\r
+ PERF_INMODULE_END("EfiBootManagerConnectAllDefaultConsoles");\r
\r
//\r
// Do the platform specific action after the console is ready\r
// > Connect certain devices\r
// > Dispatch aditional option roms\r
// > Special boot: e.g.: USB boot, enter UI\r
- // \r
- PERF_START (NULL, "PlatformBootManagerAfterConsole", "BDS", 0);\r
+ //\r
+ PERF_INMODULE_BEGIN("PlatformBootManagerAfterConsole");\r
PlatformBootManagerAfterConsole ();\r
- PERF_END (NULL, "PlatformBootManagerAfterConsole", "BDS", 0);\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
);\r
\r
//\r
- // Boot to Boot Manager Menu when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot\r
+ // BootManagerMenu doesn't contain the correct information when return status is EFI_NOT_FOUND.\r
//\r
- DataSize = sizeof (UINT64);\r
- Status = gRT->GetVariable (\r
- L"OsIndications",\r
- &gEfiGlobalVariableGuid,\r
- NULL,\r
- &DataSize,\r
- &OsIndication\r
- );\r
- if (EFI_ERROR (Status)) {\r
- OsIndication = 0;\r
- }\r
+ BootManagerMenuStatus = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);\r
\r
- BootFwUi = (BOOLEAN) ((OsIndication & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) != 0);\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) {\r
- OsIndication &= ~((UINT64) EFI_OS_INDICATIONS_BOOT_TO_FW_UI);\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
- L"OsIndications",\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
//\r
// Launch Boot Manager Menu directly when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot\r
//\r
- if (BootFwUi) {\r
+ if (BootFwUi && (BootManagerMenuStatus != EFI_NOT_FOUND)) {\r
//\r
// Follow generic rule, Call BdsDxeOnConnectConInCallBack to connect ConIn before enter UI\r
//\r
\r
//\r
// Directly enter the setup page.\r
- // BootManagerMenu always contains the correct information even call fails.\r
//\r
- EfiBootManagerGetBootManagerMenu (&BootManagerMenu);\r
EfiBootManagerBoot (&BootManagerMenu);\r
- EfiBootManagerFreeLoadOption (&BootManagerMenu);\r
}\r
\r
- //\r
- // Execute SysPrep####\r
- //\r
- LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeSysPrep);\r
- ProcessLoadOptions (LoadOptions, LoadOptionCount);\r
- EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\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_START (NULL, "BdsWait", "BDS", 0);\r
- BdsWait (HotkeyTriggered);\r
- PERF_END (NULL, "BdsWait", "BDS", 0);\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
- //\r
- // BdsReadKeys() be removed after all keyboard drivers invoke callback in timer callback.\r
- //\r
- BdsReadKeys ();\r
+ EfiBootManagerHotkeyBoot ();\r
\r
- EfiBootManagerHotkeyBoot ();\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
- if (BootNext != NULL) {\r
- UnicodeSPrint (BootNextVariableName, sizeof (BootNextVariableName), L"Boot%04x", *BootNext);\r
- Status = EfiBootManagerVariableToLoadOption (BootNextVariableName, &BootOption);\r
- if (!EFI_ERROR (Status)) {\r
- EfiBootManagerBoot (&BootOption);\r
- EfiBootManagerFreeLoadOption (&BootOption);\r
- if (BootOption.Status == EFI_SUCCESS) {\r
- //\r
- // Boot to Boot Manager Menu upon EFI_SUCCESS\r
- //\r
- EfiBootManagerGetBootManagerMenu (&BootOption);\r
- EfiBootManagerBoot (&BootOption);\r
- EfiBootManagerFreeLoadOption (&BootOption);\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
- while (TRUE) {\r
- //\r
- // BDS select the boot device to load OS\r
- // Try next upon boot failure\r
- // Show Boot Manager Menu upon boot success\r
- //\r
- DefaultBootBehavior ();\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
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
- EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or \r
- 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 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
@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_AUTHENTICATED_WRITE_ACCESS \r
- or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo \r
- does NOT pass the validation check carried out by the firmware.\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