]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / ArmVirtPkg / Library / PlatformBootManagerLib / PlatformBm.c
index cc6d21e30007887a9747baae8f2468cd6a959504..3ad1ecd9d2862ab8c7bba45f8315b87a70e9bcf8 100644 (file)
@@ -3,64 +3,60 @@
 \r
   Copyright (C) 2015-2016, Red Hat, Inc.\r
   Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>\r
-  Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>\r
 \r
-  This program and the accompanying materials are licensed and made available\r
-  under the terms and conditions of the BSD License which accompanies this\r
-  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, WITHOUT\r
-  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
 #include <IndustryStandard/Pci22.h>\r
+#include <IndustryStandard/Virtio095.h>\r
+#include <Library/BootLogoLib.h>\r
 #include <Library/DevicePathLib.h>\r
 #include <Library/PcdLib.h>\r
+#include <Library/PlatformBmPrintScLib.h>\r
 #include <Library/QemuBootOrderLib.h>\r
+#include <Library/TpmPlatformHierarchyLib.h>\r
 #include <Library/UefiBootManagerLib.h>\r
 #include <Protocol/DevicePath.h>\r
+#include <Protocol/FirmwareVolume2.h>\r
 #include <Protocol/GraphicsOutput.h>\r
 #include <Protocol/LoadedImage.h>\r
 #include <Protocol/PciIo.h>\r
 #include <Protocol/PciRootBridgeIo.h>\r
+#include <Protocol/VirtioDevice.h>\r
 #include <Guid/EventGroup.h>\r
+#include <Guid/GlobalVariable.h>\r
 #include <Guid/RootBridgesConnectedEventGroup.h>\r
+#include <Guid/SerialPortLibVendor.h>\r
 \r
 #include "PlatformBm.h"\r
 \r
-#define DP_NODE_LEN(Type) { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) }\r
-\r
+#define DP_NODE_LEN(Type)  { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) }\r
 \r
 #pragma pack (1)\r
 typedef struct {\r
-  VENDOR_DEVICE_PATH         SerialDxe;\r
-  UART_DEVICE_PATH           Uart;\r
-  VENDOR_DEFINED_DEVICE_PATH TermType;\r
-  EFI_DEVICE_PATH_PROTOCOL   End;\r
+  VENDOR_DEVICE_PATH            SerialDxe;\r
+  UART_DEVICE_PATH              Uart;\r
+  VENDOR_DEFINED_DEVICE_PATH    TermType;\r
+  EFI_DEVICE_PATH_PROTOCOL      End;\r
 } PLATFORM_SERIAL_CONSOLE;\r
 #pragma pack ()\r
 \r
