]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/BdsDxe/BdsEntry.c
MdeModulePkg/Variable: Make only EFI_VARIABLE_NON_VOLATILE invalid
[mirror_edk2.git] / MdeModulePkg / Universal / BdsDxe / BdsEntry.c
index 3734ff954da292d000ad1020a72baf39d2b80485..766dde3aaeeb564dba1a1b8f3fdde6098d28699e 100644 (file)
@@ -5,23 +5,19 @@
   After DxeCore finish DXE phase, gEfiBdsArchProtocolGuid->BdsEntry will be invoked\r
   to enter BDS phase.\r
 \r
+Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.<BR>\r
+(C) Copyright 2016-2019 Hewlett Packard Enterprise Development LP<BR>\r
 (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>\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
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
 #include "Bds.h"\r
 #include "Language.h"\r
 #include "HwErrRecSupport.h"\r
+#include <Library/VariablePolicyHelperLib.h>\r
 \r
-#define SET_BOOT_OPTION_SUPPORT_KEY_COUNT(a, c)  \\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
@@ -35,7 +31,7 @@ EFI_BDS_ARCH_PROTOCOL  gBds = {
 //\r
 // gConnectConInEvent - Event which is signaled when ConIn connection is required\r
 //\r
-EFI_EVENT      gConnectConInEvent = NULL;\r
+EFI_EVENT  gConnectConInEvent = NULL;\r
 \r
 ///\r
 /// The read-only variables defined in UEFI Spec.\r
@@ -46,9 +42,9 @@ CHAR16  *mReadOnlyVariables[] = {
   EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME,\r
   EFI_HW_ERR_REC_SUPPORT_VARIABLE_NAME,\r
   EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME\r
-  };\r
+};\r
 \r
-CHAR16 *mBdsLoadOptionName[] = {\r
+CHAR16  *mBdsLoadOptionName[] = {\r
   L"Driver",\r
   L"SysPrep",\r
   L"Boot",\r
@@ -66,11 +62,11 @@ CHAR16 *mBdsLoadOptionName[] = {
 VOID\r
 EFIAPI\r
 BdsDxeOnConnectConInCallBack (\r
-  IN EFI_EVENT                Event,\r
-  IN VOID                     *Context\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
   )\r
 {\r
-  EFI_STATUS Status;\r
+  EFI_STATUS  Status;\r
 \r
   //\r
   // When Osloader call ReadKeyStroke to signal this event\r
@@ -82,7 +78,85 @@ BdsDxeOnConnectConInCallBack (
     // 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
+    DEBUG ((DEBUG_WARN, "[Bds] Connect ConIn failed - %r!!!\n", Status));\r
+  }\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
+\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
+\r
+  if (Handles != NULL) {\r
+    FreePool (Handles);\r
   }\r
 }\r
 \r
@@ -101,23 +175,40 @@ BdsDxeOnConnectConInCallBack (
 EFI_STATUS\r
 EFIAPI\r
 BdsInitialize (\r
-  IN EFI_HANDLE                            ImageHandle,\r
-  IN EFI_SYSTEM_TABLE                      *SystemTable\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
   )\r
 {\r
   EFI_STATUS  Status;\r
   EFI_HANDLE  Handle;\r
+\r
   //\r
   // Install protocol interface\r
   //\r
   Handle = NULL;\r
   Status = gBS->InstallMultipleProtocolInterfaces (\r
                   &Handle,\r
-                  &gEfiBdsArchProtocolGuid, &gBds,\r
+                  &gEfiBdsArchProtocolGuid,\r
+                  &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
@@ -133,8 +224,8 @@ BdsInitialize (
 **/\r
 EFI_STATUS\r
 BdsWaitForSingleEvent (\r
-  IN  EFI_EVENT                  Event,\r
-  IN  UINT64                     Timeout       OPTIONAL\r
+  IN  EFI_EVENT  Event,\r
+  IN  UINT64     Timeout       OPTIONAL\r
   )\r
 {\r
   UINTN       Index;\r
@@ -194,17 +285,16 @@ BdsReadKeys (
   VOID\r
   )\r
 {\r
-  EFI_STATUS         Status;\r
-  EFI_INPUT_KEY      Key;\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
+\r
     if (EFI_ERROR (Status)) {\r
       //\r
       // No more keys.\r
@@ -223,17 +313,17 @@ BdsReadKeys (
 **/\r
 VOID\r
 BdsWait (\r
-  IN EFI_EVENT      HotkeyTriggered\r
+  IN EFI_EVENT  HotkeyTriggered\r
   )\r
 {\r
-  EFI_STATUS            Status;\r
-  UINT16                TimeoutRemain;\r
+  EFI_STATUS  Status;\r
+  UINT16      TimeoutRemain;\r
 \r
-  DEBUG ((EFI_D_INFO, "[Bds]BdsWait ...Zzzzzzzzzzzz...\n"));\r
+  DEBUG ((DEBUG_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
+    DEBUG ((DEBUG_INFO, "[Bds]BdsWait(%d)..Zzzz...\n", (UINTN)TimeoutRemain));\r
     PlatformBootManagerWaitCallback (TimeoutRemain);\r
 \r
     BdsReadKeys (); // BUGBUG: Only reading can signal HotkeyTriggered\r
@@ -256,7 +346,19 @@ BdsWait (
       TimeoutRemain--;\r
     }\r
   }\r
-  DEBUG ((EFI_D_INFO, "[Bds]Exit the waiting!\n"));\r
+\r
+  //\r
+  // If the platform configured a nonzero and finite time-out, and we have\r
+  // actually reached that, report 100% completion to the platform.\r
+  //\r
+  // Note that the (TimeoutRemain == 0) condition excludes\r
+  // PcdPlatformBootTimeOut=0xFFFF, and that's deliberate.\r
+  //\r
+  if ((PcdGet16 (PcdPlatformBootTimeOut) != 0) && (TimeoutRemain == 0)) {\r
+    PlatformBootManagerWaitCallback (0);\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO, "[Bds]Exit the waiting!\n"));\r
 }\r
 \r
 /**\r
@@ -271,12 +373,17 @@ BdsWait (
 **/\r
 BOOLEAN\r
 BootBootOptions (\r
-  IN EFI_BOOT_MANAGER_LOAD_OPTION    *BootOptions,\r
-  IN UINTN                           BootOptionCount,\r
-  IN EFI_BOOT_MANAGER_LOAD_OPTION    *BootManagerMenu\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
+  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
@@ -312,13 +419,13 @@ BootBootOptions (
     // 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
-  return (BOOLEAN) (Index < BootOptionCount);\r
+  return (BOOLEAN)(Index < BootOptionCount);\r
 }\r
 \r
 /**\r
@@ -329,14 +436,14 @@ BootBootOptions (
 **/\r
 VOID\r
 ProcessLoadOptions (\r
-  IN EFI_BOOT_MANAGER_LOAD_OPTION       *LoadOptions,\r
-  IN UINTN                              LoadOptionCount\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
+  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
@@ -351,18 +458,32 @@ ProcessLoadOptions (
     if (Index == 0) {\r
       LoadOptionType = LoadOptions[Index].OptionType;\r
     }\r
+\r
     ASSERT (LoadOptionType == LoadOptions[Index].OptionType);\r
+    ASSERT (LoadOptionType != LoadOptionTypeBoot);\r
 \r
     Status = EfiBootManagerProcessLoadOption (&LoadOptions[Index]);\r
 \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
-      if (LoadOptionType == LoadOptionTypePlatformRecovery) {\r
-        //\r
-        // Stop processing if any entry is successful\r
-        //\r
+      //\r
+      // Stop processing if any PlatformRecovery#### returns success.\r
+      //\r
+      if ((LoadOptions[Index].Status == EFI_SUCCESS) &&\r
+          (LoadOptionType == LoadOptionTypePlatformRecovery))\r
+      {\r
         break;\r
       }\r
-      if ((LoadOptions[Index].Attributes & LOAD_OPTION_FORCE_RECONNECT) != 0) {\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
+      {\r
         ReconnectAll = TRUE;\r
       }\r
     }\r
@@ -373,7 +494,7 @@ ProcessLoadOptions (
   // 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
+  if (ReconnectAll && (LoadOptionType == LoadOptionTypeDriver)) {\r
     EfiBootManagerDisconnectAll ();\r
     EfiBootManagerConnectAll ();\r
   }\r
@@ -381,24 +502,24 @@ ProcessLoadOptions (
 \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
 VOID\r
 BdsFormalizeConsoleVariable (\r
-  IN  CHAR16          *VariableName\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
+  GetEfiGlobalVariable2 (VariableName, (VOID **)&DevicePath, &VariableSize);\r
+  if ((DevicePath != NULL) && !IsDevicePathValid (DevicePath, VariableSize)) {\r
     Status = gRT->SetVariable (\r
                     VariableName,\r
                     &gEfiGlobalVariableGuid,\r
@@ -418,34 +539,52 @@ BdsFormalizeConsoleVariable (
 }\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 | EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY;\r
+  Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);\r
+  if (Status != EFI_NOT_FOUND) {\r
+    OsIndicationSupport = EFI_OS_INDICATIONS_BOOT_TO_FW_UI;\r
+    EfiBootManagerFreeLoadOption (&BootManagerMenu);\r
+  } else {\r
+    OsIndicationSupport = 0;\r
+  }\r
+\r
+  if (PcdGetBool (PcdPlatformRecoverySupport)) {\r
+    OsIndicationSupport |= EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY;\r
+  }\r
+\r
+  if (PcdGetBool (PcdCapsuleOnDiskSupport)) {\r
+    OsIndicationSupport |= EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED;\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
+                  sizeof (UINT64),\r
                   &OsIndicationSupport\r
                   );\r
   //\r
@@ -461,15 +600,15 @@ BdsFormalizeOSIndicationVariable (
   //   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
+  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
@@ -477,9 +616,9 @@ BdsFormalizeOSIndicationVariable (
   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
+      )\r
+  {\r
+    DEBUG ((DEBUG_ERROR, "[Bds] Unformalized OsIndications variable exists. Delete it\n"));\r
     Status = gRT->SetVariable (\r
                     EFI_OS_INDICATIONS_VARIABLE_NAME,\r
                     &gEfiGlobalVariableGuid,\r
@@ -490,16 +629,16 @@ BdsFormalizeOSIndicationVariable (
     //\r
     // Deleting variable with current variable implementation shouldn't fail.\r
     //\r
-    ASSERT_EFI_ERROR(Status);\r
+    ASSERT_EFI_ERROR (Status);\r
   }\r
 }\r
 \r
 /**\r
 \r
-  Validate variables. \r
+  Validate variables.\r
 \r
 **/\r
-VOID \r
+VOID\r
 BdsFormalizeEfiGlobalVariable (\r
   VOID\r
   )\r
@@ -517,57 +656,6 @@ BdsFormalizeEfiGlobalVariable (
   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
@@ -591,7 +679,7 @@ BdsEntry (
   EFI_STATUS                      Status;\r
   UINT32                          BootOptionSupport;\r
   UINT16                          BootTimeOut;\r
-  EDKII_VARIABLE_LOCK_PROTOCOL    *VariableLock;\r
+  EDKII_VARIABLE_POLICY_PROTOCOL  *VariablePolicy;\r
   UINTN                           Index;\r
   EFI_BOOT_MANAGER_LOAD_OPTION    LoadOption;\r
   UINT16                          *BootNext;\r
@@ -601,6 +689,8 @@ BdsEntry (
   BOOLEAN                         PlatformRecovery;\r
   BOOLEAN                         BootSuccess;\r
   EFI_DEVICE_PATH_PROTOCOL        *FilePath;\r
+  EFI_STATUS                      BootManagerMenuStatus;\r
+  EFI_BOOT_MANAGER_LOAD_OPTION    PlatformDefaultBootOption;\r
 \r
   HotkeyTriggered = NULL;\r
   Status          = EFI_SUCCESS;\r
@@ -609,18 +699,14 @@ BdsEntry (
   //\r
   // Insert the performance probe\r
   //\r
-  PERF_END (NULL, "DXE", NULL, 0);\r
-  PERF_START (NULL, "BDS", NULL, 0);\r
-  DEBUG ((EFI_D_INFO, "[Bds] Entry...\n"));\r
-\r
-  PERF_CODE (\r
-    BdsAllocateMemoryForPerformanceData ();\r
-  );\r
+  PERF_CROSSMODULE_END ("DXE");\r
+  PERF_CROSSMODULE_BEGIN ("BDS");\r
+  DEBUG ((DEBUG_INFO, "[Bds] Entry...\n"));\r
 \r
   //\r
   // Fill in FirmwareVendor and FirmwareRevision from PCDs\r
   //\r
-  FirmwareVendor = (CHAR16 *) PcdGetPtr (PcdFirmwareVendor);\r
+  FirmwareVendor      = (CHAR16 *)PcdGetPtr (PcdFirmwareVendor);\r
   gST->FirmwareVendor = AllocateRuntimeCopyPool (StrSize (FirmwareVendor), FirmwareVendor);\r
   ASSERT (gST->FirmwareVendor != NULL);\r
   gST->FirmwareRevision = PcdGet32 (PcdFirmwareRevision);\r
@@ -629,7 +715,7 @@ BdsEntry (
   // Fixup Tasble CRC after we updated Firmware Vendor and Revision\r
   //\r
   gST->Hdr.CRC32 = 0;\r
-  gBS->CalculateCrc32 ((VOID *) gST, sizeof (EFI_SYSTEM_TABLE), &gST->Hdr.CRC32);\r
+  gBS->CalculateCrc32 ((VOID *)gST, sizeof (EFI_SYSTEM_TABLE), &gST->Hdr.CRC32);\r
 \r
   //\r
   // Validate Variable.\r
@@ -639,11 +725,20 @@ BdsEntry (
   //\r
   // Mark the read-only variables if the Variable Lock protocol exists\r
   //\r
-  Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);\r
-  DEBUG ((EFI_D_INFO, "[BdsDxe] Locate Variable Lock protocol - %r\n", Status));\r
+  Status = gBS->LocateProtocol (&gEdkiiVariablePolicyProtocolGuid, NULL, (VOID **)&VariablePolicy);\r
+  DEBUG ((DEBUG_INFO, "[BdsDxe] Locate Variable Policy protocol - %r\n", Status));\r
   if (!EFI_ERROR (Status)) {\r
-    for (Index = 0; Index < sizeof (mReadOnlyVariables) / sizeof (mReadOnlyVariables[0]); Index++) {\r
-      Status = VariableLock->RequestToLock (VariableLock, mReadOnlyVariables[Index], &gEfiGlobalVariableGuid);\r
+    for (Index = 0; Index < ARRAY_SIZE (mReadOnlyVariables); Index++) {\r
+      Status = RegisterBasicVariablePolicy (\r
+                 VariablePolicy,\r
+                 &gEfiGlobalVariableGuid,\r
+                 mReadOnlyVariables[Index],\r
+                 VARIABLE_POLICY_NO_MIN_SIZE,\r
+                 VARIABLE_POLICY_NO_MAX_SIZE,\r
+                 VARIABLE_POLICY_NO_MUST_ATTR,\r
+                 VARIABLE_POLICY_NO_CANT_ATTR,\r
+                 VARIABLE_POLICY_TYPE_LOCK_NOW\r
+                 );\r
       ASSERT_EFI_ERROR (Status);\r
     }\r
   }\r
@@ -677,6 +772,7 @@ BdsEntry (
     BootOptionSupport |= EFI_BOOT_OPTION_SUPPORT_KEY;\r
     SET_BOOT_OPTION_SUPPORT_KEY_COUNT (BootOptionSupport, 3);\r
   }\r
+\r
   Status = gRT->SetVariable (\r
                   EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME,\r
                   &gEfiGlobalVariableGuid,\r
@@ -690,41 +786,32 @@ BdsEntry (
   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
+  GetEfiGlobalVariable2 (EFI_BOOT_NEXT_VARIABLE_NAME, (VOID **)&BootNext, &DataSize);\r
   if (DataSize != sizeof (UINT16)) {\r
     if (BootNext != NULL) {\r
       FreePool (BootNext);\r
     }\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
+  if (FilePath == NULL) {\r
+    DEBUG ((DEBUG_ERROR, "Fail to allocate memory for default boot file path. Unable to boot.\n"));\r
+    CpuDeadLoop ();\r
+  }\r
+\r
   Status = EfiBootManagerInitializeLoadOption (\r
-             &LoadOption,\r
-             0,\r
+             &PlatformDefaultBootOption,\r
+             LoadOptionNumberUnassigned,\r
              LoadOptionTypePlatformRecovery,\r
              LOAD_OPTION_ACTIVE,\r
              L"Default PlatformRecovery",\r
@@ -733,8 +820,33 @@ BdsEntry (
              0\r
              );\r
   ASSERT_EFI_ERROR (Status);\r
-  EfiBootManagerLoadOptionToVariable (&LoadOption);\r
-  EfiBootManagerFreeLoadOption (&LoadOption);\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 if the platform supports Platform Recovery.\r
+  //\r
+  if (PcdGetBool (PcdPlatformRecoverySupport)) {\r
+    LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypePlatformRecovery);\r
+    if (EfiBootManagerFindLoadOption (&PlatformDefaultBootOption, 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
+\r
+      PlatformDefaultBootOption.OptionNumber = Index;\r
+      Status                                 = EfiBootManagerLoadOptionToVariable (&PlatformDefaultBootOption);\r
+      ASSERT_EFI_ERROR (Status);\r
+    }\r
+\r
+    EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
+  }\r
+\r
   FreePool (FilePath);\r
 \r
   //\r
@@ -745,18 +857,35 @@ BdsEntry (
     (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
@@ -773,29 +902,18 @@ BdsEntry (
   //\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
+\r
+  PERF_INMODULE_END ("EfiBootManagerConnectAllDefaultConsoles");\r
 \r
   //\r
   // Do the platform specific action after the console is ready\r
@@ -807,68 +925,85 @@ BdsEntry (
   // > 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
+  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_CODE_BEGIN ();\r
+  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE  LoadOptionType;\r
+\r
+  DEBUG ((DEBUG_INFO, "[Bds]OsIndication: %016x\n", OsIndication));\r
+  DEBUG ((DEBUG_INFO, "[Bds]=============Begin Load Options Dumping ...=============\n"));\r
+  for (LoadOptionType = 0; LoadOptionType < LoadOptionTypeMax; LoadOptionType++) {\r
+    DEBUG ((\r
+      DEBUG_INFO,\r
+      "  %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 Options:\n",\r
-        mBdsLoadOptionName[LoadOptionType]\r
+        DEBUG_INFO,\r
+        "    %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
-      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
+    EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO, "[Bds]=============End Load Options Dumping=============\n"));\r
+  DEBUG_CODE_END ();\r
 \r
   //\r
-  // BootManagerMenu always contains the correct information even call fails.\r
+  // BootManagerMenu doesn't contain the correct information when return status is EFI_NOT_FOUND.\r
   //\r
-  EfiBootManagerGetBootManagerMenu (&BootManagerMenu);\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
+  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
+  //\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
+    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
@@ -878,7 +1013,7 @@ BdsEntry (
   //\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
@@ -903,10 +1038,9 @@ BdsEntry (
     //\r
     // Execute Key####\r
     //\r
-    PERF_START (NULL, "BdsWait", "BDS", 0);\r
+    PERF_INMODULE_BEGIN ("BdsWait");\r
     BdsWait (HotkeyTriggered);\r
-    PERF_END   (NULL, "BdsWait", "BDS", 0);\r
-\r
+    PERF_INMODULE_END ("BdsWait");\r
     //\r
     // BdsReadKeys() can be removed after all keyboard drivers invoke callback in timer callback.\r
     //\r
@@ -914,18 +1048,37 @@ BdsEntry (
 \r
     EfiBootManagerHotkeyBoot ();\r
 \r
-    //\r
-    // Boot to "BootNext"\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
+        if ((LoadOption.Status == EFI_SUCCESS) &&\r
+            (BootManagerMenuStatus != EFI_NOT_FOUND) &&\r
+            (LoadOption.OptionNumber != BootManagerMenu.OptionNumber))\r
+        {\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
@@ -937,20 +1090,32 @@ BdsEntry (
       // Retry to boot if any of the boot succeeds\r
       //\r
       LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeBoot);\r
-      BootSuccess = BootBootOptions (LoadOptions, LoadOptionCount, &BootManagerMenu);\r
+      BootSuccess = BootBootOptions (LoadOptions, LoadOptionCount, (BootManagerMenuStatus != EFI_NOT_FOUND) ? &BootManagerMenu : NULL);\r
       EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
     } while (BootSuccess);\r
   }\r
 \r
-  EfiBootManagerFreeLoadOption (&BootManagerMenu);\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
+    if (PcdGetBool (PcdPlatformRecoverySupport)) {\r
+      LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypePlatformRecovery);\r
+      ProcessLoadOptions (LoadOptions, LoadOptionCount);\r
+      EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
+    } else {\r
+      //\r
+      // When platform recovery is not enabled, still boot to platform default file path.\r
+      //\r
+      EfiBootManagerProcessLoadOption (&PlatformDefaultBootOption);\r
+    }\r
   }\r
 \r
-  DEBUG ((EFI_D_ERROR, "[Bds] Unable to boot!\n"));\r
+  EfiBootManagerFreeLoadOption (&PlatformDefaultBootOption);\r
+\r
+  DEBUG ((DEBUG_ERROR, "[Bds] Unable to boot!\n"));\r
+  PlatformBootManagerUnableToBoot ();\r
   CpuDeadLoop ();\r
 }\r
 \r
@@ -963,15 +1128,14 @@ BdsEntry (
                                  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
@@ -983,19 +1147,18 @@ BdsEntry (
   @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
 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
+  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
@@ -1010,7 +1173,7 @@ BdsDxeSetVariableAndReportStatusCodeOnError (
                   Data\r
                   );\r
   if (EFI_ERROR (Status)) {\r
-    NameSize = StrSize (VariableName);\r
+    NameSize          = StrSize (VariableName);\r
     SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize);\r
     if (SetVariableStatus != NULL) {\r
       CopyGuid (&SetVariableStatus->Guid, VendorGuid);\r
@@ -1018,8 +1181,8 @@ BdsDxeSetVariableAndReportStatusCodeOnError (
       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
+      CopyMem (SetVariableStatus + 1, VariableName, NameSize);\r
+      CopyMem (((UINT8 *)(SetVariableStatus + 1)) + NameSize, Data, DataSize);\r
 \r
       REPORT_STATUS_CODE_EX (\r
         EFI_ERROR_CODE,\r