X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=OvmfPkg%2FLibrary%2FPlatformBootManagerLib%2FBdsPlatform.c;h=1408d94f7dae74fcef6b74f34e8f4f414026baee;hb=8e875037bf96c95b9f9c4adce8d453c7936309f0;hp=7ef4d3de16295fe466f7f43750fe4cd3f68a8a42;hpb=7f89929f7fb2f4d75c30fd6838daad61dc996eb5;p=mirror_edk2.git diff --git a/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c b/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c index 7ef4d3de16..1408d94f7d 100644 --- a/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c +++ b/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c @@ -1,20 +1,18 @@ /** @file Platform BDS customizations. - Copyright (c) 2004 - 2016, 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 distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "BdsPlatform.h" #include -#include +#include +#include +#include +#include +#include // @@ -25,7 +23,6 @@ VOID *mEfiDevPathNotifyReg; EFI_EVENT mEfiDevPathEvent; VOID *mEmuVariableEventReg; EFI_EVENT mEmuVariableEvent; -BOOLEAN mDetectVgaOnly; UINT16 mHostBridgeDevId; // @@ -33,14 +30,12 @@ UINT16 mHostBridgeDevId; // (for configuring PCI Interrupt Line register) // CONST UINT8 PciHostIrqs[] = { - 0x0a, 0x0a, 0x0b, 0x0b + 0x0a, // LNKA, LNKE + 0x0a, // LNKB, LNKF + 0x0b, // LNKC, LNKG + 0x0b // LNKD, LNKH }; -// -// Array Size macro -// -#define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0])) - // // Type definitions // @@ -149,6 +144,134 @@ PlatformRegisterFvBootOption ( EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount); } +/** + 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: + - DXEFV's base address or size changed (historical), + - DXEFV'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. +**/ +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_BEGIN (); + CHAR16 *DevicePathString; + + DevicePathString = ConvertDevicePathToText(BootOptions[Index].FilePath, + FALSE, FALSE); + DEBUG (( + EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_VERBOSE, + "%a: removing stale Boot#%04x %s: %r\n", + __FUNCTION__, + (UINT32)BootOptions[Index].OptionNumber, + DevicePathString == NULL ? L"" : DevicePathString, + Status + )); + if (DevicePathString != NULL) { + FreePool (DevicePathString); + } + DEBUG_CODE_END (); + } + + EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount); +} + VOID PlatformRegisterOptionsAndKeys ( VOID @@ -185,12 +308,6 @@ PlatformRegisterOptionsAndKeys ( NULL, (UINT16) BootOption.OptionNumber, 0, &Esc, NULL ); ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED); - // - // Register UEFI Shell - // - PlatformRegisterFvBootOption ( - PcdGetPtr (PcdShellFile), L"EFI Internal Shell", LOAD_OPTION_ACTIVE - ); } EFI_STATUS @@ -201,6 +318,15 @@ ConnectRootBridge ( IN VOID *Context ); +STATIC +EFI_STATUS +EFIAPI +ConnectVirtioPciRng ( + IN EFI_HANDLE Handle, + IN VOID *Instance, + IN VOID *Context + ); + STATIC VOID SaveS3BootScript ( @@ -210,30 +336,31 @@ SaveS3BootScript ( // // 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 ) -/*++ - -Routine Description: - - Platform Bds init. Incude the platform firmware vendor, revision - and so crc check. - -Arguments: - -Returns: - - None. - ---*/ { - EFI_HANDLE Handle; - EFI_STATUS Status; + EFI_HANDLE Handle; + EFI_STATUS Status; + UINT16 FrontPageTimeout; + RETURN_STATUS PcdStatus; - DEBUG ((EFI_D_INFO, "PlatformBootManagerBeforeConsole\n")); + DEBUG ((DEBUG_INFO, "PlatformBootManagerBeforeConsole\n")); InstallDevicePathCallback (); VisitAllInstancesOfProtocol (&gEfiPciRootBridgeIoProtocolGuid, @@ -253,7 +380,7 @@ Returns: // EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid); - if (QemuFwCfgS3Enabled ()) { + if (PcdGetBool (PcdAcpiS3Enable)) { // // Save the boot script too. Note that this will require us to emit the // DxeSmmReadyToLock event just below, which in turn locks down SMM. @@ -261,8 +388,19 @@ Returns: SaveS3BootScript (); } + // We need to connect all trusted consoles for TCG PP. Here we treat all + // consoles in OVMF to be trusted consoles. + PlatformInitializeConsole ( + XenDetected() ? gXenPlatformConsole : gPlatformConsole); + + // + // Process TPM PPI request; this may require keyboard input + // + Tcg2PhysicalPresenceLibProcessRequest (NULL); + // // Prevent further changes to LockBoxes or SMRAM. + // Any TPM 2 Physical Presence Interface opcode must be handled before. // Handle = NULL; Status = gBS->InstallProtocolInterface (&Handle, @@ -270,10 +408,44 @@ Returns: NULL); ASSERT_EFI_ERROR (Status); - PlatformInitializeConsole (gPlatformConsole); - PcdSet16 (PcdPlatformBootTimeOut, GetFrontPageTimeoutFromQemu ()); + // + // Dispatch deferred images after EndOfDxe event and ReadyToLock + // installation. + // + EfiBootManagerDispatchDeferredImages (); + + FrontPageTimeout = GetFrontPageTimeoutFromQemu (); + PcdStatus = PcdSet16S (PcdPlatformBootTimeOut, FrontPageTimeout); + ASSERT_RETURN_ERROR (PcdStatus); + // + // Reflect the PCD in the standard Timeout variable. + // + Status = gRT->SetVariable ( + EFI_TIME_OUT_VARIABLE_NAME, + &gEfiGlobalVariableGuid, + (EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS), + sizeof FrontPageTimeout, + &FrontPageTimeout + ); + DEBUG (( + EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE, + "%a: SetVariable(%s, %u): %r\n", + __FUNCTION__, + EFI_TIME_OUT_VARIABLE_NAME, + FrontPageTimeout, + Status + )); PlatformRegisterOptionsAndKeys (); + + // + // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL + // instances on Virtio PCI RNG devices. + // + VisitAllInstancesOfProtocol (&gEfiPciIoProtocolGuid, ConnectVirtioPciRng, + NULL); } @@ -302,28 +474,110 @@ ConnectRootBridge ( } +STATIC EFI_STATUS -PrepareLpcBridgeDevicePath ( - IN EFI_HANDLE DeviceHandle +EFIAPI +ConnectVirtioPciRng ( + IN EFI_HANDLE Handle, + IN VOID *Instance, + IN VOID *Context ) -/*++ +{ + EFI_PCI_IO_PROTOCOL *PciIo; + EFI_STATUS Status; + UINT16 VendorId; + UINT16 DeviceId; + UINT8 RevisionId; + BOOLEAN Virtio10; + UINT16 SubsystemId; -Routine Description: + PciIo = Instance; - Add IsaKeyboard to ConIn, - add IsaSerial to ConOut, ConIn, ErrOut. - LPC Bridge: 06 01 00 + // + // Read and check VendorId. + // + Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PCI_VENDOR_ID_OFFSET, + 1, &VendorId); + if (EFI_ERROR (Status)) { + goto Error; + } + if (VendorId != VIRTIO_VENDOR_ID) { + return EFI_SUCCESS; + } -Arguments: + // + // Read DeviceId and RevisionId. + // + Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PCI_DEVICE_ID_OFFSET, + 1, &DeviceId); + if (EFI_ERROR (Status)) { + goto Error; + } + Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, PCI_REVISION_ID_OFFSET, + 1, &RevisionId); + if (EFI_ERROR (Status)) { + goto Error; + } - DeviceHandle - Handle of PCIIO protocol. + // + // 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 EFI_SUCCESS; + } + + // + // 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 Error; + } + if ((Virtio10 && SubsystemId >= 0x40) || + (!Virtio10 && SubsystemId == VIRTIO_SUBSYSTEM_ENTROPY_SOURCE)) { + Status = gBS->ConnectController ( + Handle, // ControllerHandle + NULL, // DriverImageHandle -- connect all drivers + NULL, // RemainingDevicePath -- produce all child handles + FALSE // Recursive -- don't follow child handles + ); + if (EFI_ERROR (Status)) { + goto Error; + } + } + return EFI_SUCCESS; + +Error: + DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, Status)); + return Status; +} -Returns: - EFI_SUCCESS - LPC bridge is added to ConOut, ConIn, and ErrOut. - EFI_STATUS - No LPC bridge is added. +/** + Add IsaKeyboard to ConIn; add IsaSerial to ConOut, ConIn, ErrOut. + + @param[in] DeviceHandle Handle of the LPC Bridge device. + + @retval EFI_SUCCESS Console devices on the LPC bridge have been added to + ConOut, ConIn, and ErrOut. ---*/ + @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing + from DeviceHandle. +**/ +EFI_STATUS +PrepareLpcBridgeDevicePath ( + IN EFI_HANDLE DeviceHandle + ) { EFI_STATUS Status; EFI_DEVICE_PATH_PROTOCOL *DevicePath; @@ -344,7 +598,8 @@ Returns: // // Register Keyboard // - DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode); + DevicePath = AppendDevicePathNode (DevicePath, + (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode); EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL); @@ -354,9 +609,12 @@ Returns: DevicePath = TempDevicePath; gPnp16550ComPortDeviceNode.UID = 0; - DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode); - DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode); - DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode); + DevicePath = AppendDevicePathNode (DevicePath, + (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode); + DevicePath = AppendDevicePathNode (DevicePath, + (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode); + DevicePath = AppendDevicePathNode (DevicePath, + (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode); // // Print Device Path @@ -364,9 +622,9 @@ Returns: DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE); if (DevPathStr != NULL) { DEBUG(( - EFI_D_INFO, + DEBUG_INFO, "BdsPlatform.c+%d: COM%d DevPath: %s\n", - __LINE__, + DEBUG_LINE_NUMBER, gPnp16550ComPortDeviceNode.UID + 1, DevPathStr )); @@ -383,9 +641,12 @@ Returns: DevicePath = TempDevicePath; gPnp16550ComPortDeviceNode.UID = 1; - DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode); - DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode); - DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode); + DevicePath = AppendDevicePathNode (DevicePath, + (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode); + DevicePath = AppendDevicePathNode (DevicePath, + (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode); + DevicePath = AppendDevicePathNode (DevicePath, + (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode); // // Print Device Path @@ -393,9 +654,9 @@ Returns: DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE); if (DevPathStr != NULL) { DEBUG(( - EFI_D_INFO, + DEBUG_INFO, "BdsPlatform.c+%d: COM%d DevPath: %s\n", - __LINE__, + DEBUG_LINE_NUMBER, gPnp16550ComPortDeviceNode.UID + 1, DevPathStr )); @@ -409,6 +670,43 @@ Returns: return EFI_SUCCESS; } +typedef struct { + VENDOR_DEVICE_PATH Guid; + EFI_DEVICE_PATH_PROTOCOL End; +} SERIAL_DEVICE_PATH; + +SERIAL_DEVICE_PATH serialDevicePath = { + { + { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH), 0} }, + EDKII_SERIAL_PORT_LIB_VENDOR_GUID + }, + { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } } +}; + +VOID +PrepareMicrovmDevicePath ( + VOID + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + UINT16 HostBridgeDevId; + + HostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId); + if (HostBridgeDevId != MICROVM_PSEUDO_DEVICE_ID) { + return; + } + + DevicePath = (EFI_DEVICE_PATH_PROTOCOL*)&serialDevicePath; + DevicePath = AppendDevicePathNode (DevicePath, + (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode); + DevicePath = AppendDevicePathNode (DevicePath, + (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode); + + EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL); + EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL); + EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL); +} + EFI_STATUS GetGopDevicePath ( IN EFI_DEVICE_PATH_PROTOCOL *PciDevicePath, @@ -443,7 +741,7 @@ GetGopDevicePath ( } // - // Try to connect this handle, so that GOP dirver could start on this + // Try to connect this handle, so that GOP driver could start on this // device and create child handles with GraphicsOutput Protocol installed // on them, then we get device paths of these child handles and select // them as possible console device. @@ -462,7 +760,8 @@ GetGopDevicePath ( // Add all the child handles as possible Console Device // for (Index = 0; Index < GopHandleCount; Index++) { - Status = gBS->HandleProtocol (GopHandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID*)&TempDevicePath); + Status = gBS->HandleProtocol (GopHandleBuffer[Index], + &gEfiDevicePathProtocolGuid, (VOID*)&TempDevicePath); if (EFI_ERROR (Status)) { continue; } @@ -475,14 +774,14 @@ GetGopDevicePath ( // In current implementation, we only enable one of the child handles // as console device, i.e. sotre one of the child handle's device // path to variable "ConOut" - // In futhure, we could select all child handles to be console device + // In future, we could select all child handles to be console device // *GopDevicePath = TempDevicePath; // - // Delete the PCI device's path that added by GetPlugInPciVgaDevicePath() - // Add the integrity GOP device path. + // Delete the PCI device's path that added by + // GetPlugInPciVgaDevicePath(). Add the integrity GOP device path. // EfiBootManagerUpdateConsoleVariable (ConOutDev, NULL, PciDevicePath); EfiBootManagerUpdateConsoleVariable (ConOutDev, TempDevicePath, NULL); @@ -494,27 +793,20 @@ GetGopDevicePath ( return EFI_SUCCESS; } -EFI_STATUS -PreparePciVgaDevicePath ( - IN EFI_HANDLE DeviceHandle - ) -/*++ - -Routine Description: - - Add PCI VGA to ConOut. - PCI VGA: 03 00 00 - -Arguments: - - DeviceHandle - Handle of PCIIO protocol. +/** + Add PCI display to ConOut. -Returns: + @param[in] DeviceHandle Handle of the PCI display device. - EFI_SUCCESS - PCI VGA is added to ConOut. - EFI_STATUS - No PCI VGA device is added. + @retval EFI_SUCCESS The PCI display device has been added to ConOut. ---*/ + @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing + from DeviceHandle. +**/ +EFI_STATUS +PreparePciDisplayDevicePath ( + IN EFI_HANDLE DeviceHandle + ) { EFI_STATUS Status; EFI_DEVICE_PATH_PROTOCOL *DevicePath; @@ -539,27 +831,21 @@ Returns: return EFI_SUCCESS; } -EFI_STATUS -PreparePciSerialDevicePath ( - IN EFI_HANDLE DeviceHandle - ) -/*++ - -Routine Description: - +/** Add PCI Serial to ConOut, ConIn, ErrOut. - PCI Serial: 07 00 02 - -Arguments: - DeviceHandle - Handle of PCIIO protocol. + @param[in] DeviceHandle Handle of the PCI serial device. -Returns: + @retval EFI_SUCCESS The PCI serial device has been added to ConOut, ConIn, + ErrOut. - EFI_SUCCESS - PCI Serial is added to ConOut, ConIn, and ErrOut. - EFI_STATUS - No PCI Serial device is added. - ---*/ + @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing + from DeviceHandle. +**/ +EFI_STATUS +PreparePciSerialDevicePath ( + IN EFI_HANDLE DeviceHandle + ) { EFI_STATUS Status; EFI_DEVICE_PATH_PROTOCOL *DevicePath; @@ -574,8 +860,10 @@ Returns: return Status; } - DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode); - DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode); + DevicePath = AppendDevicePathNode (DevicePath, + (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode); + DevicePath = AppendDevicePathNode (DevicePath, + (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode); EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL); EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL); @@ -691,7 +979,8 @@ VisitAllPciInstances ( @param[in] PciIo - PCI IO protocol instance @param[in] Pci - PCI Header register block - @retval EFI_SUCCESS - PCI Device check and Console variable update successfully. + @retval EFI_SUCCESS - PCI Device check and Console variable update + successfully. @retval EFI_STATUS - PCI Device check or Console variable update fail. **/ @@ -713,46 +1002,44 @@ DetectAndPreparePlatformPciDevicePath ( ); ASSERT_EFI_ERROR (Status); - if (!mDetectVgaOnly) { + // + // Here we decide whether it is LPC Bridge + // + if ((IS_PCI_LPC (Pci)) || + ((IS_PCI_ISA_PDECODE (Pci)) && + (Pci->Hdr.VendorId == 0x8086) && + (Pci->Hdr.DeviceId == 0x7000) + ) + ) { // - // Here we decide whether it is LPC Bridge + // Add IsaKeyboard to ConIn, + // add IsaSerial to ConOut, ConIn, ErrOut // - if ((IS_PCI_LPC (Pci)) || - ((IS_PCI_ISA_PDECODE (Pci)) && - (Pci->Hdr.VendorId == 0x8086) && - (Pci->Hdr.DeviceId == 0x7000) - ) - ) { - // - // Add IsaKeyboard to ConIn, - // add IsaSerial to ConOut, ConIn, ErrOut - // - DEBUG ((EFI_D_INFO, "Found LPC Bridge device\n")); - PrepareLpcBridgeDevicePath (Handle); - return EFI_SUCCESS; - } + DEBUG ((DEBUG_INFO, "Found LPC Bridge device\n")); + PrepareLpcBridgeDevicePath (Handle); + return EFI_SUCCESS; + } + // + // Here we decide which Serial device to enable in PCI bus + // + if (IS_PCI_16550SERIAL (Pci)) { // - // Here we decide which Serial device to enable in PCI bus + // Add them to ConOut, ConIn, ErrOut. // - if (IS_PCI_16550SERIAL (Pci)) { - // - // Add them to ConOut, ConIn, ErrOut. - // - DEBUG ((EFI_D_INFO, "Found PCI 16550 SERIAL device\n")); - PreparePciSerialDevicePath (Handle); - return EFI_SUCCESS; - } + DEBUG ((DEBUG_INFO, "Found PCI 16550 SERIAL device\n")); + PreparePciSerialDevicePath (Handle); + return EFI_SUCCESS; } // - // Here we decide which VGA device to enable in PCI bus + // Here we decide which display device to enable in PCI bus // - if (IS_PCI_VGA (Pci)) { + if (IS_PCI_DISPLAY (Pci)) { // // Add them to ConOut. // - DEBUG ((EFI_D_INFO, "Found PCI VGA device\n")); - PreparePciVgaDevicePath (Handle); + DEBUG ((DEBUG_INFO, "Found PCI display device\n")); + PreparePciDisplayDevicePath (Handle); return EFI_SUCCESS; } @@ -761,80 +1048,48 @@ DetectAndPreparePlatformPciDevicePath ( /** - Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut - - @param[in] DetectVgaOnly - Only detect VGA device if it's TRUE. + Connect the predefined platform default console device. - @retval EFI_SUCCESS - PCI Device check and Console variable update successfully. - @retval EFI_STATUS - PCI Device check or Console variable update fail. + Always try to find and enable PCI display devices. + @param[in] PlatformConsole Predefined platform default console device array. **/ -EFI_STATUS -DetectAndPreparePlatformPciDevicePaths ( - BOOLEAN DetectVgaOnly - ) -{ - mDetectVgaOnly = DetectVgaOnly; - return VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath); -} - - VOID PlatformInitializeConsole ( IN PLATFORM_CONSOLE_CONNECT_ENTRY *PlatformConsole ) -/*++ - -Routine Description: - - Connect the predefined platform default console device. Always try to find - and enable the vga device if have. - -Arguments: - - PlatformConsole - Predfined platform default console device array. ---*/ { UINTN Index; - EFI_DEVICE_PATH_PROTOCOL *VarConout; - EFI_DEVICE_PATH_PROTOCOL *VarConin; // - // Connect RootBridge + // Do platform specific PCI Device check and add them to ConOut, ConIn, + // ErrOut // - GetEfiGlobalVariable2 (EFI_CON_OUT_VARIABLE_NAME, (VOID **) &VarConout, NULL); - GetEfiGlobalVariable2 (EFI_CON_IN_VARIABLE_NAME, (VOID **) &VarConin, NULL); + VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath); - if (VarConout == NULL || VarConin == NULL) { - // - // Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut - // - DetectAndPreparePlatformPciDevicePaths (FALSE); + PrepareMicrovmDevicePath (); + // + // Have chance to connect the platform default console, + // the platform default console is the minimum device group + // the platform should support + // + for (Index = 0; PlatformConsole[Index].DevicePath != NULL; ++Index) { // - // Have chance to connect the platform default console, - // the platform default console is the minimue device group - // the platform should support + // Update the console variable with the connect type // - for (Index = 0; PlatformConsole[Index].DevicePath != NULL; ++Index) { - // - // Update the console variable with the connect type - // - if ((PlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) { - EfiBootManagerUpdateConsoleVariable (ConIn, PlatformConsole[Index].DevicePath, NULL); - } - if ((PlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) { - EfiBootManagerUpdateConsoleVariable (ConOut, PlatformConsole[Index].DevicePath, NULL); - } - if ((PlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) { - EfiBootManagerUpdateConsoleVariable (ErrOut, PlatformConsole[Index].DevicePath, NULL); - } + if ((PlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) { + EfiBootManagerUpdateConsoleVariable (ConIn, + PlatformConsole[Index].DevicePath, NULL); + } + if ((PlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) { + EfiBootManagerUpdateConsoleVariable (ConOut, + PlatformConsole[Index].DevicePath, NULL); + } + if ((PlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) { + EfiBootManagerUpdateConsoleVariable (ErrOut, + PlatformConsole[Index].DevicePath, NULL); } - } else { - // - // Only detect VGA device and add them to ConOut - // - DetectAndPreparePlatformPciDevicePaths (TRUE); } } @@ -914,7 +1169,7 @@ SetPciIntLine ( } if (RootBusNumber == 0 && RootSlot == 0) { DEBUG(( - EFI_D_ERROR, + DEBUG_ERROR, "%a: PCI host bridge (00:00.0) should have no interrupts!\n", __FUNCTION__ )); @@ -965,7 +1220,7 @@ SetPciIntLine ( Status = PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function); ASSERT_EFI_ERROR (Status); - DEBUG ((EFI_D_VERBOSE, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__, + DEBUG ((DEBUG_VERBOSE, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__, (UINT32)Bus, (UINT32)Device, (UINT32)Function, DevPathString, IrqLine)); @@ -1007,27 +1262,35 @@ PciAcpiInitialization ( // // 00:01.0 ISA Bridge (PIIX4) LNK routing targets // - PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A - PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B - PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C - PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D + PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), PciHostIrqs[0]); // A + PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), PciHostIrqs[1]); // B + PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), PciHostIrqs[2]); // C + PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), PciHostIrqs[3]); // D break; case INTEL_Q35_MCH_DEVICE_ID: Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE); // // 00:1f.0 LPC Bridge (Q35) LNK routing targets // - PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A - PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B - PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C - PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D - PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E - PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F - PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G - PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H + PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), PciHostIrqs[0]); // A + PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), PciHostIrqs[1]); // B + PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), PciHostIrqs[2]); // C + PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), PciHostIrqs[3]); // D + PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), PciHostIrqs[0]); // E + PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), PciHostIrqs[1]); // F + PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), PciHostIrqs[2]); // G + PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), PciHostIrqs[3]); // H break; + case MICROVM_PSEUDO_DEVICE_ID: + return; default: - DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n", + if (XenDetected ()) { + // + // There is no PCI bus in this case. + // + return; + } + DEBUG ((DEBUG_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n", __FUNCTION__, mHostBridgeDevId)); ASSERT (FALSE); return; @@ -1044,7 +1307,6 @@ PciAcpiInitialization ( IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0); } - EFI_STATUS EFIAPI ConnectRecursivelyIfPciMassStorage ( @@ -1057,7 +1319,11 @@ ConnectRecursivelyIfPciMassStorage ( EFI_DEVICE_PATH_PROTOCOL *DevicePath; CHAR16 *DevPathStr; - if (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE)) { + // + // Recognize PCI Mass Storage, and Xen PCI devices + // + if (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE) || + (XenDetected() && IS_CLASS2 (PciHeader, 0xFF, 0x80))) { DevicePath = NULL; Status = gBS->HandleProtocol ( Handle, @@ -1074,8 +1340,12 @@ ConnectRecursivelyIfPciMassStorage ( DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE); if (DevPathStr != NULL) { DEBUG(( - EFI_D_INFO, - "Found Mass Storage device: %s\n", + DEBUG_INFO, + "Found %s device: %s\n", + (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE) ? + L"Mass Storage" : + L"Xen" + ), DevPathStr )); FreePool(DevPathStr); @@ -1096,8 +1366,8 @@ ConnectRecursivelyIfPciMassStorage ( This notification function is invoked when the EMU Variable FVB has been changed. - @param Event The event that occured - @param Context For EFI compatiblity. Not used. + @param Event The event that occurred + @param Context For EFI compatibility. Not used. **/ VOID @@ -1107,7 +1377,7 @@ EmuVariablesUpdatedCallback ( IN VOID *Context ) { - DEBUG ((EFI_D_INFO, "EmuVariablesUpdatedCallback\n")); + DEBUG ((DEBUG_INFO, "EmuVariablesUpdatedCallback\n")); UpdateNvVarsOnFileSystem (); } @@ -1122,6 +1392,7 @@ VisitingFileSystemInstance ( { EFI_STATUS Status; STATIC BOOLEAN ConnectedToFileSystem = FALSE; + RETURN_STATUS PcdStatus; if (ConnectedToFileSystem) { return EFI_ALREADY_STARTED; @@ -1141,7 +1412,9 @@ VisitingFileSystemInstance ( NULL, &mEmuVariableEventReg ); - PcdSet64 (PcdEmuVariableEvent, (UINT64)(UINTN) mEmuVariableEvent); + PcdStatus = PcdSet64S (PcdEmuVariableEvent, + (UINT64)(UINTN) mEmuVariableEvent); + ASSERT_RETURN_ERROR (PcdStatus); return EFI_SUCCESS; } @@ -1160,31 +1433,20 @@ PlatformBdsRestoreNvVarsFromHardDisk ( } +/** + Connect with predefined platform connect sequence. + The OEM/IBV can customize with their own connect sequence. +**/ VOID PlatformBdsConnectSequence ( VOID ) -/*++ - -Routine Description: - - Connect with predeined platform connect sequence, - the OEM/IBV can customize with their own connect sequence. - -Arguments: - - None. - -Returns: - - None. - ---*/ { - UINTN Index; + UINTN Index; + RETURN_STATUS Status; - DEBUG ((EFI_D_INFO, "PlatformBdsConnectSequence\n")); + DEBUG ((DEBUG_INFO, "PlatformBdsConnectSequence\n")); Index = 0; @@ -1197,104 +1459,20 @@ Returns: // // Build the platform boot option // - BdsLibConnectDevicePath (gPlatformConnectSequence[Index]); + EfiBootManagerConnectDevicePath (gPlatformConnectSequence[Index], NULL); Index++; } - // - // Just use the simple policy to connect all devices - // - BdsLibConnectAll (); - - PciAcpiInitialization (); - - // - // Clear the logo after all devices are connected. - // - gST->ConOut->ClearScreen (gST->ConOut); -} - -VOID -PlatformBdsGetDriverOption ( - IN OUT LIST_ENTRY *BdsDriverLists - ) -/*++ - -Routine Description: - - Load the predefined driver option, OEM/IBV can customize this - to load their own drivers - -Arguments: - - BdsDriverLists - The header of the driver option link list. - -Returns: - - None. - ---*/ -{ - DEBUG ((EFI_D_INFO, "PlatformBdsGetDriverOption\n")); - return; -} - -VOID -PlatformBdsDiagnostics ( - IN EXTENDMEM_COVERAGE_LEVEL MemoryTestLevel, - IN BOOLEAN QuietBoot, - IN BASEM_MEMORY_TEST BaseMemoryTest - ) -/*++ - -Routine Description: - - Perform the platform diagnostic, such like test memory. OEM/IBV also - can customize this fuction to support specific platform diagnostic. - -Arguments: - - MemoryTestLevel - The memory test intensive level - - QuietBoot - Indicate if need to enable the quiet boot - - BaseMemoryTest - A pointer to BaseMemoryTest() - -Returns: - - None. - ---*/ -{ - EFI_STATUS Status; - - DEBUG ((EFI_D_INFO, "PlatformBdsDiagnostics\n")); - - // - // Here we can decide if we need to show - // the diagnostics screen - // Notes: this quiet boot code should be remove - // from the graphic lib - // - if (QuietBoot) { - EnableQuietBoot (PcdGetPtr(PcdLogoFile)); + Status = ConnectDevicesFromQemu (); + if (RETURN_ERROR (Status)) { // - // Perform system diagnostic + // Just use the simple policy to connect all devices // - Status = BaseMemoryTest (MemoryTestLevel); - if (EFI_ERROR (Status)) { - DisableQuietBoot (); - } - - return ; + DEBUG ((DEBUG_INFO, "EfiBootManagerConnectAll\n")); + EfiBootManagerConnectAll (); } - // - // Perform system diagnostic - // - Status = BaseMemoryTest (MemoryTestLevel); } - /** Save the S3 boot script. @@ -1327,28 +1505,31 @@ SaveS3BootScript ( } +/** + 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 PlatformBootManagerAfterConsole ( VOID ) -/*++ - -Routine Description: - - The function will excute with as the platform policy, current policy - is driven by boot mode. IBV/OEM can customize this code for their specific - policy action. - ---*/ { - EFI_STATUS Status; EFI_BOOT_MODE BootMode; - DEBUG ((EFI_D_INFO, "PlatformBootManagerAfterConsole\n")); + DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole\n")); if (PcdGetBool (PcdOvmfFlashVariablesEnable)) { - DEBUG ((EFI_D_INFO, "PlatformBdsPolicyBehavior: not restoring NvVars " + DEBUG ((DEBUG_INFO, "PlatformBdsPolicyBehavior: not restoring NvVars " "from disk since flash variables appear to be supported.\n")); } else { // @@ -1358,16 +1539,11 @@ Routine Description: PlatformBdsRestoreNvVarsFromHardDisk (); } - // - // Load the driver option as the driver option list - // - PlatformBdsGetDriverOption (DriverOptionList); - // // Get current Boot Mode // - Status = BdsLibGetBootMode (&BootMode); - DEBUG ((EFI_D_ERROR, "Boot Mode:%x\n", BootMode)); + BootMode = GetBootModeHob (); + DEBUG ((DEBUG_INFO, "Boot Mode:%x\n", BootMode)); // // Go the different platform policy with different boot mode @@ -1376,38 +1552,46 @@ Routine Description: ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION); // - // Memory test and Logo show + // Logo show // - PlatformBdsDiagnostics (IGNORE, TRUE, BaseMemoryTest); + BootLogoEnableLogo (); // - // Perform some platform specific connect sequence + // Set PCI Interrupt Line registers and ACPI SCI_EN // - PlatformBdsConnectSequence (); + PciAcpiInitialization (); // // Process QEMU's -kernel command line option // TryRunningQemuKernel (); - DEBUG ((EFI_D_INFO, "BdsLibConnectAll\n")); - BdsLibConnectAll (); - BdsLibEnumerateAllBootOption (BootOptionList); + // + // Perform some platform specific connect sequence + // + PlatformBdsConnectSequence (); + + EfiBootManagerRefreshAllBootOption (); - SetBootOrderFromQemu (BootOptionList); // - // The BootOrder variable may have changed, reload the in-memory list with - // it. + // Register UEFI Shell // - BdsLibBuildOptionFromVar (BootOptionList, L"BootOrder"); + PlatformRegisterFvBootOption ( + &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE + ); + + RemoveStaleFvFileOptions (); + SetBootOrderFromQemu (); + + PlatformBmPrintScRegisterHandler (); } /** This notification function is invoked when an instance of the EFI_DEVICE_PATH_PROTOCOL is produced. - @param Event The event that occured - @param Context For EFI compatiblity. Not used. + @param Event The event that occurred + @param Context For EFI compatibility. Not used. **/ VOID @@ -1453,7 +1637,8 @@ NotifyDevPath ( // // Get the DevicePath protocol on that handle // - Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&DevPathNode); + Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, + (VOID **)&DevPathNode); ASSERT_EFI_ERROR (Status); while (!IsDevicePathEnd (DevPathNode)) { @@ -1492,7 +1677,7 @@ InstallDevicePathCallback ( VOID ) { - DEBUG ((EFI_D_INFO, "Registered NotifyDevPath Event\n")); + DEBUG ((DEBUG_INFO, "Registered NotifyDevPath Event\n")); mEfiDevPathEvent = EfiCreateProtocolNotifyEvent ( &gEfiDevicePathProtocolGuid, TPL_CALLBACK, @@ -1503,7 +1688,8 @@ InstallDevicePathCallback ( } /** - This function is called each second during the boot manager waits the timeout. + This function is called each second during the boot manager waits the + timeout. @param TimeoutRemain The remaining timeout. **/ @@ -1513,5 +1699,90 @@ PlatformBootManagerWaitCallback ( UINT16 TimeoutRemain ) { + EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White; + UINT16 TimeoutInitial; + + TimeoutInitial = PcdGet16 (PcdPlatformBootTimeOut); + + // + // If PcdPlatformBootTimeOut is set to zero, then we consider + // that no progress update should be enacted (since we'd only + // ever display a one-shot progress of either 0% or 100%). + // + if (TimeoutInitial == 0) { + return; + } + + Black.Raw = 0x00000000; + White.Raw = 0x00FFFFFF; + + BootLogoUpdateProgress ( + White.Pixel, + Black.Pixel, + L"Start boot option", + White.Pixel, + (TimeoutInitial - TimeoutRemain) * 100 / TimeoutInitial, + 0 + ); } +/** + The function is called when no boot option could be launched, + including platform recovery options and options pointing to applications + built into firmware volumes. + + If this function returns, BDS attempts to enter an infinite loop. +**/ +VOID +EFIAPI +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); + } +}