X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=ArmVirtPkg%2FLibrary%2FPlatformBootManagerLib%2FPlatformBm.c;h=bb07f5e22b753bd0739aa4bffe8c7257ea186ea3;hp=5d7c2a44479995e8a6e4b842112d4365fe3c7955;hb=8d1b281af3a35de4098a63dfe913efe09328acf0;hpb=e6c823994e5694daf06f94b790f7331b402d6155 diff --git a/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c b/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c index 5d7c2a4447..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 - 2016, 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,6 +16,7 @@ **/ #include +#include #include #include #include @@ -27,6 +28,7 @@ #include #include #include +#include #include #include @@ -260,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. @@ -578,11 +695,18 @@ 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 @@ -629,12 +753,26 @@ PlatformBootManagerBeforeConsole ( // // Set the front page timeout from the QEMU configuration. // - PcdSet16 (PcdPlatformBootTimeOut, GetFrontPageTimeoutFromQemu ()); + PcdStatus = PcdSet16S (PcdPlatformBootTimeOut, + GetFrontPageTimeoutFromQemu ()); + ASSERT_RETURN_ERROR (PcdStatus); // // Register platform-specific boot options and keyboard shortcuts. // PlatformRegisterOptionsAndKeys (); + + // + // At this point, VIRTIO_DEVICE_PROTOCOL instances exist only for Virtio MMIO + // transports. Install EFI_RNG_PROTOCOL instances on Virtio MMIO RNG devices. + // + FilterAndProcess (&gVirtioDeviceProtocolGuid, IsVirtioRng, Connect); + + // + // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL + // instances on Virtio PCI RNG devices. + // + FilterAndProcess (&gEfiPciIoProtocolGuid, IsVirtioPciRng, Connect); } /** @@ -654,29 +792,31 @@ PlatformBootManagerAfterConsole ( VOID ) { + RETURN_STATUS Status; + // // Show the splash screen. // - // BootLogoEnableLogo ( - // ImageFormatBmp, // ImageFormat - // PcdGetPtr (PcdLogoFile), // Logo - // EdkiiPlatformLogoDisplayAttributeCenter, // Attribute - // 0, // OffsetX - // 0 // OffsetY - // ); + BootLogoEnableLogo (); // - // Connect the rest of the devices. + // 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. // - EfiBootManagerConnectAll (); + TryRunningQemuKernel (); // - // 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. + // Connect the purported boot devices. // - TryRunningQemuKernel (); + 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 @@ -688,7 +828,7 @@ PlatformBootManagerAfterConsole ( // Register UEFI Shell // PlatformRegisterFvBootOption ( - PcdGetPtr (PcdShellFile), L"EFI Internal Shell", LOAD_OPTION_ACTIVE + &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE ); RemoveStaleFvFileOptions (); @@ -725,3 +865,63 @@ PlatformBootManagerWaitCallback ( 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); + } +}