\r
Copyright (C) 2015-2016, Red Hat, Inc.\r
Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>\r
- Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>\r
+ Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>\r
\r
- This program and the accompanying materials are licensed and made available\r
- under the terms and conditions of the BSD License which accompanies this\r
- distribution. The full text of the license may be found at\r
- http://opensource.org/licenses/bsd-license.php\r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
- WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
#include <IndustryStandard/Pci22.h>\r
+#include <IndustryStandard/Virtio095.h>\r
#include <Library/BootLogoLib.h>\r
#include <Library/DevicePathLib.h>\r
#include <Library/PcdLib.h>\r
+#include <Library/PlatformBmPrintScLib.h>\r
#include <Library/QemuBootOrderLib.h>\r
+#include <Library/TpmPlatformHierarchyLib.h>\r
#include <Library/UefiBootManagerLib.h>\r
#include <Protocol/DevicePath.h>\r
#include <Protocol/FirmwareVolume2.h>\r
#include <Protocol/LoadedImage.h>\r
#include <Protocol/PciIo.h>\r
#include <Protocol/PciRootBridgeIo.h>\r
+#include <Protocol/VirtioDevice.h>\r
#include <Guid/EventGroup.h>\r
+#include <Guid/GlobalVariable.h>\r
#include <Guid/RootBridgesConnectedEventGroup.h>\r
+#include <Guid/SerialPortLibVendor.h>\r
\r
#include "PlatformBm.h"\r
\r
} PLATFORM_SERIAL_CONSOLE;\r
#pragma pack ()\r
\r
-#define SERIAL_DXE_FILE_GUID { \\r
- 0xD3987D4B, 0x971A, 0x435F, \\r
- { 0x8C, 0xAF, 0x49, 0x67, 0xEB, 0x62, 0x72, 0x41 } \\r
- }\r
-\r
STATIC PLATFORM_SERIAL_CONSOLE mSerialConsole = {\r
//\r
// VENDOR_DEVICE_PATH SerialDxe\r
//\r
{\r
{ HARDWARE_DEVICE_PATH, HW_VENDOR_DP, DP_NODE_LEN (VENDOR_DEVICE_PATH) },\r
- SERIAL_DXE_FILE_GUID\r
+ EDKII_SERIAL_PORT_LIB_VENDOR_GUID\r
},\r
\r
//\r
//\r
// This is not an error, just an informative condition.\r
//\r
- DEBUG ((EFI_D_VERBOSE, "%a: %g: %r\n", __FUNCTION__, ProtocolGuid,\r
+ DEBUG ((DEBUG_VERBOSE, "%a: %g: %r\n", __FUNCTION__, ProtocolGuid,\r
Status));\r
return;\r
}\r
Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0 /* Offset */,\r
sizeof Pci / sizeof (UINT32), &Pci);\r
if (EFI_ERROR (Status)) {\r
- DEBUG ((EFI_D_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status));\r
+ DEBUG ((DEBUG_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status));\r
return FALSE;\r
}\r
\r
}\r
\r
\r
+/**\r
+ This FILTER_FUNCTION checks if a handle corresponds to a Virtio RNG device at\r
+ the VIRTIO_DEVICE_PROTOCOL level.\r
+**/\r
+STATIC\r
+BOOLEAN\r
+EFIAPI\r
+IsVirtioRng (\r
+ IN EFI_HANDLE Handle,\r
+ IN CONST CHAR16 *ReportText\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ VIRTIO_DEVICE_PROTOCOL *VirtIo;\r
+\r
+ Status = gBS->HandleProtocol (Handle, &gVirtioDeviceProtocolGuid,\r
+ (VOID**)&VirtIo);\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ }\r
+ return (BOOLEAN)(VirtIo->SubSystemDeviceId ==\r
+ VIRTIO_SUBSYSTEM_ENTROPY_SOURCE);\r
+}\r
+\r
+\r
+/**\r
+ This FILTER_FUNCTION checks if a handle corresponds to a Virtio RNG device at\r
+ the EFI_PCI_IO_PROTOCOL level.\r
+**/\r
+STATIC\r
+BOOLEAN\r
+EFIAPI\r
+IsVirtioPciRng (\r
+ IN EFI_HANDLE Handle,\r
+ IN CONST CHAR16 *ReportText\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT16 VendorId;\r
+ UINT16 DeviceId;\r
+ UINT8 RevisionId;\r
+ BOOLEAN Virtio10;\r
+ UINT16 SubsystemId;\r
+\r
+ Status = gBS->HandleProtocol (Handle, &gEfiPciIoProtocolGuid,\r
+ (VOID**)&PciIo);\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Read and check VendorId.\r
+ //\r
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PCI_VENDOR_ID_OFFSET,\r
+ 1, &VendorId);\r
+ if (EFI_ERROR (Status)) {\r
+ goto PciError;\r
+ }\r
+ if (VendorId != VIRTIO_VENDOR_ID) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Read DeviceId and RevisionId.\r
+ //\r
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PCI_DEVICE_ID_OFFSET,\r
+ 1, &DeviceId);\r
+ if (EFI_ERROR (Status)) {\r
+ goto PciError;\r
+ }\r
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, PCI_REVISION_ID_OFFSET,\r
+ 1, &RevisionId);\r
+ if (EFI_ERROR (Status)) {\r
+ goto PciError;\r
+ }\r
+\r
+ //\r
+ // From DeviceId and RevisionId, determine whether the device is a\r
+ // modern-only Virtio 1.0 device. In case of Virtio 1.0, DeviceId can\r
+ // immediately be restricted to VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and\r
+ // SubsystemId will only play a sanity-check role. Otherwise, DeviceId can\r
+ // only be sanity-checked, and SubsystemId will decide.\r
+ //\r
+ if (DeviceId == 0x1040 + VIRTIO_SUBSYSTEM_ENTROPY_SOURCE &&\r
+ RevisionId >= 0x01) {\r
+ Virtio10 = TRUE;\r
+ } else if (DeviceId >= 0x1000 && DeviceId <= 0x103F && RevisionId == 0x00) {\r
+ Virtio10 = FALSE;\r
+ } else {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Read and check SubsystemId as dictated by Virtio10.\r
+ //\r
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16,\r
+ PCI_SUBSYSTEM_ID_OFFSET, 1, &SubsystemId);\r
+ if (EFI_ERROR (Status)) {\r
+ goto PciError;\r
+ }\r
+ if (Virtio10 && SubsystemId >= 0x40) {\r
+ return TRUE;\r
+ }\r
+ if (!Virtio10 && SubsystemId == VIRTIO_SUBSYSTEM_ENTROPY_SOURCE) {\r
+ return TRUE;\r
+ }\r
+ return FALSE;\r
+\r
+PciError:\r
+ DEBUG ((DEBUG_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status));\r
+ return FALSE;\r
+}\r
+\r
+\r
/**\r
This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking\r
the matching driver to produce all first-level child handles.\r
NULL, // RemainingDevicePath -- produce all children\r
FALSE // Recursive\r
);\r
- DEBUG ((EFI_ERROR (Status) ? EFI_D_ERROR : EFI_D_VERBOSE, "%a: %s: %r\n",\r
+ DEBUG ((EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE, "%a: %s: %r\n",\r
__FUNCTION__, ReportText, Status));\r
}\r
\r
\r
DevicePath = DevicePathFromHandle (Handle);\r
if (DevicePath == NULL) {\r
- DEBUG ((EFI_D_ERROR, "%a: %s: handle %p: device path not found\n",\r
+ DEBUG ((DEBUG_ERROR, "%a: %s: handle %p: device path not found\n",\r
__FUNCTION__, ReportText, Handle));\r
return;\r
}\r
\r
Status = EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
if (EFI_ERROR (Status)) {\r
- DEBUG ((EFI_D_ERROR, "%a: %s: adding to ConOut: %r\n", __FUNCTION__,\r
+ DEBUG ((DEBUG_ERROR, "%a: %s: adding to ConOut: %r\n", __FUNCTION__,\r
ReportText, Status));\r
return;\r
}\r
\r
Status = EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
if (EFI_ERROR (Status)) {\r
- DEBUG ((EFI_D_ERROR, "%a: %s: adding to ErrOut: %r\n", __FUNCTION__,\r
+ DEBUG ((DEBUG_ERROR, "%a: %s: adding to ErrOut: %r\n", __FUNCTION__,\r
ReportText, Status));\r
return;\r
}\r
\r
- DEBUG ((EFI_D_VERBOSE, "%a: %s: added to ConOut and ErrOut\n", __FUNCTION__,\r
+ DEBUG ((DEBUG_VERBOSE, "%a: %s: added to ConOut and ErrOut\n", __FUNCTION__,\r
ReportText));\r
}\r
\r
DevicePathString = ConvertDevicePathToText(BootOptions[Index].FilePath,\r
FALSE, FALSE);\r
DEBUG ((\r
- EFI_ERROR (Status) ? EFI_D_WARN : EFI_D_VERBOSE,\r
+ EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_VERBOSE,\r
"%a: removing stale Boot#%04x %s: %r\n",\r
__FUNCTION__,\r
(UINT32)BootOptions[Index].OptionNumber,\r
VOID\r
)\r
{\r
+ UINT16 FrontPageTimeout;\r
+ RETURN_STATUS PcdStatus;\r
+ EFI_STATUS Status;\r
+\r
//\r
// Signal EndOfDxe PI Event\r
//\r
EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);\r
\r
+ //\r
+ // Disable the TPM 2 platform hierarchy\r
+ //\r
+ ConfigureTpmPlatformHierarchy ();\r
+\r
+ //\r
+ // Dispatch deferred images after EndOfDxe event.\r
+ //\r
+ EfiBootManagerDispatchDeferredImages ();\r
+\r
//\r
// Locate the PCI root bridges and make the PCI bus driver connect each,\r
// non-recursively. This will produce a number of child handles with PciIo on\r
//\r
// Set the front page timeout from the QEMU configuration.\r
//\r
- PcdSet16 (PcdPlatformBootTimeOut, GetFrontPageTimeoutFromQemu ());\r
+ FrontPageTimeout = GetFrontPageTimeoutFromQemu ();\r
+ PcdStatus = PcdSet16S (PcdPlatformBootTimeOut, FrontPageTimeout);\r
+ ASSERT_RETURN_ERROR (PcdStatus);\r
+ //\r
+ // Reflect the PCD in the standard Timeout variable.\r
+ //\r
+ Status = gRT->SetVariable (\r
+ EFI_TIME_OUT_VARIABLE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ (EFI_VARIABLE_NON_VOLATILE |\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |\r
+ EFI_VARIABLE_RUNTIME_ACCESS),\r
+ sizeof FrontPageTimeout,\r
+ &FrontPageTimeout\r
+ );\r
+ DEBUG ((\r
+ EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE,\r
+ "%a: SetVariable(%s, %u): %r\n",\r
+ __FUNCTION__,\r
+ EFI_TIME_OUT_VARIABLE_NAME,\r
+ FrontPageTimeout,\r
+ Status\r
+ ));\r
\r
//\r
// Register platform-specific boot options and keyboard shortcuts.\r
//\r
PlatformRegisterOptionsAndKeys ();\r
+\r
+ //\r
+ // At this point, VIRTIO_DEVICE_PROTOCOL instances exist only for Virtio MMIO\r
+ // transports. Install EFI_RNG_PROTOCOL instances on Virtio MMIO RNG devices.\r
+ //\r
+ FilterAndProcess (&gVirtioDeviceProtocolGuid, IsVirtioRng, Connect);\r
+\r
+ //\r
+ // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL\r
+ // instances on Virtio PCI RNG devices.\r
+ //\r
+ FilterAndProcess (&gEfiPciIoProtocolGuid, IsVirtioPciRng, Connect);\r
}\r
\r
/**\r
Do the platform specific action after the console is ready\r
Possible things that can be done in PlatformBootManagerAfterConsole:\r
> Console post action:\r
- > Dynamically switch output mode from 100x31 to 80x25 for certain senarino\r
+ > Dynamically switch output mode from 100x31 to 80x25 for certain scenario\r
> Signal console ready platform customized event\r
> Run diagnostics like memory testing\r
> Connect certain devices\r
- > Dispatch aditional option roms\r
+ > Dispatch additional option roms\r
> Special boot: e.g.: USB boot, enter UI\r
**/\r
VOID\r
VOID\r
)\r
{\r
+ RETURN_STATUS Status;\r
+\r
//\r
// Show the splash screen.\r
//\r
- BootLogoEnableLogo (\r
- ImageFormatBmp, // ImageFormat\r
- PcdGetPtr (PcdLogoFile), // Logo\r
- EdkiiPlatformLogoDisplayAttributeCenter, // Attribute\r
- 0, // OffsetX\r
- 0 // OffsetY\r
- );\r
+ BootLogoEnableLogo ();\r
\r
//\r
- // Connect the rest of the devices.\r
+ // Process QEMU's -kernel command line option. The kernel booted this way\r
+ // will receive ACPI tables: in PlatformBootManagerBeforeConsole(), we\r
+ // connected any and all PCI root bridges, and then signaled the ACPI\r
+ // platform driver.\r
//\r
- EfiBootManagerConnectAll ();\r
+ TryRunningQemuKernel ();\r
\r
//\r
- // Process QEMU's -kernel command line option. Note that the kernel booted\r
- // this way should receive ACPI tables, which is why we connect all devices\r
- // first (see above) -- PCI enumeration blocks ACPI table installation, if\r
- // there is a PCI host.\r
+ // Connect the purported boot devices.\r
//\r
- TryRunningQemuKernel ();\r
+ Status = ConnectDevicesFromQemu ();\r
+ if (RETURN_ERROR (Status)) {\r
+ //\r
+ // Connect the rest of the devices.\r
+ //\r
+ EfiBootManagerConnectAll ();\r
+ }\r
\r
//\r
// Enumerate all possible boot options, then filter and reorder them based on\r
// Register UEFI Shell\r
//\r
PlatformRegisterFvBootOption (\r
- PcdGetPtr (PcdShellFile), L"EFI Internal Shell", LOAD_OPTION_ACTIVE\r
+ &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE\r
);\r
\r
RemoveStaleFvFileOptions ();\r
SetBootOrderFromQemu ();\r
+\r
+ PlatformBmPrintScRegisterHandler ();\r
}\r
\r
/**\r
{\r
EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;\r
EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;\r
- UINT16 Timeout;\r
+ UINT16 TimeoutInitial;\r
\r
- Timeout = PcdGet16 (PcdPlatformBootTimeOut);\r
+ TimeoutInitial = PcdGet16 (PcdPlatformBootTimeOut);\r
+\r
+ //\r
+ // If PcdPlatformBootTimeOut is set to zero, then we consider\r
+ // that no progress update should be enacted.\r
+ //\r
+ if (TimeoutInitial == 0) {\r
+ return;\r
+ }\r
\r
Black.Raw = 0x00000000;\r
White.Raw = 0x00FFFFFF;\r
Black.Pixel,\r
L"Start boot option",\r
White.Pixel,\r
- (Timeout - TimeoutRemain) * 100 / Timeout,\r
+ (TimeoutInitial - TimeoutRemain) * 100 / TimeoutInitial,\r
0\r
);\r
}\r
+\r
+/**\r
+ The function is called when no boot option could be launched,\r
+ including platform recovery options and options pointing to applications\r
+ built into firmware volumes.\r
+\r
+ If this function returns, BDS attempts to enter an infinite loop.\r
+**/\r
+VOID\r
+EFIAPI\r
+PlatformBootManagerUnableToBoot (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_INPUT_KEY Key;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;\r
+ UINTN Index;\r
+\r
+ //\r
+ // BootManagerMenu doesn't contain the correct information when return status\r
+ // is EFI_NOT_FOUND.\r
+ //\r
+ Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);\r
+ if (EFI_ERROR (Status)) {\r
+ return;\r
+ }\r
+ //\r
+ // Normally BdsDxe does not print anything to the system console, but this is\r
+ // a last resort -- the end-user will likely not see any DEBUG messages\r
+ // logged in this situation.\r
+ //\r
+ // AsciiPrint() will NULL-check gST->ConOut internally. We check gST->ConIn\r
+ // here to see if it makes sense to request and wait for a keypress.\r
+ //\r
+ if (gST->ConIn != NULL) {\r
+ AsciiPrint (\r
+ "%a: No bootable option or device was found.\n"\r
+ "%a: Press any key to enter the Boot Manager Menu.\n",\r
+ gEfiCallerBaseName,\r
+ gEfiCallerBaseName\r
+ );\r
+ Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);\r
+ ASSERT_EFI_ERROR (Status);\r
+ ASSERT (Index == 0);\r
+\r
+ //\r
+ // Drain any queued keys.\r
+ //\r
+ while (!EFI_ERROR (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key))) {\r
+ //\r
+ // just throw away Key\r
+ //\r
+ }\r
+ }\r
+\r
+ for (;;) {\r
+ EfiBootManagerBoot (&BootManagerMenu);\r
+ }\r
+}\r