X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=ArmVirtPkg%2FLibrary%2FPlatformBootManagerLib%2FPlatformBm.c;h=bb07f5e22b753bd0739aa4bffe8c7257ea186ea3;hp=56f0ea8ff77a8ba8ab2a597f06908aa1d5d3f1ee;hb=8d1b281af3a35de4098a63dfe913efe09328acf0;hpb=b7a33aff2630bedab7e8102ba8fcd7eee12d39f9
diff --git a/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c b/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c
index 56f0ea8ff7..bb07f5e22b 100644
--- a/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c
+++ b/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c
@@ -3,7 +3,7 @@
Copyright (C) 2015-2016, Red Hat, Inc.
Copyright (c) 2014, ARM Ltd. All rights reserved.
- Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.
+ Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available
under the terms and conditions of the BSD License which accompanies this
@@ -16,13 +16,19 @@
**/
#include
+#include
+#include
#include
#include
#include
+#include
#include
+#include
#include
+#include
#include
#include
+#include
#include
#include
@@ -121,32 +127,6 @@ STATIC PLATFORM_USB_KEYBOARD mUsbKeyboard = {
}
};
-//
-// BDS Platform Functions
-//
-/**
- Do the platform init, can be customized by OEM/IBV
- Possible things that can be done in PlatformBootManagerBeforeConsole:
- > Update console variable: 1. include hot-plug devices;
- > 2. Clear ConIn and add SOL for AMT
- > Register new Driver#### or Boot####
- > Register new Key####: e.g.: F12
- > Signal ReadyToLock event
- > Authentication action: 1. connect Auth devices;
- > 2. Identify auto logon user.
-**/
-VOID
-EFIAPI
-PlatformBootManagerBeforeConsole (
- VOID
- )
-{
- //
- // Signal EndOfDxe PI Event
- //
- EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
-}
-
/**
Check if the handle satisfies a particular condition.
@@ -282,6 +262,121 @@ IsPciDisplay (
}
+/**
+ This FILTER_FUNCTION checks if a handle corresponds to a Virtio RNG device at
+ the VIRTIO_DEVICE_PROTOCOL level.
+**/
+STATIC
+BOOLEAN
+EFIAPI
+IsVirtioRng (
+ IN EFI_HANDLE Handle,
+ IN CONST CHAR16 *ReportText
+ )
+{
+ EFI_STATUS Status;
+ VIRTIO_DEVICE_PROTOCOL *VirtIo;
+
+ Status = gBS->HandleProtocol (Handle, &gVirtioDeviceProtocolGuid,
+ (VOID**)&VirtIo);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+ return (BOOLEAN)(VirtIo->SubSystemDeviceId ==
+ VIRTIO_SUBSYSTEM_ENTROPY_SOURCE);
+}
+
+
+/**
+ This FILTER_FUNCTION checks if a handle corresponds to a Virtio RNG device at
+ the EFI_PCI_IO_PROTOCOL level.
+**/
+STATIC
+BOOLEAN
+EFIAPI
+IsVirtioPciRng (
+ IN EFI_HANDLE Handle,
+ IN CONST CHAR16 *ReportText
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT16 VendorId;
+ UINT16 DeviceId;
+ UINT8 RevisionId;
+ BOOLEAN Virtio10;
+ UINT16 SubsystemId;
+
+ Status = gBS->HandleProtocol (Handle, &gEfiPciIoProtocolGuid,
+ (VOID**)&PciIo);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ //
+ // Read and check VendorId.
+ //
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PCI_VENDOR_ID_OFFSET,
+ 1, &VendorId);
+ if (EFI_ERROR (Status)) {
+ goto PciError;
+ }
+ if (VendorId != VIRTIO_VENDOR_ID) {
+ return FALSE;
+ }
+
+ //
+ // Read DeviceId and RevisionId.
+ //
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PCI_DEVICE_ID_OFFSET,
+ 1, &DeviceId);
+ if (EFI_ERROR (Status)) {
+ goto PciError;
+ }
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, PCI_REVISION_ID_OFFSET,
+ 1, &RevisionId);
+ if (EFI_ERROR (Status)) {
+ goto PciError;
+ }
+
+ //
+ // From DeviceId and RevisionId, determine whether the device is a
+ // modern-only Virtio 1.0 device. In case of Virtio 1.0, DeviceId can
+ // immediately be restricted to VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and
+ // SubsystemId will only play a sanity-check role. Otherwise, DeviceId can
+ // only be sanity-checked, and SubsystemId will decide.
+ //
+ if (DeviceId == 0x1040 + VIRTIO_SUBSYSTEM_ENTROPY_SOURCE &&
+ RevisionId >= 0x01) {
+ Virtio10 = TRUE;
+ } else if (DeviceId >= 0x1000 && DeviceId <= 0x103F && RevisionId == 0x00) {
+ Virtio10 = FALSE;
+ } else {
+ return FALSE;
+ }
+
+ //
+ // Read and check SubsystemId as dictated by Virtio10.
+ //
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16,
+ PCI_SUBSYSTEM_ID_OFFSET, 1, &SubsystemId);
+ if (EFI_ERROR (Status)) {
+ goto PciError;
+ }
+ if (Virtio10 && SubsystemId >= 0x40) {
+ return TRUE;
+ }
+ if (!Virtio10 && SubsystemId == VIRTIO_SUBSYSTEM_ENTROPY_SOURCE) {
+ return TRUE;
+ }
+ return FALSE;
+
+PciError:
+ DEBUG ((DEBUG_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status));
+ return FALSE;
+}
+
+
/**
This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking
the matching driver to produce all first-level child handles.
@@ -347,24 +442,271 @@ AddOutput (
ReportText));
}
+STATIC
+VOID
+PlatformRegisterFvBootOption (
+ EFI_GUID *FileGuid,
+ CHAR16 *Description,
+ UINT32 Attributes
+ )
+{
+ EFI_STATUS Status;
+ INTN OptionIndex;
+ EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
+ UINTN BootOptionCount;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ Status = gBS->HandleProtocol (
+ gImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **) &LoadedImage
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
+ DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);
+ ASSERT (DevicePath != NULL);
+ DevicePath = AppendDevicePathNode (
+ DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
+ );
+ ASSERT (DevicePath != NULL);
+
+ Status = EfiBootManagerInitializeLoadOption (
+ &NewOption,
+ LoadOptionNumberUnassigned,
+ LoadOptionTypeBoot,
+ Attributes,
+ Description,
+ DevicePath,
+ NULL,
+ 0
+ );
+ ASSERT_EFI_ERROR (Status);
+ FreePool (DevicePath);
+
+ BootOptions = EfiBootManagerGetLoadOptions (
+ &BootOptionCount, LoadOptionTypeBoot
+ );
+
+ OptionIndex = EfiBootManagerFindLoadOption (
+ &NewOption, BootOptions, BootOptionCount
+ );
+
+ if (OptionIndex == -1) {
+ Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);
+ ASSERT_EFI_ERROR (Status);
+ }
+ EfiBootManagerFreeLoadOption (&NewOption);
+ EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
+}
+
/**
- Do the platform specific action after the console is ready
- Possible things that can be done in PlatformBootManagerAfterConsole:
- > Console post action:
- > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
- > Signal console ready platform customized event
- > Run diagnostics like memory testing
- > Connect certain devices
- > Dispatch aditional option roms
- > Special boot: e.g.: USB boot, enter UI
+ Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options
+ whose device paths do not resolve exactly to an FvFile in the system.
+
+ This removes any boot options that point to binaries built into the firmware
+ and have become stale due to any of the following:
+ - FvMain's base address or size changed (historical),
+ - FvMain's FvNameGuid changed,
+ - the FILE_GUID of the pointed-to binary changed,
+ - the referenced binary is no longer built into the firmware.
+
+ EfiBootManagerFindLoadOption() used in PlatformRegisterFvBootOption() only
+ avoids exact duplicates.
+**/
+STATIC
+VOID
+RemoveStaleFvFileOptions (
+ VOID
+ )
+{
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
+ UINTN BootOptionCount;
+ UINTN Index;
+
+ BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount,
+ LoadOptionTypeBoot);
+
+ for (Index = 0; Index < BootOptionCount; ++Index) {
+ EFI_DEVICE_PATH_PROTOCOL *Node1, *Node2, *SearchNode;
+ EFI_STATUS Status;
+ EFI_HANDLE FvHandle;
+
+ //
+ // If the device path starts with neither MemoryMapped(...) nor Fv(...),
+ // then keep the boot option.
+ //
+ Node1 = BootOptions[Index].FilePath;
+ if (!(DevicePathType (Node1) == HARDWARE_DEVICE_PATH &&
+ DevicePathSubType (Node1) == HW_MEMMAP_DP) &&
+ !(DevicePathType (Node1) == MEDIA_DEVICE_PATH &&
+ DevicePathSubType (Node1) == MEDIA_PIWG_FW_VOL_DP)) {
+ continue;
+ }
+
+ //
+ // If the second device path node is not FvFile(...), then keep the boot
+ // option.
+ //
+ Node2 = NextDevicePathNode (Node1);
+ if (DevicePathType (Node2) != MEDIA_DEVICE_PATH ||
+ DevicePathSubType (Node2) != MEDIA_PIWG_FW_FILE_DP) {
+ continue;
+ }
+
+ //
+ // Locate the Firmware Volume2 protocol instance that is denoted by the
+ // boot option. If this lookup fails (i.e., the boot option references a
+ // firmware volume that doesn't exist), then we'll proceed to delete the
+ // boot option.
+ //
+ SearchNode = Node1;
+ Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid,
+ &SearchNode, &FvHandle);
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // The firmware volume was found; now let's see if it contains the FvFile
+ // identified by GUID.
+ //
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFileNode;
+ UINTN BufferSize;
+ EFI_FV_FILETYPE FoundType;
+ EFI_FV_FILE_ATTRIBUTES FileAttributes;
+ UINT32 AuthenticationStatus;
+
+ Status = gBS->HandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **)&FvProtocol);
+ ASSERT_EFI_ERROR (Status);
+
+ FvFileNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)Node2;
+ //
+ // Buffer==NULL means we request metadata only: BufferSize, FoundType,
+ // FileAttributes.
+ //
+ Status = FvProtocol->ReadFile (
+ FvProtocol,
+ &FvFileNode->FvFileName, // NameGuid
+ NULL, // Buffer
+ &BufferSize,
+ &FoundType,
+ &FileAttributes,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // The FvFile was found. Keep the boot option.
+ //
+ continue;
+ }
+ }
+
+ //
+ // Delete the boot option.
+ //
+ Status = EfiBootManagerDeleteLoadOptionVariable (
+ BootOptions[Index].OptionNumber, LoadOptionTypeBoot);
+ DEBUG_CODE (
+ CHAR16 *DevicePathString;
+
+ DevicePathString = ConvertDevicePathToText(BootOptions[Index].FilePath,
+ FALSE, FALSE);
+ DEBUG ((
+ EFI_ERROR (Status) ? EFI_D_WARN : EFI_D_VERBOSE,
+ "%a: removing stale Boot#%04x %s: %r\n",
+ __FUNCTION__,
+ (UINT32)BootOptions[Index].OptionNumber,
+ DevicePathString == NULL ? L"" : DevicePathString,
+ Status
+ ));
+ if (DevicePathString != NULL) {
+ FreePool (DevicePathString);
+ }
+ );
+ }
+
+ EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
+}
+
+
+STATIC
+VOID
+PlatformRegisterOptionsAndKeys (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_INPUT_KEY Enter;
+ EFI_INPUT_KEY F2;
+ EFI_INPUT_KEY Esc;
+ EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
+
+ //
+ // Register ENTER as CONTINUE key
+ //
+ Enter.ScanCode = SCAN_NULL;
+ Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
+ Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Map F2 and ESC to Boot Manager Menu
+ //
+ F2.ScanCode = SCAN_F2;
+ F2.UnicodeChar = CHAR_NULL;
+ Esc.ScanCode = SCAN_ESC;
+ Esc.UnicodeChar = CHAR_NULL;
+ Status = EfiBootManagerGetBootManagerMenu (&BootOption);
+ ASSERT_EFI_ERROR (Status);
+ Status = EfiBootManagerAddKeyOptionVariable (
+ NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL
+ );
+ ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
+ Status = EfiBootManagerAddKeyOptionVariable (
+ NULL, (UINT16) BootOption.OptionNumber, 0, &Esc, NULL
+ );
+ ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
+}
+
+
+//
+// BDS Platform Functions
+//
+/**
+ Do the platform init, can be customized by OEM/IBV
+ Possible things that can be done in PlatformBootManagerBeforeConsole:
+ > Update console variable: 1. include hot-plug devices;
+ > 2. Clear ConIn and add SOL for AMT
+ > Register new Driver#### or Boot####
+ > Register new Key####: e.g.: F12
+ > Signal ReadyToLock event
+ > Authentication action: 1. connect Auth devices;
+ > 2. Identify auto logon user.
**/
VOID
EFIAPI
-PlatformBootManagerAfterConsole (
+PlatformBootManagerBeforeConsole (
VOID
)
{
+ RETURN_STATUS PcdStatus;
+
+ //
+ // Signal EndOfDxe PI Event
+ //
+ EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
+
+ //
+ // Dispatch deferred images after EndOfDxe event.
+ //
+ EfiBootManagerDispatchDeferredImages ();
+
//
// Locate the PCI root bridges and make the PCI bus driver connect each,
// non-recursively. This will produce a number of child handles with PciIo on
@@ -409,99 +751,177 @@ PlatformBootManagerAfterConsole (
(EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
//
- // Connect the consoles based on the above variables.
- //
- BdsLibConnectAllDefaultConsoles ();
-
- //
- // Show the splash screen.
+ // Set the front page timeout from the QEMU configuration.
//
- EnableQuietBoot (PcdGetPtr (PcdLogoFile));
+ PcdStatus = PcdSet16S (PcdPlatformBootTimeOut,
+ GetFrontPageTimeoutFromQemu ());
+ ASSERT_RETURN_ERROR (PcdStatus);
//
- // Connect the rest of the devices.
+ // Register platform-specific boot options and keyboard shortcuts.
//
- BdsLibConnectAll ();
+ PlatformRegisterOptionsAndKeys ();
//
- // Process QEMU's -kernel command line option. Note that the kernel booted
- // this way should receive ACPI tables, which is why we connect all devices
- // first (see above) -- PCI enumeration blocks ACPI table installation, if
- // there is a PCI host.
+ // At this point, VIRTIO_DEVICE_PROTOCOL instances exist only for Virtio MMIO
+ // transports. Install EFI_RNG_PROTOCOL instances on Virtio MMIO RNG devices.
//
- TryRunningQemuKernel ();
+ FilterAndProcess (&gVirtioDeviceProtocolGuid, IsVirtioRng, Connect);
- BdsLibEnumerateAllBootOption (BootOptionList);
- SetBootOrderFromQemu (BootOptionList);
//
- // The BootOrder variable may have changed, reload the in-memory list with
- // it.
+ // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL
+ // instances on Virtio PCI RNG devices.
//
- BdsLibBuildOptionFromVar (BootOptionList, L"BootOrder");
-
- PlatformBdsEnterFrontPage (GetFrontPageTimeoutFromQemu(), TRUE);
+ FilterAndProcess (&gEfiPciIoProtocolGuid, IsVirtioPciRng, Connect);
}
/**
- Hook point after a boot attempt succeeds. We don't expect a boot option to
- return, so the UEFI 2.0 specification defines that you will default to an
- interactive mode and stop processing the BootOrder list in this case. This
- is also a platform implementation and can be customized by IBV/OEM.
-
- @param Option Pointer to Boot Option that succeeded to boot.
-
+ Do the platform specific action after the console is ready
+ Possible things that can be done in PlatformBootManagerAfterConsole:
+ > Console post action:
+ > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
+ > Signal console ready platform customized event
+ > Run diagnostics like memory testing
+ > Connect certain devices
+ > Dispatch aditional option roms
+ > Special boot: e.g.: USB boot, enter UI
**/
VOID
EFIAPI
-PlatformBdsBootSuccess (
- IN BDS_COMMON_OPTION *Option
+PlatformBootManagerAfterConsole (
+ VOID
)
{
-}
+ RETURN_STATUS Status;
-/**
- Hook point after a boot attempt fails.
+ //
+ // Show the splash screen.
+ //
+ BootLogoEnableLogo ();
- @param Option Pointer to Boot Option that failed to boot.
- @param Status Status returned from failed boot.
- @param ExitData Exit data returned from failed boot.
- @param ExitDataSize Exit data size returned from failed boot.
+ //
+ // Process QEMU's -kernel command line option. The kernel booted this way
+ // will receive ACPI tables: in PlatformBootManagerBeforeConsole(), we
+ // connected any and all PCI root bridges, and then signaled the ACPI
+ // platform driver.
+ //
+ TryRunningQemuKernel ();
-**/
-VOID
-EFIAPI
-PlatformBdsBootFail (
- IN BDS_COMMON_OPTION *Option,
- IN EFI_STATUS Status,
- IN CHAR16 *ExitData,
- IN UINTN ExitDataSize
- )
-{
+ //
+ // Connect the purported boot devices.
+ //
+ Status = ConnectDevicesFromQemu ();
+ if (RETURN_ERROR (Status)) {
+ //
+ // Connect the rest of the devices.
+ //
+ EfiBootManagerConnectAll ();
+ }
+
+ //
+ // Enumerate all possible boot options, then filter and reorder them based on
+ // the QEMU configuration.
+ //
+ EfiBootManagerRefreshAllBootOption ();
+
+ //
+ // Register UEFI Shell
+ //
+ PlatformRegisterFvBootOption (
+ &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE
+ );
+
+ RemoveStaleFvFileOptions ();
+ SetBootOrderFromQemu ();
}
/**
- This function locks platform flash that is not allowed to be updated during normal boot path.
- The flash layout is platform specific.
+ This function is called each second during the boot manager waits the
+ timeout.
+
+ @param TimeoutRemain The remaining timeout.
**/
VOID
EFIAPI
-PlatformBdsLockNonUpdatableFlash (
- VOID
+PlatformBootManagerWaitCallback (
+ UINT16 TimeoutRemain
)
{
- return;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;
+ UINT16 Timeout;
+
+ Timeout = PcdGet16 (PcdPlatformBootTimeOut);
+
+ Black.Raw = 0x00000000;
+ White.Raw = 0x00FFFFFF;
+
+ BootLogoUpdateProgress (
+ White.Pixel,
+ Black.Pixel,
+ L"Start boot option",
+ White.Pixel,
+ (Timeout - TimeoutRemain) * 100 / Timeout,
+ 0
+ );
}
/**
- This function is called each second during the boot manager waits the
- timeout.
+ The function is called when no boot option could be launched,
+ including platform recovery options and options pointing to applications
+ built into firmware volumes.
- @param TimeoutRemain The remaining timeout.
+ If this function returns, BDS attempts to enter an infinite loop.
**/
VOID
EFIAPI
-PlatformBootManagerWaitCallback (
- UINT16 TimeoutRemain
+PlatformBootManagerUnableToBoot (
+ VOID
)
{
+ EFI_STATUS Status;
+ EFI_INPUT_KEY Key;
+ EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;
+ UINTN Index;
+
+ //
+ // BootManagerMenu doesn't contain the correct information when return status
+ // is EFI_NOT_FOUND.
+ //
+ Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+ //
+ // Normally BdsDxe does not print anything to the system console, but this is
+ // a last resort -- the end-user will likely not see any DEBUG messages
+ // logged in this situation.
+ //
+ // AsciiPrint() will NULL-check gST->ConOut internally. We check gST->ConIn
+ // here to see if it makes sense to request and wait for a keypress.
+ //
+ if (gST->ConIn != NULL) {
+ AsciiPrint (
+ "%a: No bootable option or device was found.\n"
+ "%a: Press any key to enter the Boot Manager Menu.\n",
+ gEfiCallerBaseName,
+ gEfiCallerBaseName
+ );
+ Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (Index == 0);
+
+ //
+ // Drain any queued keys.
+ //
+ while (!EFI_ERROR (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key))) {
+ //
+ // just throw away Key
+ //
+ }
+ }
+
+ for (;;) {
+ EfiBootManagerBoot (&BootManagerMenu);
+ }
}