X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=OvmfPkg%2FLibrary%2FPlatformBootManagerLib%2FBdsPlatform.c;h=98f6f07341ec27e54a7607d63f07bab742dd4d4d;hb=HEAD;hp=16618a8f57f08636ba62ce5f68cbb8d0d8219092;hpb=103b12cec526e4fa6f709840fefc1d554387a170;p=mirror_edk2.git diff --git a/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c b/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c index 16618a8f57..98f6f07341 100644 --- a/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c +++ b/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c @@ -1,49 +1,40 @@ /** @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 // // Global data // -VOID *mEfiDevPathNotifyReg; -EFI_EVENT mEfiDevPathEvent; -VOID *mEmuVariableEventReg; -EFI_EVENT mEmuVariableEvent; -BOOLEAN mDetectVgaOnly; -UINT16 mHostBridgeDevId; +VOID *mEfiDevPathNotifyReg; +EFI_EVENT mEfiDevPathEvent; +VOID *mEmuVariableEventReg; +EFI_EVENT mEmuVariableEvent; +UINT16 mHostBridgeDevId; // // Table of host IRQs matching PCI IRQs A-D // (for configuring PCI Interrupt Line register) // -CONST UINT8 PciHostIrqs[] = { - 0x0a, 0x0a, 0x0b, 0x0b +CONST UINT8 PciHostIrqs[] = { + 0x0a, // LNKA, LNKE + 0x0a, // LNKB, LNKF + 0x0b, // LNKC, LNKG + 0x0b // LNKD, LNKH }; -// -// Array Size macro -// -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0])) -#endif - // // Type definitions // @@ -69,7 +60,6 @@ EFI_STATUS IN PCI_TYPE00 *Pci ); - // // Function prototypes // @@ -83,7 +73,7 @@ VisitAllInstancesOfProtocol ( EFI_STATUS VisitAllPciInstancesOfProtocol ( - IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction + IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction ); VOID @@ -93,24 +83,24 @@ InstallDevicePathCallback ( VOID PlatformRegisterFvBootOption ( - EFI_GUID *FileGuid, - CHAR16 *Description, - UINT32 Attributes + 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; + 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 + (VOID **)&LoadedImage ); ASSERT_EFI_ERROR (Status); @@ -119,7 +109,7 @@ PlatformRegisterFvBootOption ( ASSERT (DevicePath != NULL); DevicePath = AppendDevicePathNode ( DevicePath, - (EFI_DEVICE_PATH_PROTOCOL *) &FileNode + (EFI_DEVICE_PATH_PROTOCOL *)&FileNode ); ASSERT (DevicePath != NULL); @@ -137,17 +127,21 @@ PlatformRegisterFvBootOption ( FreePool (DevicePath); BootOptions = EfiBootManagerGetLoadOptions ( - &BootOptionCount, LoadOptionTypeBoot + &BootOptionCount, + LoadOptionTypeBoot ); OptionIndex = EfiBootManagerFindLoadOption ( - &NewOption, BootOptions, BootOptionCount + &NewOption, + BootOptions, + BootOptionCount ); if (OptionIndex == -1) { Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN); ASSERT_EFI_ERROR (Status); } + EfiBootManagerFreeLoadOption (&NewOption); EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount); } @@ -171,27 +165,30 @@ RemoveStaleFvFileOptions ( VOID ) { - EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions; - UINTN BootOptionCount; - UINTN Index; + EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions; + UINTN BootOptionCount; + UINTN Index; - BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, - LoadOptionTypeBoot); + BootOptions = EfiBootManagerGetLoadOptions ( + &BootOptionCount, + LoadOptionTypeBoot + ); for (Index = 0; Index < BootOptionCount; ++Index) { - EFI_DEVICE_PATH_PROTOCOL *Node1, *Node2, *SearchNode; - EFI_STATUS Status; - EFI_HANDLE FvHandle; + 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)) { + if (!((DevicePathType (Node1) == HARDWARE_DEVICE_PATH) && + (DevicePathSubType (Node1) == HW_MEMMAP_DP)) && + !((DevicePathType (Node1) == MEDIA_DEVICE_PATH) && + (DevicePathSubType (Node1) == MEDIA_PIWG_FW_VOL_DP))) + { continue; } @@ -200,8 +197,9 @@ RemoveStaleFvFileOptions ( // option. // Node2 = NextDevicePathNode (Node1); - if (DevicePathType (Node2) != MEDIA_DEVICE_PATH || - DevicePathSubType (Node2) != MEDIA_PIWG_FW_FILE_DP) { + if ((DevicePathType (Node2) != MEDIA_DEVICE_PATH) || + (DevicePathSubType (Node2) != MEDIA_PIWG_FW_FILE_DP)) + { continue; } @@ -212,23 +210,29 @@ RemoveStaleFvFileOptions ( // boot option. // SearchNode = Node1; - Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, - &SearchNode, &FvHandle); + 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); + 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; @@ -257,24 +261,30 @@ RemoveStaleFvFileOptions ( // Delete the boot option. // Status = EfiBootManagerDeleteLoadOptionVariable ( - BootOptions[Index].OptionNumber, LoadOptionTypeBoot); - DEBUG_CODE ( - CHAR16 *DevicePathString; + 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); + } - 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); - } - ); + DEBUG_CODE_END (); } EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount); @@ -285,18 +295,18 @@ PlatformRegisterOptionsAndKeys ( VOID ) { - EFI_STATUS Status; - EFI_INPUT_KEY Enter; - EFI_INPUT_KEY F2; - EFI_INPUT_KEY Esc; - EFI_BOOT_MANAGER_LOAD_OPTION BootOption; + 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); + Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL); ASSERT_EFI_ERROR (Status); // @@ -306,14 +316,22 @@ PlatformRegisterOptionsAndKeys ( F2.UnicodeChar = CHAR_NULL; Esc.ScanCode = SCAN_ESC; Esc.UnicodeChar = CHAR_NULL; - Status = EfiBootManagerGetBootManagerMenu (&BootOption); + Status = EfiBootManagerGetBootManagerMenu (&BootOption); ASSERT_EFI_ERROR (Status); Status = EfiBootManagerAddKeyOptionVariable ( - NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL + NULL, + (UINT16)BootOption.OptionNumber, + 0, + &F2, + NULL ); ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED); Status = EfiBootManagerAddKeyOptionVariable ( - NULL, (UINT16) BootOption.OptionNumber, 0, &Esc, NULL + NULL, + (UINT16)BootOption.OptionNumber, + 0, + &Esc, + NULL ); ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED); } @@ -326,6 +344,15 @@ ConnectRootBridge ( IN VOID *Context ); +STATIC +EFI_STATUS +EFIAPI +ConnectVirtioPciRng ( + IN EFI_HANDLE Handle, + IN VOID *Instance, + IN VOID *Context + ); + STATIC VOID SaveS3BootScript ( @@ -335,35 +362,39 @@ 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. Include the platform firmware vendor, revision - and so crc check. - -Arguments: - -Returns: - - None. - ---*/ { - EFI_HANDLE Handle; - EFI_STATUS Status; - RETURN_STATUS PcdStatus; + 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, - ConnectRootBridge, NULL); + VisitAllInstancesOfProtocol ( + &gEfiPciRootBridgeIoProtocolGuid, + ConnectRootBridge, + NULL + ); // // Signal the ACPI platform driver that it can download QEMU ACPI tables. @@ -379,7 +410,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. @@ -387,23 +418,85 @@ Returns: SaveS3BootScript (); } + // + // We need to connect all trusted consoles for TCG PP. Here we treat all + // consoles in OVMF to be trusted consoles. + // + // Cloud Hypervisor doesn't emulate any LPC bridge, which is why it must + // rely on the serial I/O port to be connected as a console. It reuses the + // definition from Xen as it is very generic. + // + PlatformInitializeConsole ( + (XenDetected () || PcdGet16 (PcdOvmfHostBridgePciDevId) == CLOUDHV_DEVICE_ID) ? 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, - &gEfiDxeSmmReadyToLockProtocolGuid, EFI_NATIVE_INTERFACE, - NULL); + Status = gBS->InstallProtocolInterface ( + &Handle, + &gEfiDxeSmmReadyToLockProtocolGuid, + EFI_NATIVE_INTERFACE, + NULL + ); ASSERT_EFI_ERROR (Status); - PlatformInitializeConsole (gPlatformConsole); - PcdStatus = PcdSet16S (PcdPlatformBootTimeOut, - GetFrontPageTimeoutFromQemu ()); + // + // Dispatch deferred images after EndOfDxe event and ReadyToLock + // installation. + // + EfiBootManagerDispatchDeferredImages (); + + // + // GPU passthrough only allows Console enablement after ROM image load + // + PlatformInitializeConsole ( + XenDetected () ? gXenPlatformConsole : gPlatformConsole + ); + + 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 + ); +} EFI_STATUS EFIAPI @@ -413,7 +506,7 @@ ConnectRootBridge ( IN VOID *Context ) { - EFI_STATUS Status; + EFI_STATUS Status; // // Make the PCI bus driver connect the root bridge, non-recursively. This @@ -429,29 +522,135 @@ ConnectRootBridge ( return Status; } - +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; + } -Arguments: + if (VendorId != VIRTIO_VENDOR_ID) { + return EFI_SUCCESS; + } - DeviceHandle - Handle of PCIIO protocol. + // + // Read DeviceId and RevisionId. + // + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint16, + PCI_DEVICE_ID_OFFSET, + 1, + &DeviceId + ); + if (EFI_ERROR (Status)) { + goto Error; + } -Returns: + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint8, + PCI_REVISION_ID_OFFSET, + 1, + &RevisionId + ); + if (EFI_ERROR (Status)) { + goto Error; + } - EFI_SUCCESS - LPC bridge is added to ConOut, ConIn, and ErrOut. - EFI_STATUS - No LPC bridge is added. + // + // 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; +} + +/** + 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; @@ -459,46 +658,59 @@ Returns: CHAR16 *DevPathStr; DevicePath = NULL; - Status = gBS->HandleProtocol ( - DeviceHandle, - &gEfiDevicePathProtocolGuid, - (VOID*)&DevicePath - ); + Status = gBS->HandleProtocol ( + DeviceHandle, + &gEfiDevicePathProtocolGuid, + (VOID *)&DevicePath + ); if (EFI_ERROR (Status)) { return Status; } + TempDevicePath = DevicePath; // // Register Keyboard // - DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode); + DevicePath = AppendDevicePathNode ( + DevicePath, + (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode + ); EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL); // // Register COM1 // - DevicePath = TempDevicePath; + 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 // DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE); if (DevPathStr != NULL) { - DEBUG(( - EFI_D_INFO, + DEBUG (( + DEBUG_INFO, "BdsPlatform.c+%d: COM%d DevPath: %s\n", - __LINE__, + DEBUG_LINE_NUMBER, gPnp16550ComPortDeviceNode.UID + 1, DevPathStr )); - FreePool(DevPathStr); + FreePool (DevPathStr); } EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL); @@ -508,26 +720,35 @@ Returns: // // Register COM2 // - DevicePath = TempDevicePath; + 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 // DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE); if (DevPathStr != NULL) { - DEBUG(( - EFI_D_INFO, + DEBUG (( + DEBUG_INFO, "BdsPlatform.c+%d: COM%d DevPath: %s\n", - __LINE__, + DEBUG_LINE_NUMBER, gPnp16550ComPortDeviceNode.UID + 1, DevPathStr )); - FreePool(DevPathStr); + FreePool (DevPathStr); } EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL); @@ -537,21 +758,64 @@ 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, - OUT EFI_DEVICE_PATH_PROTOCOL **GopDevicePath - ) + IN EFI_DEVICE_PATH_PROTOCOL *PciDevicePath, + OUT EFI_DEVICE_PATH_PROTOCOL **GopDevicePath + ) { - UINTN Index; - EFI_STATUS Status; - EFI_HANDLE PciDeviceHandle; - EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; - EFI_DEVICE_PATH_PROTOCOL *TempPciDevicePath; - UINTN GopHandleCount; - EFI_HANDLE *GopHandleBuffer; - - if (PciDevicePath == NULL || GopDevicePath == NULL) { + UINTN Index; + EFI_STATUS Status; + EFI_HANDLE PciDeviceHandle; + EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; + EFI_DEVICE_PATH_PROTOCOL *TempPciDevicePath; + UINTN GopHandleCount; + EFI_HANDLE *GopHandleBuffer; + + if ((PciDevicePath == NULL) || (GopDevicePath == NULL)) { return EFI_INVALID_PARAMETER; } @@ -590,15 +854,21 @@ 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; } + if (CompareMem ( PciDevicePath, TempDevicePath, GetDevicePathSize (PciDevicePath) - END_DEVICE_PATH_LENGTH - ) == 0) { + ) == 0) + { // // In current implementation, we only enable one of the child handles // as console device, i.e. sotre one of the child handle's device @@ -609,40 +879,34 @@ GetGopDevicePath ( *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); } } + gBS->FreePool (GopHandleBuffer); } return EFI_SUCCESS; } -EFI_STATUS -PreparePciDisplayDevicePath ( - 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; @@ -650,11 +914,11 @@ Returns: DevicePath = NULL; GopDevicePath = NULL; - Status = gBS->HandleProtocol ( - DeviceHandle, - &gEfiDevicePathProtocolGuid, - (VOID*)&DevicePath - ); + Status = gBS->HandleProtocol ( + DeviceHandle, + &gEfiDevicePathProtocolGuid, + (VOID *)&DevicePath + ); if (EFI_ERROR (Status)) { return Status; } @@ -667,43 +931,43 @@ 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: + @param[in] DeviceHandle Handle of the PCI serial device. - DeviceHandle - Handle of PCIIO protocol. + @retval EFI_SUCCESS The PCI serial device has been added to ConOut, ConIn, + ErrOut. -Returns: - - 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; DevicePath = NULL; - Status = gBS->HandleProtocol ( - DeviceHandle, - &gEfiDevicePathProtocolGuid, - (VOID*)&DevicePath - ); + Status = gBS->HandleProtocol ( + DeviceHandle, + &gEfiDevicePathProtocolGuid, + (VOID *)&DevicePath + ); if (EFI_ERROR (Status)) { 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); @@ -719,24 +983,24 @@ VisitAllInstancesOfProtocol ( IN VOID *Context ) { - EFI_STATUS Status; - UINTN HandleCount; - EFI_HANDLE *HandleBuffer; - UINTN Index; - VOID *Instance; + EFI_STATUS Status; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINTN Index; + VOID *Instance; // // Start to check all the PciIo to find all possible device // - HandleCount = 0; + HandleCount = 0; HandleBuffer = NULL; - Status = gBS->LocateHandleBuffer ( - ByProtocol, - Id, - NULL, - &HandleCount, - &HandleBuffer - ); + Status = gBS->LocateHandleBuffer ( + ByProtocol, + Id, + NULL, + &HandleCount, + &HandleBuffer + ); if (EFI_ERROR (Status)) { return Status; } @@ -747,11 +1011,11 @@ VisitAllInstancesOfProtocol ( continue; } - Status = (*CallBackFunction) ( - HandleBuffer[Index], - Instance, - Context - ); + Status = (*CallBackFunction)( + HandleBuffer[Index], + Instance, + Context + ); } gBS->FreePool (HandleBuffer); @@ -759,7 +1023,6 @@ VisitAllInstancesOfProtocol ( return EFI_SUCCESS; } - EFI_STATUS EFIAPI VisitingAPciInstance ( @@ -768,49 +1031,45 @@ VisitingAPciInstance ( IN VOID *Context ) { - EFI_STATUS Status; - EFI_PCI_IO_PROTOCOL *PciIo; - PCI_TYPE00 Pci; + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + PCI_TYPE00 Pci; - PciIo = (EFI_PCI_IO_PROTOCOL*) Instance; + PciIo = (EFI_PCI_IO_PROTOCOL *)Instance; // // Check for all PCI device // Status = PciIo->Pci.Read ( - PciIo, - EfiPciIoWidthUint32, - 0, - sizeof (Pci) / sizeof (UINT32), - &Pci - ); + PciIo, + EfiPciIoWidthUint32, + 0, + sizeof (Pci) / sizeof (UINT32), + &Pci + ); if (EFI_ERROR (Status)) { return Status; } - return (*(VISIT_PCI_INSTANCE_CALLBACK)(UINTN) Context) ( - Handle, - PciIo, - &Pci - ); - + return (*(VISIT_PCI_INSTANCE_CALLBACK)(UINTN)Context)( + Handle, + PciIo, + &Pci + ); } - - EFI_STATUS VisitAllPciInstances ( - IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction + IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction ) { return VisitAllInstancesOfProtocol ( &gEfiPciIoProtocolGuid, VisitingAPciInstance, - (VOID*)(UINTN) CallBackFunction + (VOID *)(UINTN)CallBackFunction ); } - /** Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut. @@ -819,7 +1078,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. **/ @@ -831,45 +1091,45 @@ DetectAndPreparePlatformPciDevicePath ( IN PCI_TYPE00 *Pci ) { - EFI_STATUS Status; + EFI_STATUS Status; Status = PciIo->Attributes ( - PciIo, - EfiPciIoAttributeOperationEnable, - EFI_PCI_DEVICE_ENABLE, - NULL - ); + PciIo, + EfiPciIoAttributeOperationEnable, + EFI_PCI_DEVICE_ENABLE, + NULL + ); 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; } // @@ -879,7 +1139,7 @@ DetectAndPreparePlatformPciDevicePath ( // // Add them to ConOut. // - DEBUG ((EFI_D_INFO, "Found PCI display device\n")); + DEBUG ((DEBUG_INFO, "Found PCI display device\n")); PreparePciDisplayDevicePath (Handle); return EFI_SUCCESS; } @@ -887,86 +1147,63 @@ DetectAndPreparePlatformPciDevicePath ( return Status; } - /** - 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 + 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 - Predefined platform default console device array. ---*/ { - UINTN Index; - EFI_DEVICE_PATH_PROTOCOL *VarConout; - EFI_DEVICE_PATH_PROTOCOL *VarConin; + UINTN Index; // - // 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 minimum 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); } } - /** Configure PCI Interrupt Line register for applicable devices Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq() @@ -997,15 +1234,15 @@ SetPciIntLine ( Status = EFI_SUCCESS; if (PciHdr->Device.InterruptPin != 0) { - DevPathNode = DevicePathFromHandle (Handle); ASSERT (DevPathNode != NULL); DevPath = DevPathNode; RootBusNumber = 0; - if (DevicePathType (DevPathNode) == ACPI_DEVICE_PATH && - DevicePathSubType (DevPathNode) == ACPI_DP && - ((ACPI_HID_DEVICE_PATH *)DevPathNode)->HID == EISA_PNP_ID(0x0A03)) { + if ((DevicePathType (DevPathNode) == ACPI_DEVICE_PATH) && + (DevicePathSubType (DevPathNode) == ACPI_DP) && + (((ACPI_HID_DEVICE_PATH *)DevPathNode)->HID == EISA_PNP_ID (0x0A03))) + { RootBusNumber = ((ACPI_HID_DEVICE_PATH *)DevPathNode)->UID; } @@ -1013,13 +1250,13 @@ SetPciIntLine ( // Compute index into PciHostIrqs[] table by walking // the device path and adding up all device numbers // - Status = EFI_NOT_FOUND; + Status = EFI_NOT_FOUND; RootSlot = 0; - Idx = PciHdr->Device.InterruptPin - 1; + Idx = PciHdr->Device.InterruptPin - 1; while (!IsDevicePathEnd (DevPathNode)) { - if (DevicePathType (DevPathNode) == HARDWARE_DEVICE_PATH && - DevicePathSubType (DevPathNode) == HW_PCI_DP) { - + if ((DevicePathType (DevPathNode) == HARDWARE_DEVICE_PATH) && + (DevicePathSubType (DevPathNode) == HW_PCI_DP)) + { Idx += ((PCI_DEVICE_PATH *)DevPathNode)->Device; // @@ -1030,19 +1267,21 @@ SetPciIntLine ( // Q35 cases with more than 24 slots on the root bus. // if (Status != EFI_SUCCESS) { - Status = EFI_SUCCESS; + Status = EFI_SUCCESS; RootSlot = ((PCI_DEVICE_PATH *)DevPathNode)->Device; } } DevPathNode = NextDevicePathNode (DevPathNode); } + if (EFI_ERROR (Status)) { return Status; } - if (RootBusNumber == 0 && RootSlot == 0) { - DEBUG(( - EFI_D_ERROR, + + if ((RootBusNumber == 0) && (RootSlot == 0)) { + DEBUG (( + DEBUG_ERROR, "%a: PCI host bridge (00:00.0) should have no interrupts!\n", __FUNCTION__ )); @@ -1073,29 +1312,39 @@ SetPciIntLine ( // Idx -= RootSlot; } + break; default: ASSERT (FALSE); // should never get here } - Idx %= ARRAY_SIZE (PciHostIrqs); + + Idx %= ARRAY_SIZE (PciHostIrqs); IrqLine = PciHostIrqs[Idx]; DEBUG_CODE_BEGIN (); { - CHAR16 *DevPathString; - STATIC CHAR16 Fallback[] = L""; - UINTN Segment, Bus, Device, Function; + CHAR16 *DevPathString; + STATIC CHAR16 Fallback[] = L""; + UINTN Segment, Bus, Device, Function; DevPathString = ConvertDevicePathToText (DevPath, FALSE, FALSE); if (DevPathString == NULL) { DevPathString = Fallback; } + 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__, - (UINT32)Bus, (UINT32)Device, (UINT32)Function, DevPathString, - IrqLine)); + DEBUG (( + DEBUG_VERBOSE, + "%a: [%02x:%02x.%x] %s -> 0x%02x\n", + __FUNCTION__, + (UINT32)Bus, + (UINT32)Device, + (UINT32)Function, + DevPathString, + IrqLine + )); if (DevPathString != Fallback) { FreePool (DevPathString); @@ -1107,18 +1356,17 @@ SetPciIntLine ( // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx] // Status = PciIo->Pci.Write ( - PciIo, - EfiPciIoWidthUint8, - PCI_INT_LINE_OFFSET, - 1, - &IrqLine - ); + PciIo, + EfiPciIoWidthUint8, + PCI_INT_LINE_OFFSET, + 1, + &IrqLine + ); } return Status; } - VOID PciAcpiInitialization ( ) @@ -1135,28 +1383,42 @@ 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: + case CLOUDHV_DEVICE_ID: + return; default: - DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n", - __FUNCTION__, mHostBridgeDevId)); + 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; } @@ -1172,38 +1434,6 @@ PciAcpiInitialization ( IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0); } -/** - This function detects if OVMF is running on Xen. - -**/ -STATIC -BOOLEAN -XenDetected ( - VOID - ) -{ - EFI_HOB_GUID_TYPE *GuidHob; - STATIC INTN FoundHob = -1; - - if (FoundHob == 0) { - return FALSE; - } else if (FoundHob == 1) { - return TRUE; - } - - // - // See if a XenInfo HOB is available - // - GuidHob = GetFirstGuidHob (&gEfiXenInfoGuid); - if (GuidHob == NULL) { - FoundHob = 0; - return FALSE; - } - - FoundHob = 1; - return TRUE; -} - EFI_STATUS EFIAPI ConnectRecursivelyIfPciMassStorage ( @@ -1220,13 +1450,14 @@ ConnectRecursivelyIfPciMassStorage ( // Recognize PCI Mass Storage, and Xen PCI devices // if (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE) || - (XenDetected() && IS_CLASS2 (PciHeader, 0xFF, 0x80))) { + (XenDetected () && IS_CLASS2 (PciHeader, 0xFF, 0x80))) + { DevicePath = NULL; - Status = gBS->HandleProtocol ( - Handle, - &gEfiDevicePathProtocolGuid, - (VOID*)&DevicePath - ); + Status = gBS->HandleProtocol ( + Handle, + &gEfiDevicePathProtocolGuid, + (VOID *)&DevicePath + ); if (EFI_ERROR (Status)) { return Status; } @@ -1236,26 +1467,27 @@ ConnectRecursivelyIfPciMassStorage ( // DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE); if (DevPathStr != NULL) { - DEBUG(( - EFI_D_INFO, + DEBUG (( + DEBUG_INFO, "Found %s device: %s\n", - IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE) ? L"Mass Storage" : L"Xen", + (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE) ? + L"Mass Storage" : + L"Xen" + ), DevPathStr )); - FreePool(DevPathStr); + FreePool (DevPathStr); } Status = gBS->ConnectController (Handle, NULL, NULL, TRUE); if (EFI_ERROR (Status)) { return Status; } - } return EFI_SUCCESS; } - /** This notification function is invoked when the EMU Variable FVB has been changed. @@ -1267,15 +1499,14 @@ ConnectRecursivelyIfPciMassStorage ( VOID EFIAPI EmuVariablesUpdatedCallback ( - IN EFI_EVENT Event, - IN VOID *Context + IN EFI_EVENT Event, + IN VOID *Context ) { - DEBUG ((EFI_D_INFO, "EmuVariablesUpdatedCallback\n")); + DEBUG ((DEBUG_INFO, "EmuVariablesUpdatedCallback\n")); UpdateNvVarsOnFileSystem (); } - EFI_STATUS EFIAPI VisitingFileSystemInstance ( @@ -1298,7 +1529,7 @@ VisitingFileSystemInstance ( } ConnectedToFileSystem = TRUE; - mEmuVariableEvent = + mEmuVariableEvent = EfiCreateProtocolNotifyEvent ( &gEfiDevicePathProtocolGuid, TPL_CALLBACK, @@ -1306,14 +1537,15 @@ VisitingFileSystemInstance ( NULL, &mEmuVariableEventReg ); - PcdStatus = PcdSet64S (PcdEmuVariableEvent, - (UINT64)(UINTN) mEmuVariableEvent); + PcdStatus = PcdSet64S ( + PcdEmuVariableEvent, + (UINT64)(UINTN)mEmuVariableEvent + ); ASSERT_RETURN_ERROR (PcdStatus); return EFI_SUCCESS; } - VOID PlatformBdsRestoreNvVarsFromHardDisk ( ) @@ -1324,33 +1556,22 @@ PlatformBdsRestoreNvVarsFromHardDisk ( VisitingFileSystemInstance, NULL ); - } +/** + Connect with predefined platform connect sequence. + + The OEM/IBV can customize with their own connect sequence. +**/ VOID PlatformBdsConnectSequence ( VOID ) -/*++ - -Routine Description: - - Connect with predefined 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; @@ -1367,13 +1588,14 @@ Returns: Index++; } - // - // Just use the simple policy to connect all devices - // - DEBUG ((EFI_D_INFO, "EfiBootManagerConnectAll\n")); - EfiBootManagerConnectAll (); - - PciAcpiInitialization (); + Status = ConnectDevicesFromQemu (); + if (RETURN_ERROR (Status)) { + // + // Just use the simple policy to connect all devices + // + DEBUG ((DEBUG_INFO, "EfiBootManagerConnectAll\n")); + EfiBootManagerConnectAll (); + } } /** @@ -1388,12 +1610,15 @@ SaveS3BootScript ( VOID ) { - EFI_STATUS Status; - EFI_S3_SAVE_STATE_PROTOCOL *BootScript; - STATIC CONST UINT8 Info[] = { 0xDE, 0xAD, 0xBE, 0xEF }; + EFI_STATUS Status; + EFI_S3_SAVE_STATE_PROTOCOL *BootScript; + STATIC CONST UINT8 Info[] = { 0xDE, 0xAD, 0xBE, 0xEF }; - Status = gBS->LocateProtocol (&gEfiS3SaveStateProtocolGuid, NULL, - (VOID **) &BootScript); + Status = gBS->LocateProtocol ( + &gEfiS3SaveStateProtocolGuid, + NULL, + (VOID **)&BootScript + ); ASSERT_EFI_ERROR (Status); // @@ -1401,35 +1626,44 @@ SaveS3BootScript ( // implementation embeds a deep copy of the info in the boot script, rather // than storing just a pointer to runtime or NVS storage. // - Status = BootScript->Write(BootScript, EFI_BOOT_SCRIPT_INFORMATION_OPCODE, - (UINT32) sizeof Info, - (EFI_PHYSICAL_ADDRESS)(UINTN) &Info); + Status = BootScript->Write ( + BootScript, + EFI_BOOT_SCRIPT_INFORMATION_OPCODE, + (UINT32)sizeof Info, + (EFI_PHYSICAL_ADDRESS)(UINTN)&Info + ); ASSERT_EFI_ERROR (Status); } +/** + 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 execute with as the platform policy, current policy - is driven by boot mode. IBV/OEM can customize this code for their specific - policy action. - ---*/ { - EFI_BOOT_MODE BootMode; + 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 " - "from disk since flash variables appear to be supported.\n")); + DEBUG (( + DEBUG_INFO, + "PlatformBdsPolicyBehavior: not restoring NvVars " + "from disk since flash variables appear to be supported.\n" + )); } else { // // Try to restore variables from the hard disk early so @@ -1442,7 +1676,7 @@ Routine Description: // Get current Boot Mode // BootMode = GetBootModeHob (); - DEBUG ((EFI_D_ERROR, "Boot Mode:%x\n", BootMode)); + DEBUG ((DEBUG_INFO, "Boot Mode:%x\n", BootMode)); // // Go the different platform policy with different boot mode @@ -1456,26 +1690,40 @@ Routine Description: BootLogoEnableLogo (); // - // Perform some platform specific connect sequence + // Set PCI Interrupt Line registers and ACPI SCI_EN // - PlatformBdsConnectSequence (); + PciAcpiInitialization (); + + // + // Write qemu bootorder to efi variables + // + StoreQemuBootOrder (); // // Process QEMU's -kernel command line option // TryRunningQemuKernel (); + // + // Perform some platform specific connect sequence + // + PlatformBdsConnectSequence (); + EfiBootManagerRefreshAllBootOption (); // // Register UEFI Shell // PlatformRegisterFvBootOption ( - PcdGetPtr (PcdShellFile), L"EFI Internal Shell", LOAD_OPTION_ACTIVE + &gUefiShellFileGuid, + L"EFI Internal Shell", + LOAD_OPTION_ACTIVE ); RemoveStaleFvFileOptions (); SetBootOrderFromQemu (); + + PlatformBmPrintScRegisterHandler (); } /** @@ -1489,31 +1737,31 @@ Routine Description: VOID EFIAPI NotifyDevPath ( - IN EFI_EVENT Event, - IN VOID *Context + IN EFI_EVENT Event, + IN VOID *Context ) { - EFI_HANDLE Handle; - EFI_STATUS Status; - UINTN BufferSize; - EFI_DEVICE_PATH_PROTOCOL *DevPathNode; - ATAPI_DEVICE_PATH *Atapi; + EFI_HANDLE Handle; + EFI_STATUS Status; + UINTN BufferSize; + EFI_DEVICE_PATH_PROTOCOL *DevPathNode; + ATAPI_DEVICE_PATH *Atapi; // // Examine all new handles // - for (;;) { + for ( ; ;) { // // Get the next handle // BufferSize = sizeof (Handle); - Status = gBS->LocateHandle ( - ByRegisterNotify, - NULL, - mEfiDevPathNotifyReg, - &BufferSize, - &Handle - ); + Status = gBS->LocateHandle ( + ByRegisterNotify, + NULL, + mEfiDevPathNotifyReg, + &BufferSize, + &Handle + ); // // If not found, we're done @@ -1529,7 +1777,11 @@ 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)) { @@ -1537,16 +1789,17 @@ NotifyDevPath ( // Find the handler to dump this device path node // if ( - (DevicePathType(DevPathNode) == MESSAGING_DEVICE_PATH) && - (DevicePathSubType(DevPathNode) == MSG_ATAPI_DP) - ) { - Atapi = (ATAPI_DEVICE_PATH*) DevPathNode; + (DevicePathType (DevPathNode) == MESSAGING_DEVICE_PATH) && + (DevicePathSubType (DevPathNode) == MSG_ATAPI_DP) + ) + { + Atapi = (ATAPI_DEVICE_PATH *)DevPathNode; PciOr16 ( PCI_LIB_ADDRESS ( 0, 1, 1, - (Atapi->PrimarySecondary == 1) ? 0x42: 0x40 + (Atapi->PrimarySecondary == 1) ? 0x42 : 0x40 ), BIT15 ); @@ -1562,38 +1815,47 @@ NotifyDevPath ( return; } - VOID InstallDevicePathCallback ( VOID ) { - DEBUG ((EFI_D_INFO, "Registered NotifyDevPath Event\n")); + DEBUG ((DEBUG_INFO, "Registered NotifyDevPath Event\n")); mEfiDevPathEvent = EfiCreateProtocolNotifyEvent ( - &gEfiDevicePathProtocolGuid, - TPL_CALLBACK, - NotifyDevPath, - NULL, - &mEfiDevPathNotifyReg - ); + &gEfiDevicePathProtocolGuid, + TPL_CALLBACK, + NotifyDevPath, + NULL, + &mEfiDevPathNotifyReg + ); } /** - 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. **/ VOID EFIAPI PlatformBootManagerWaitCallback ( - UINT16 TimeoutRemain + UINT16 TimeoutRemain ) { - EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black; - EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White; - UINT16 Timeout; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White; + UINT16 TimeoutInitial; - Timeout = PcdGet16 (PcdPlatformBootTimeOut); + 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; @@ -1603,8 +1865,68 @@ PlatformBootManagerWaitCallback ( Black.Pixel, L"Start boot option", White.Pixel, - (Timeout - TimeoutRemain) * 100 / Timeout, + (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); + } +}