-#define SERIAL_DXE_FILE_GUID { \\r
-          0xD3987D4B, 0x971A, 0x435F, \\r
-          { 0x8C, 0xAF, 0x49, 0x67, 0xEB, 0x62, 0x72, 0x41 } \\r
-          }\r
-\r
-STATIC PLATFORM_SERIAL_CONSOLE mSerialConsole = {\r
+STATIC PLATFORM_SERIAL_CONSOLE  mSerialConsole = {\r
   //\r
   // VENDOR_DEVICE_PATH SerialDxe\r
   //\r
   {\r
-    { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, DP_NODE_LEN (VENDOR_DEVICE_PATH) },\r
-    SERIAL_DXE_FILE_GUID\r
+    { HARDWARE_DEVICE_PATH,  HW_VENDOR_DP, DP_NODE_LEN (VENDOR_DEVICE_PATH) },\r
+    EDKII_SERIAL_PORT_LIB_VENDOR_GUID\r
   },\r
 \r
   //\r
   // UART_DEVICE_PATH Uart\r
   //\r
   {\r
-    { MESSAGING_DEVICE_PATH, MSG_UART_DP, DP_NODE_LEN (UART_DEVICE_PATH) },\r
+    { MESSAGING_DEVICE_PATH, MSG_UART_DP,  DP_NODE_LEN (UART_DEVICE_PATH)   },\r
     0,                                      // Reserved\r
     FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate\r
     FixedPcdGet8 (PcdUartDefaultDataBits),  // DataBits\r
@@ -90,15 +86,14 @@ STATIC PLATFORM_SERIAL_CONSOLE mSerialConsole = {
   }\r
 };\r
 \r
-\r
 #pragma pack (1)\r
 typedef struct {\r
-  USB_CLASS_DEVICE_PATH    Keyboard;\r
-  EFI_DEVICE_PATH_PROTOCOL End;\r
+  USB_CLASS_DEVICE_PATH       Keyboard;\r
+  EFI_DEVICE_PATH_PROTOCOL    End;\r
 } PLATFORM_USB_KEYBOARD;\r
 #pragma pack ()\r
 \r
-STATIC PLATFORM_USB_KEYBOARD mUsbKeyboard = {\r
+STATIC PLATFORM_USB_KEYBOARD  mUsbKeyboard = {\r
   //\r
   // USB_CLASS_DEVICE_PATH Keyboard\r
   //\r
@@ -123,7 +118,6 @@ STATIC PLATFORM_USB_KEYBOARD mUsbKeyboard = {
   }\r
 };\r
 \r
-\r
 /**\r
   Check if the handle satisfies a particular condition.\r
 \r
@@ -137,12 +131,11 @@ STATIC PLATFORM_USB_KEYBOARD mUsbKeyboard = {
 **/\r
 typedef\r
 BOOLEAN\r
-(EFIAPI *FILTER_FUNCTION) (\r
+(EFIAPI *FILTER_FUNCTION)(\r
   IN EFI_HANDLE   Handle,\r
   IN CONST CHAR16 *ReportText\r
   );\r
 \r
-\r
 /**\r
   Process a handle.\r
 \r
@@ -152,7 +145,7 @@ BOOLEAN
 **/\r
 typedef\r
 VOID\r
-(EFIAPI *CALLBACK_FUNCTION)  (\r
+(EFIAPI *CALLBACK_FUNCTION)(\r
   IN EFI_HANDLE   Handle,\r
   IN CONST CHAR16 *ReportText\r
   );\r
@@ -173,31 +166,41 @@ VOID
 STATIC\r
 VOID\r
 FilterAndProcess (\r
-  IN EFI_GUID          *ProtocolGuid,\r
-  IN FILTER_FUNCTION   Filter         OPTIONAL,\r
-  IN CALLBACK_FUNCTION Process\r
+  IN EFI_GUID           *ProtocolGuid,\r
+  IN FILTER_FUNCTION    Filter         OPTIONAL,\r
+  IN CALLBACK_FUNCTION  Process\r
   )\r
 {\r
-  EFI_STATUS Status;\r
-  EFI_HANDLE *Handles;\r
-  UINTN      NoHandles;\r
-  UINTN      Idx;\r
-\r
-  Status = gBS->LocateHandleBuffer (ByProtocol, ProtocolGuid,\r
-                  NULL /* SearchKey */, &NoHandles, &Handles);\r
+  EFI_STATUS  Status;\r
+  EFI_HANDLE  *Handles;\r
+  UINTN       NoHandles;\r
+  UINTN       Idx;\r
+\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  ProtocolGuid,\r
+                  NULL /* SearchKey */,\r
+                  &NoHandles,\r
+                  &Handles\r
+                  );\r
   if (EFI_ERROR (Status)) {\r
     //\r
     // This is not an error, just an informative condition.\r
     //\r
-    DEBUG ((EFI_D_VERBOSE, "%a: %g: %r\n", __FUNCTION__, ProtocolGuid,\r
-      Status));\r
+    DEBUG ((\r
+      DEBUG_VERBOSE,\r
+      "%a: %g: %r\n",\r
+      __FUNCTION__,\r
+      ProtocolGuid,\r
+      Status\r
+      ));\r
     return;\r
   }\r
 \r
   ASSERT (NoHandles > 0);\r
   for (Idx = 0; Idx < NoHandles; ++Idx) {\r
-    CHAR16        *DevicePathText;\r
-    STATIC CHAR16 Fallback[] = L"<device path unavailable>";\r
+    CHAR16         *DevicePathText;\r
+    STATIC CHAR16  Fallback[] = L"<device path unavailable>";\r
 \r
     //\r
     // The ConvertDevicePathToText() function handles NULL input transparently.\r
@@ -211,7 +214,7 @@ FilterAndProcess (
       DevicePathText = Fallback;\r
     }\r
 \r
-    if (Filter == NULL || Filter (Handles[Idx], DevicePathText)) {\r
+    if ((Filter == NULL) || Filter (Handles[Idx], DevicePathText)) {\r
       Process (Handles[Idx], DevicePathText);\r
     }\r
 \r
@@ -219,10 +222,10 @@ FilterAndProcess (
       FreePool (DevicePathText);\r
     }\r
   }\r
+\r
   gBS->FreePool (Handles);\r
 }\r
 \r
-\r
 /**\r
   This FILTER_FUNCTION checks if a handle corresponds to a PCI display device.\r
 **/\r
@@ -230,16 +233,19 @@ STATIC
 BOOLEAN\r
 EFIAPI\r
 IsPciDisplay (\r
-  IN EFI_HANDLE   Handle,\r
-  IN CONST CHAR16 *ReportText\r
+  IN EFI_HANDLE    Handle,\r
+  IN CONST CHAR16  *ReportText\r
   )\r
 {\r
-  EFI_STATUS          Status;\r
-  EFI_PCI_IO_PROTOCOL *PciIo;\r
-  PCI_TYPE00          Pci;\r
+  EFI_STATUS           Status;\r
+  EFI_PCI_IO_PROTOCOL  *PciIo;\r
+  PCI_TYPE00           Pci;\r
 \r
-  Status = gBS->HandleProtocol (Handle, &gEfiPciIoProtocolGuid,\r
-                  (VOID**)&PciIo);\r
+  Status = gBS->HandleProtocol (\r
+                  Handle,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **)&PciIo\r
+                  );\r
   if (EFI_ERROR (Status)) {\r
     //\r
     // This is not an error worth reporting.\r
@@ -247,16 +253,166 @@ IsPciDisplay (
     return FALSE;\r
   }\r
 \r
-  Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0 /* Offset */,\r
-                        sizeof Pci / sizeof (UINT32), &Pci);\r
+  Status = PciIo->Pci.Read (\r
+                        PciIo,\r
+                        EfiPciIoWidthUint32,\r
+                        0 /* Offset */,\r
+                        sizeof Pci / sizeof (UINT32),\r
+                        &Pci\r
+                        );\r
   if (EFI_ERROR (Status)) {\r
-    DEBUG ((EFI_D_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status));\r
+    DEBUG ((DEBUG_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status));\r
     return FALSE;\r
   }\r
 \r
   return IS_PCI_DISPLAY (&Pci);\r
 }\r
 \r
+/**\r
+  This FILTER_FUNCTION checks if a handle corresponds to a Virtio RNG device at\r
+  the VIRTIO_DEVICE_PROTOCOL level.\r
+**/\r
+STATIC\r
+BOOLEAN\r
+EFIAPI\r
+IsVirtioRng (\r
+  IN EFI_HANDLE    Handle,\r
+  IN CONST CHAR16  *ReportText\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  VIRTIO_DEVICE_PROTOCOL  *VirtIo;\r
+\r
+  Status = gBS->HandleProtocol (\r
+                  Handle,\r
+                  &gVirtioDeviceProtocolGuid,\r
+                  (VOID **)&VirtIo\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return FALSE;\r
+  }\r
+\r
+  return (BOOLEAN)(VirtIo->SubSystemDeviceId ==\r
+                   VIRTIO_SUBSYSTEM_ENTROPY_SOURCE);\r
+}\r
+\r
+/**\r
+  This FILTER_FUNCTION checks if a handle corresponds to a Virtio RNG device at\r
+  the EFI_PCI_IO_PROTOCOL level.\r
+**/\r
+STATIC\r
+BOOLEAN\r
+EFIAPI\r
+IsVirtioPciRng (\r
+  IN EFI_HANDLE    Handle,\r
+  IN CONST CHAR16  *ReportText\r
+  )\r
+{\r
+  EFI_STATUS           Status;\r
+  EFI_PCI_IO_PROTOCOL  *PciIo;\r
+  UINT16               VendorId;\r
+  UINT16               DeviceId;\r
+  UINT8                RevisionId;\r
+  BOOLEAN              Virtio10;\r
+  UINT16               SubsystemId;\r
+\r
+  Status = gBS->HandleProtocol (\r
+                  Handle,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **)&PciIo\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Read and check VendorId.\r
+  //\r
+  Status = PciIo->Pci.Read (\r
+                        PciIo,\r
+                        EfiPciIoWidthUint16,\r
+                        PCI_VENDOR_ID_OFFSET,\r
+                        1,\r
+                        &VendorId\r
+                        );\r
+  if (EFI_ERROR (Status)) {\r
+    goto PciError;\r
+  }\r
+\r
+  if (VendorId != VIRTIO_VENDOR_ID) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Read DeviceId and RevisionId.\r
+  //\r
+  Status = PciIo->Pci.Read (\r
+                        PciIo,\r
+                        EfiPciIoWidthUint16,\r
+                        PCI_DEVICE_ID_OFFSET,\r
+                        1,\r
+                        &DeviceId\r
+                        );\r
+  if (EFI_ERROR (Status)) {\r
+    goto PciError;\r
+  }\r
+\r
+  Status = PciIo->Pci.Read (\r
+                        PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        PCI_REVISION_ID_OFFSET,\r
+                        1,\r
+                        &RevisionId\r
+                        );\r
+  if (EFI_ERROR (Status)) {\r
+    goto PciError;\r
+  }\r
+\r
+  //\r
+  // From DeviceId and RevisionId, determine whether the device is a\r
+  // modern-only Virtio 1.0 device. In case of Virtio 1.0, DeviceId can\r
+  // immediately be restricted to VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and\r
+  // SubsystemId will only play a sanity-check role. Otherwise, DeviceId can\r
+  // only be sanity-checked, and SubsystemId will decide.\r
+  //\r
+  if ((DeviceId == 0x1040 + VIRTIO_SUBSYSTEM_ENTROPY_SOURCE) &&\r
+      (RevisionId >= 0x01))\r
+  {\r
+    Virtio10 = TRUE;\r
+  } else if ((DeviceId >= 0x1000) && (DeviceId <= 0x103F) && (RevisionId == 0x00)) {\r
+    Virtio10 = FALSE;\r
+  } else {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Read and check SubsystemId as dictated by Virtio10.\r
+  //\r
+  Status = PciIo->Pci.Read (\r
+                        PciIo,\r
+                        EfiPciIoWidthUint16,\r
+                        PCI_SUBSYSTEM_ID_OFFSET,\r
+                        1,\r
+                        &SubsystemId\r
+                        );\r
+  if (EFI_ERROR (Status)) {\r
+    goto PciError;\r
+  }\r
+\r
+  if (Virtio10 && (SubsystemId >= 0x40)) {\r
+    return TRUE;\r
+  }\r
+\r
+  if (!Virtio10 && (SubsystemId == VIRTIO_SUBSYSTEM_ENTROPY_SOURCE)) {\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+\r
+PciError:\r
+  DEBUG ((DEBUG_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status));\r
+  return FALSE;\r
+}\r
 \r
 /**\r
   This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking\r
@@ -266,11 +422,11 @@ STATIC
 VOID\r
 EFIAPI\r
 Connect (\r
-  IN EFI_HANDLE   Handle,\r
-  IN CONST CHAR16 *ReportText\r
+  IN EFI_HANDLE    Handle,\r
+  IN CONST CHAR16  *ReportText\r
   )\r
 {\r
-  EFI_STATUS Status;\r
+  EFI_STATUS  Status;\r
 \r
   Status = gBS->ConnectController (\r
                   Handle, // ControllerHandle\r
@@ -278,11 +434,15 @@ Connect (
                   NULL,   // RemainingDevicePath -- produce all children\r
                   FALSE   // Recursive\r
                   );\r
-  DEBUG ((EFI_ERROR (Status) ? EFI_D_ERROR : EFI_D_VERBOSE, "%a: %s: %r\n",\r
-    __FUNCTION__, ReportText, Status));\r
+  DEBUG ((\r
+    EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE,\r
+    "%a: %s: %r\n",\r
+    __FUNCTION__,\r
+    ReportText,\r
+    Status\r
+    ));\r
 }\r
 \r
-\r
 /**\r
   This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the\r
   handle, and adds it to ConOut and ErrOut.\r
@@ -291,59 +451,78 @@ STATIC
 VOID\r
 EFIAPI\r
 AddOutput (\r
-  IN EFI_HANDLE   Handle,\r
-  IN CONST CHAR16 *ReportText\r
+  IN EFI_HANDLE    Handle,\r
+  IN CONST CHAR16  *ReportText\r
   )\r
 {\r
-  EFI_STATUS               Status;\r
-  EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+  EFI_STATUS                Status;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
 \r
   DevicePath = DevicePathFromHandle (Handle);\r
   if (DevicePath == NULL) {\r
-    DEBUG ((EFI_D_ERROR, "%a: %s: handle %p: device path not found\n",\r
-      __FUNCTION__, ReportText, Handle));\r
+    DEBUG ((\r
+      DEBUG_ERROR,\r
+      "%a: %s: handle %p: device path not found\n",\r
+      __FUNCTION__,\r
+      ReportText,\r
+      Handle\r
+      ));\r
     return;\r
   }\r
 \r
   Status = EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
   if (EFI_ERROR (Status)) {\r
-    DEBUG ((EFI_D_ERROR, "%a: %s: adding to ConOut: %r\n", __FUNCTION__,\r
-      ReportText, Status));\r
+    DEBUG ((\r
+      DEBUG_ERROR,\r
+      "%a: %s: adding to ConOut: %r\n",\r
+      __FUNCTION__,\r
+      ReportText,\r
+      Status\r
+      ));\r
     return;\r
   }\r
 \r
   Status = EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
   if (EFI_ERROR (Status)) {\r
-    DEBUG ((EFI_D_ERROR, "%a: %s: adding to ErrOut: %r\n", __FUNCTION__,\r
-      ReportText, Status));\r
+    DEBUG ((\r
+      DEBUG_ERROR,\r
+      "%a: %s: adding to ErrOut: %r\n",\r
+      __FUNCTION__,\r
+      ReportText,\r
+      Status\r
+      ));\r
     return;\r
   }\r
 \r
-  DEBUG ((EFI_D_VERBOSE, "%a: %s: added to ConOut and ErrOut\n", __FUNCTION__,\r
-    ReportText));\r
+  DEBUG ((\r
+    DEBUG_VERBOSE,\r
+    "%a: %s: added to ConOut and ErrOut\n",\r
+    __FUNCTION__,\r
+    ReportText\r
+    ));\r
 }\r
 \r
 STATIC\r
 VOID\r
 PlatformRegisterFvBootOption (\r
-  EFI_GUID                         *FileGuid,\r
-  CHAR16                           *Description,\r
-  UINT32                           Attributes\r
+  EFI_GUID  *FileGuid,\r
+  CHAR16    *Description,\r
+  UINT32    Attributes\r
   )\r
 {\r
-  EFI_STATUS                        Status;\r
-  INTN                              OptionIndex;\r
-  EFI_BOOT_MANAGER_LOAD_OPTION      NewOption;\r
-  EFI_BOOT_MANAGER_LOAD_OPTION      *BootOptions;\r
-  UINTN                             BootOptionCount;\r
-  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;\r
-  EFI_LOADED_IMAGE_PROTOCOL         *LoadedImage;\r
-  EFI_DEVICE_PATH_PROTOCOL          *DevicePath;\r
+  EFI_STATUS                         Status;\r
+  INTN                               OptionIndex;\r
+  EFI_BOOT_MANAGER_LOAD_OPTION       NewOption;\r
+  EFI_BOOT_MANAGER_LOAD_OPTION       *BootOptions;\r
+  UINTN                              BootOptionCount;\r
+  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH  FileNode;\r
+  EFI_LOADED_IMAGE_PROTOCOL          *LoadedImage;\r
+  EFI_DEVICE_PATH_PROTOCOL           *DevicePath;\r
 \r
   Status = gBS->HandleProtocol (\r
                   gImageHandle,\r
                   &gEfiLoadedImageProtocolGuid,\r
-                  (VOID **) &LoadedImage\r
+                  (VOID **)&LoadedImage\r
                   );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
@@ -352,7 +531,7 @@ PlatformRegisterFvBootOption (
   ASSERT (DevicePath != NULL);\r
   DevicePath = AppendDevicePathNode (\r
                  DevicePath,\r
-                 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode\r
+                 (EFI_DEVICE_PATH_PROTOCOL *)&FileNode\r
                  );\r
   ASSERT (DevicePath != NULL);\r
 \r
@@ -370,21 +549,169 @@ PlatformRegisterFvBootOption (
   FreePool (DevicePath);\r
 \r
   BootOptions = EfiBootManagerGetLoadOptions (\r
-                  &BootOptionCount, LoadOptionTypeBoot\r
+                  &BootOptionCount,\r
+                  LoadOptionTypeBoot\r
                   );\r
 \r
   OptionIndex = EfiBootManagerFindLoadOption (\r
-                  &NewOption, BootOptions, BootOptionCount\r
+                  &NewOption,\r
+                  BootOptions,\r
+                  BootOptionCount\r
                   );\r
 \r
   if (OptionIndex == -1) {\r
     Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);\r
     ASSERT_EFI_ERROR (Status);\r
   }\r
+\r
   EfiBootManagerFreeLoadOption (&NewOption);\r
   EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
 }\r
 \r
+/**\r
+  Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options\r
+  whose device paths do not resolve exactly to an FvFile in the system.\r
+\r
+  This removes any boot options that point to binaries built into the firmware\r
+  and have become stale due to any of the following:\r
+  - FvMain's base address or size changed (historical),\r
+  - FvMain's FvNameGuid changed,\r
+  - the FILE_GUID of the pointed-to binary changed,\r
+  - the referenced binary is no longer built into the firmware.\r
+\r
+  EfiBootManagerFindLoadOption() used in PlatformRegisterFvBootOption() only\r
+  avoids exact duplicates.\r
+**/\r
+STATIC\r
+VOID\r
+RemoveStaleFvFileOptions (\r
+  VOID\r
+  )\r
+{\r
+  EFI_BOOT_MANAGER_LOAD_OPTION  *BootOptions;\r
+  UINTN                         BootOptionCount;\r
+  UINTN                         Index;\r
+\r
+  BootOptions = EfiBootManagerGetLoadOptions (\r
+                  &BootOptionCount,\r
+                  LoadOptionTypeBoot\r
+                  );\r
+\r
+  for (Index = 0; Index < BootOptionCount; ++Index) {\r
+    EFI_DEVICE_PATH_PROTOCOL  *Node1, *Node2, *SearchNode;\r
+    EFI_STATUS                Status;\r
+    EFI_HANDLE                FvHandle;\r
+\r
+    //\r
+    // If the device path starts with neither MemoryMapped(...) nor Fv(...),\r
+    // then keep the boot option.\r
+    //\r
+    Node1 = BootOptions[Index].FilePath;\r
+    if (!((DevicePathType (Node1) == HARDWARE_DEVICE_PATH) &&\r
+          (DevicePathSubType (Node1) == HW_MEMMAP_DP)) &&\r
+        !((DevicePathType (Node1) == MEDIA_DEVICE_PATH) &&\r
+          (DevicePathSubType (Node1) == MEDIA_PIWG_FW_VOL_DP)))\r
+    {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // If the second device path node is not FvFile(...), then keep the boot\r
+    // option.\r
+    //\r
+    Node2 = NextDevicePathNode (Node1);\r
+    if ((DevicePathType (Node2) != MEDIA_DEVICE_PATH) ||\r
+        (DevicePathSubType (Node2) != MEDIA_PIWG_FW_FILE_DP))\r
+    {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Locate the Firmware Volume2 protocol instance that is denoted by the\r
+    // boot option. If this lookup fails (i.e., the boot option references a\r
+    // firmware volume that doesn't exist), then we'll proceed to delete the\r
+    // boot option.\r
+    //\r
+    SearchNode = Node1;\r
+    Status     = gBS->LocateDevicePath (\r
+                        &gEfiFirmwareVolume2ProtocolGuid,\r
+                        &SearchNode,\r
+                        &FvHandle\r
+                        );\r
+\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // The firmware volume was found; now let's see if it contains the FvFile\r
+      // identified by GUID.\r
+      //\r
+      EFI_FIRMWARE_VOLUME2_PROTOCOL      *FvProtocol;\r
+      MEDIA_FW_VOL_FILEPATH_DEVICE_PATH  *FvFileNode;\r
+      UINTN                              BufferSize;\r
+      EFI_FV_FILETYPE                    FoundType;\r
+      EFI_FV_FILE_ATTRIBUTES             FileAttributes;\r
+      UINT32                             AuthenticationStatus;\r
+\r
+      Status = gBS->HandleProtocol (\r
+                      FvHandle,\r
+                      &gEfiFirmwareVolume2ProtocolGuid,\r
+                      (VOID **)&FvProtocol\r
+                      );\r
+      ASSERT_EFI_ERROR (Status);\r
+\r
+      FvFileNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)Node2;\r
+      //\r
+      // Buffer==NULL means we request metadata only: BufferSize, FoundType,\r
+      // FileAttributes.\r
+      //\r
+      Status = FvProtocol->ReadFile (\r
+                             FvProtocol,\r
+                             &FvFileNode->FvFileName, // NameGuid\r
+                             NULL,                    // Buffer\r
+                             &BufferSize,\r
+                             &FoundType,\r
+                             &FileAttributes,\r
+                             &AuthenticationStatus\r
+                             );\r
+      if (!EFI_ERROR (Status)) {\r
+        //\r
+        // The FvFile was found. Keep the boot option.\r
+        //\r
+        continue;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Delete the boot option.\r
+    //\r
+    Status = EfiBootManagerDeleteLoadOptionVariable (\r
+               BootOptions[Index].OptionNumber,\r
+               LoadOptionTypeBoot\r
+               );\r
+    DEBUG_CODE_BEGIN ();\r
+    CHAR16  *DevicePathString;\r
+\r
+    DevicePathString = ConvertDevicePathToText (\r
+                         BootOptions[Index].FilePath,\r
+                         FALSE,\r
+                         FALSE\r
+                         );\r
+    DEBUG ((\r
+      EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_VERBOSE,\r
+      "%a: removing stale Boot#%04x %s: %r\n",\r
+      __FUNCTION__,\r
+      (UINT32)BootOptions[Index].OptionNumber,\r
+      DevicePathString == NULL ? L"<unavailable>" : DevicePathString,\r
+      Status\r
+      ));\r
+    if (DevicePathString != NULL) {\r
+      FreePool (DevicePathString);\r
+    }\r
+\r
+    DEBUG_CODE_END ();\r
+  }\r
+\r
+  EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
+}\r
 \r
 STATIC\r
 VOID\r
@@ -392,18 +719,18 @@ PlatformRegisterOptionsAndKeys (
   VOID\r
   )\r
 {\r
-  EFI_STATUS                   Status;\r
-  EFI_INPUT_KEY                Enter;\r
-  EFI_INPUT_KEY                F2;\r
-  EFI_INPUT_KEY                Esc;\r
-  EFI_BOOT_MANAGER_LOAD_OPTION BootOption;\r
+  EFI_STATUS                    Status;\r
+  EFI_INPUT_KEY                 Enter;\r
+  EFI_INPUT_KEY                 F2;\r
+  EFI_INPUT_KEY                 Esc;\r
+  EFI_BOOT_MANAGER_LOAD_OPTION  BootOption;\r
 \r
   //\r
   // Register ENTER as CONTINUE key\r
   //\r
   Enter.ScanCode    = SCAN_NULL;\r
   Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;\r
-  Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);\r
+  Status            = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);\r
   ASSERT_EFI_ERROR (Status);\r
 \r
   //\r
@@ -413,28 +740,30 @@ PlatformRegisterOptionsAndKeys (
   F2.UnicodeChar  = CHAR_NULL;\r
   Esc.ScanCode    = SCAN_ESC;\r
   Esc.UnicodeChar = CHAR_NULL;\r
-  Status = EfiBootManagerGetBootManagerMenu (&BootOption);\r
+  Status          = EfiBootManagerGetBootManagerMenu (&BootOption);\r
   ASSERT_EFI_ERROR (Status);\r
   Status = EfiBootManagerAddKeyOptionVariable (\r
-             NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL\r
+             NULL,\r
+             (UINT16)BootOption.OptionNumber,\r
+             0,\r
+             &F2,\r
+             NULL\r
              );\r
   ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);\r
   Status = EfiBootManagerAddKeyOptionVariable (\r
-             NULL, (UINT16) BootOption.OptionNumber, 0, &Esc, NULL\r
+             NULL,\r
+             (UINT16)BootOption.OptionNumber,\r
+             0,\r
+             &Esc,\r
+             NULL\r
              );\r
   ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);\r
-  //\r
-  // Register UEFI Shell\r
-  //\r
-  PlatformRegisterFvBootOption (\r
-    PcdGetPtr (PcdShellFile), L"EFI Internal Shell", LOAD_OPTION_ACTIVE\r
-    );\r
 }\r
 \r
-\r
 //\r
 // BDS Platform Functions\r
 //\r
+\r
 /**\r
   Do the platform init, can be customized by OEM/IBV\r
   Possible things that can be done in PlatformBootManagerBeforeConsole:\r
@@ -452,11 +781,25 @@ PlatformBootManagerBeforeConsole (
   VOID\r
   )\r
 {\r
+  UINT16         FrontPageTimeout;\r
+  RETURN_STATUS  PcdStatus;\r
+  EFI_STATUS     Status;\r
+\r
   //\r
   // Signal EndOfDxe PI Event\r
   //\r
   EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);\r
 \r
+  //\r
+  // Disable the TPM 2 platform hierarchy\r
+  //\r
+  ConfigureTpmPlatformHierarchy ();\r
+\r
+  //\r
+  // Dispatch deferred images after EndOfDxe event.\r
+  //\r
+  EfiBootManagerDispatchDeferredImages ();\r
+\r
   //\r
   // Locate the PCI root bridges and make the PCI bus driver connect each,\r
   // non-recursively. This will produce a number of child handles with PciIo on\r
@@ -485,41 +828,89 @@ PlatformBootManagerBeforeConsole (
   //\r
   // Add the hardcoded short-form USB keyboard device path to ConIn.\r
   //\r
-  EfiBootManagerUpdateConsoleVariable (ConIn,\r
-    (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard, NULL);\r
+  EfiBootManagerUpdateConsoleVariable (\r
+    ConIn,\r
+    (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard,\r
+    NULL\r
+    );\r
 \r
   //\r
   // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.\r
   //\r
-  CopyGuid (&mSerialConsole.TermType.Guid,\r
-    PcdGetPtr (PcdTerminalTypeGuidBuffer));\r
-  EfiBootManagerUpdateConsoleVariable (ConIn,\r
-    (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);\r
-  EfiBootManagerUpdateConsoleVariable (ConOut,\r
-    (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);\r
-  EfiBootManagerUpdateConsoleVariable (ErrOut,\r
-    (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);\r
+  CopyGuid (\r
+    &mSerialConsole.TermType.Guid,\r
+    PcdGetPtr (PcdTerminalTypeGuidBuffer)\r
+    );\r
+  EfiBootManagerUpdateConsoleVariable (\r
+    ConIn,\r
+    (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole,\r
+    NULL\r
+    );\r
+  EfiBootManagerUpdateConsoleVariable (\r
+    ConOut,\r
+    (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole,\r
+    NULL\r
+    );\r
+  EfiBootManagerUpdateConsoleVariable (\r
+    ErrOut,\r
+    (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole,\r
+    NULL\r
+    );\r
 \r
   //\r
   // Set the front page timeout from the QEMU configuration.\r
   //\r
-  PcdSet16 (PcdPlatformBootTimeOut, GetFrontPageTimeoutFromQemu ());\r
+  FrontPageTimeout = GetFrontPageTimeoutFromQemu ();\r
+  PcdStatus        = PcdSet16S (PcdPlatformBootTimeOut, FrontPageTimeout);\r
+  ASSERT_RETURN_ERROR (PcdStatus);\r
+  //\r
+  // Reflect the PCD in the standard Timeout variable.\r
+  //\r
+  Status = gRT->SetVariable (\r
+                  EFI_TIME_OUT_VARIABLE_NAME,\r
+                  &gEfiGlobalVariableGuid,\r
+                  (EFI_VARIABLE_NON_VOLATILE |\r
+                   EFI_VARIABLE_BOOTSERVICE_ACCESS |\r
+                   EFI_VARIABLE_RUNTIME_ACCESS),\r
+                  sizeof FrontPageTimeout,\r
+                  &FrontPageTimeout\r
+                  );\r
+  DEBUG ((\r
+    EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE,\r
+    "%a: SetVariable(%s, %u): %r\n",\r
+    __FUNCTION__,\r
+    EFI_TIME_OUT_VARIABLE_NAME,\r
+    FrontPageTimeout,\r
+    Status\r
+    ));\r
 \r
   //\r
   // Register platform-specific boot options and keyboard shortcuts.\r
   //\r
   PlatformRegisterOptionsAndKeys ();\r
+\r
+  //\r
+  // At this point, VIRTIO_DEVICE_PROTOCOL instances exist only for Virtio MMIO\r
+  // transports. Install EFI_RNG_PROTOCOL instances on Virtio MMIO RNG devices.\r
+  //\r
+  FilterAndProcess (&gVirtioDeviceProtocolGuid, IsVirtioRng, Connect);\r
+\r
+  //\r
+  // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL\r
+  // instances on Virtio PCI RNG devices.\r
+  //\r
+  FilterAndProcess (&gEfiPciIoProtocolGuid, IsVirtioPciRng, Connect);\r
 }\r
 \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
+    > Dynamically switch output mode from 100x31 to 80x25 for certain scenario\r
     > Signal console ready platform customized event\r
   > Run diagnostics like memory testing\r
   > Connect certain devices\r
-  > Dispatch aditional option roms\r
+  > Dispatch additional option roms\r
   > Special boot: e.g.: USB boot, enter UI\r
 **/\r
 VOID\r
@@ -528,30 +919,51 @@ PlatformBootManagerAfterConsole (
   VOID\r
   )\r
 {\r
+  RETURN_STATUS  Status;\r
+\r
   //\r
   // Show the splash screen.\r
   //\r
-  EnableQuietBoot (PcdGetPtr (PcdLogoFile));\r
+  BootLogoEnableLogo ();\r
 \r
   //\r
-  // Connect the rest of the devices.\r
+  // Process QEMU's -kernel command line option. The kernel booted this way\r
+  // will receive ACPI tables: in PlatformBootManagerBeforeConsole(), we\r
+  // connected any and all PCI root bridges, and then signaled the ACPI\r
+  // platform driver.\r
   //\r
-  EfiBootManagerConnectAll ();\r
+  TryRunningQemuKernel ();\r
 \r
   //\r
-  // Process QEMU's -kernel command line option. Note that the kernel booted\r
-  // this way should receive ACPI tables, which is why we connect all devices\r
-  // first (see above) -- PCI enumeration blocks ACPI table installation, if\r
-  // there is a PCI host.\r
+  // Connect the purported boot devices.\r
   //\r
-  TryRunningQemuKernel ();\r
+  Status = ConnectDevicesFromQemu ();\r
+  if (RETURN_ERROR (Status)) {\r
+    //\r
+    // Connect the rest of the devices.\r
+    //\r
+    EfiBootManagerConnectAll ();\r
+  }\r
 \r
   //\r
   // Enumerate all possible boot options, then filter and reorder them based on\r
   // the QEMU configuration.\r
   //\r
   EfiBootManagerRefreshAllBootOption ();\r
+\r
+  //\r
+  // Register UEFI Shell\r
+  //\r
+  PlatformRegisterFvBootOption (\r
+    &gUefiShellFileGuid,\r
+    L"EFI Internal Shell",\r
+    LOAD_OPTION_ACTIVE\r
+    );\r
+\r
+  RemoveStaleFvFileOptions ();\r
   SetBootOrderFromQemu ();\r
+\r
+  PlatformBmPrintScRegisterHandler ();\r
 }\r
 \r
 /**\r
@@ -563,7 +975,93 @@ PlatformBootManagerAfterConsole (
 VOID\r
 EFIAPI\r
 PlatformBootManagerWaitCallback (\r
-  UINT16          TimeoutRemain\r
+  UINT16  TimeoutRemain\r
   )\r
 {\r
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION  Black;\r
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION  White;\r
+  UINT16                               TimeoutInitial;\r
+\r
+  TimeoutInitial = PcdGet16 (PcdPlatformBootTimeOut);\r
+\r
+  //\r
+  // If PcdPlatformBootTimeOut is set to zero, then we consider\r
+  // that no progress update should be enacted.\r
+  //\r
+  if (TimeoutInitial == 0) {\r
+    return;\r
+  }\r
+\r
+  Black.Raw = 0x00000000;\r
+  White.Raw = 0x00FFFFFF;\r
+\r
+  BootLogoUpdateProgress (\r
+    White.Pixel,\r
+    Black.Pixel,\r
+    L"Start boot option",\r
+    White.Pixel,\r
+    (TimeoutInitial - TimeoutRemain) * 100 / TimeoutInitial,\r
+    0\r
+    );\r
+}\r
+\r
+/**\r
+  The function is called when no boot option could be launched,\r
+  including platform recovery options and options pointing to applications\r
+  built into firmware volumes.\r
+\r
+  If this function returns, BDS attempts to enter an infinite loop.\r
+**/\r
+VOID\r
+EFIAPI\r
+PlatformBootManagerUnableToBoot (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_INPUT_KEY                 Key;\r
+  EFI_BOOT_MANAGER_LOAD_OPTION  BootManagerMenu;\r
+  UINTN                         Index;\r
+\r
+  //\r
+  // BootManagerMenu doesn't contain the correct information when return status\r
+  // is EFI_NOT_FOUND.\r
+  //\r
+  Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);\r
+  if (EFI_ERROR (Status)) {\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Normally BdsDxe does not print anything to the system console, but this is\r
+  // a last resort -- the end-user will likely not see any DEBUG messages\r
+  // logged in this situation.\r
+  //\r
+  // AsciiPrint() will NULL-check gST->ConOut internally. We check gST->ConIn\r
+  // here to see if it makes sense to request and wait for a keypress.\r
+  //\r
+  if (gST->ConIn != NULL) {\r
+    AsciiPrint (\r
+      "%a: No bootable option or device was found.\n"\r
+      "%a: Press any key to enter the Boot Manager Menu.\n",\r
+      gEfiCallerBaseName,\r
+      gEfiCallerBaseName\r
+      );\r
+    Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);\r
+    ASSERT_EFI_ERROR (Status);\r
+    ASSERT (Index == 0);\r
+\r
+    //\r
+    // Drain any queued keys.\r
+    //\r
+    while (!EFI_ERROR (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key))) {\r
+      //\r
+      // just throw away Key\r
+      //\r
+    }\r
+  }\r
+\r
+  for ( ; ;) {\r
+    EfiBootManagerBoot (&BootManagerMenu);\r
+  }\r
 }\r