123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924 |
- /** @file
- Implementation for PlatformBootManagerLib library class interfaces.
- Copyright (C) 2015-2016, Red Hat, Inc.
- Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
- Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include <IndustryStandard/Pci22.h>
- #include <IndustryStandard/Virtio095.h>
- #include <Library/BootLogoLib.h>
- #include <Library/DevicePathLib.h>
- #include <Library/PcdLib.h>
- #include <Library/PlatformBmPrintScLib.h>
- #include <Library/QemuBootOrderLib.h>
- #include <Library/UefiBootManagerLib.h>
- #include <Protocol/DevicePath.h>
- #include <Protocol/FirmwareVolume2.h>
- #include <Protocol/GraphicsOutput.h>
- #include <Protocol/LoadedImage.h>
- #include <Protocol/PciIo.h>
- #include <Protocol/PciRootBridgeIo.h>
- #include <Protocol/VirtioDevice.h>
- #include <Guid/EventGroup.h>
- #include <Guid/RootBridgesConnectedEventGroup.h>
- #include "PlatformBm.h"
- #define DP_NODE_LEN(Type) { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) }
- #pragma pack (1)
- typedef struct {
- VENDOR_DEVICE_PATH SerialDxe;
- UART_DEVICE_PATH Uart;
- VENDOR_DEFINED_DEVICE_PATH TermType;
- EFI_DEVICE_PATH_PROTOCOL End;
- } PLATFORM_SERIAL_CONSOLE;
- #pragma pack ()
- #define SERIAL_DXE_FILE_GUID { \
- 0xD3987D4B, 0x971A, 0x435F, \
- { 0x8C, 0xAF, 0x49, 0x67, 0xEB, 0x62, 0x72, 0x41 } \
- }
- STATIC PLATFORM_SERIAL_CONSOLE mSerialConsole = {
- //
- // VENDOR_DEVICE_PATH SerialDxe
- //
- {
- { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, DP_NODE_LEN (VENDOR_DEVICE_PATH) },
- SERIAL_DXE_FILE_GUID
- },
- //
- // UART_DEVICE_PATH Uart
- //
- {
- { MESSAGING_DEVICE_PATH, MSG_UART_DP, DP_NODE_LEN (UART_DEVICE_PATH) },
- 0, // Reserved
- FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate
- FixedPcdGet8 (PcdUartDefaultDataBits), // DataBits
- FixedPcdGet8 (PcdUartDefaultParity), // Parity
- FixedPcdGet8 (PcdUartDefaultStopBits) // StopBits
- },
- //
- // VENDOR_DEFINED_DEVICE_PATH TermType
- //
- {
- {
- MESSAGING_DEVICE_PATH, MSG_VENDOR_DP,
- DP_NODE_LEN (VENDOR_DEFINED_DEVICE_PATH)
- }
- //
- // Guid to be filled in dynamically
- //
- },
- //
- // EFI_DEVICE_PATH_PROTOCOL End
- //
- {
- END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
- DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
- }
- };
- #pragma pack (1)
- typedef struct {
- USB_CLASS_DEVICE_PATH Keyboard;
- EFI_DEVICE_PATH_PROTOCOL End;
- } PLATFORM_USB_KEYBOARD;
- #pragma pack ()
- STATIC PLATFORM_USB_KEYBOARD mUsbKeyboard = {
- //
- // USB_CLASS_DEVICE_PATH Keyboard
- //
- {
- {
- MESSAGING_DEVICE_PATH, MSG_USB_CLASS_DP,
- DP_NODE_LEN (USB_CLASS_DEVICE_PATH)
- },
- 0xFFFF, // VendorId: any
- 0xFFFF, // ProductId: any
- 3, // DeviceClass: HID
- 1, // DeviceSubClass: boot
- 1 // DeviceProtocol: keyboard
- },
- //
- // EFI_DEVICE_PATH_PROTOCOL End
- //
- {
- END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
- DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
- }
- };
- /**
- Check if the handle satisfies a particular condition.
- @param[in] Handle The handle to check.
- @param[in] ReportText A caller-allocated string passed in for reporting
- purposes. It must never be NULL.
- @retval TRUE The condition is satisfied.
- @retval FALSE Otherwise. This includes the case when the condition could not
- be fully evaluated due to an error.
- **/
- typedef
- BOOLEAN
- (EFIAPI *FILTER_FUNCTION) (
- IN EFI_HANDLE Handle,
- IN CONST CHAR16 *ReportText
- );
- /**
- Process a handle.
- @param[in] Handle The handle to process.
- @param[in] ReportText A caller-allocated string passed in for reporting
- purposes. It must never be NULL.
- **/
- typedef
- VOID
- (EFIAPI *CALLBACK_FUNCTION) (
- IN EFI_HANDLE Handle,
- IN CONST CHAR16 *ReportText
- );
- /**
- Locate all handles that carry the specified protocol, filter them with a
- callback function, and pass each handle that passes the filter to another
- callback.
- @param[in] ProtocolGuid The protocol to look for.
- @param[in] Filter The filter function to pass each handle to. If this
- parameter is NULL, then all handles are processed.
- @param[in] Process The callback function to pass each handle to that
- clears the filter.
- **/
- STATIC
- VOID
- FilterAndProcess (
- IN EFI_GUID *ProtocolGuid,
- IN FILTER_FUNCTION Filter OPTIONAL,
- IN CALLBACK_FUNCTION Process
- )
- {
- EFI_STATUS Status;
- EFI_HANDLE *Handles;
- UINTN NoHandles;
- UINTN Idx;
- Status = gBS->LocateHandleBuffer (ByProtocol, ProtocolGuid,
- NULL /* SearchKey */, &NoHandles, &Handles);
- if (EFI_ERROR (Status)) {
- //
- // This is not an error, just an informative condition.
- //
- DEBUG ((EFI_D_VERBOSE, "%a: %g: %r\n", __FUNCTION__, ProtocolGuid,
- Status));
- return;
- }
- ASSERT (NoHandles > 0);
- for (Idx = 0; Idx < NoHandles; ++Idx) {
- CHAR16 *DevicePathText;
- STATIC CHAR16 Fallback[] = L"<device path unavailable>";
- //
- // The ConvertDevicePathToText() function handles NULL input transparently.
- //
- DevicePathText = ConvertDevicePathToText (
- DevicePathFromHandle (Handles[Idx]),
- FALSE, // DisplayOnly
- FALSE // AllowShortcuts
- );
- if (DevicePathText == NULL) {
- DevicePathText = Fallback;
- }
- if (Filter == NULL || Filter (Handles[Idx], DevicePathText)) {
- Process (Handles[Idx], DevicePathText);
- }
- if (DevicePathText != Fallback) {
- FreePool (DevicePathText);
- }
- }
- gBS->FreePool (Handles);
- }
- /**
- This FILTER_FUNCTION checks if a handle corresponds to a PCI display device.
- **/
- STATIC
- BOOLEAN
- EFIAPI
- IsPciDisplay (
- IN EFI_HANDLE Handle,
- IN CONST CHAR16 *ReportText
- )
- {
- EFI_STATUS Status;
- EFI_PCI_IO_PROTOCOL *PciIo;
- PCI_TYPE00 Pci;
- Status = gBS->HandleProtocol (Handle, &gEfiPciIoProtocolGuid,
- (VOID**)&PciIo);
- if (EFI_ERROR (Status)) {
- //
- // This is not an error worth reporting.
- //
- return FALSE;
- }
- Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0 /* Offset */,
- sizeof Pci / sizeof (UINT32), &Pci);
- if (EFI_ERROR (Status)) {
- DEBUG ((EFI_D_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status));
- return FALSE;
- }
- return IS_PCI_DISPLAY (&Pci);
- }
- /**
- 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.
- **/
- STATIC
- VOID
- EFIAPI
- Connect (
- IN EFI_HANDLE Handle,
- IN CONST CHAR16 *ReportText
- )
- {
- EFI_STATUS Status;
- Status = gBS->ConnectController (
- Handle, // ControllerHandle
- NULL, // DriverImageHandle
- NULL, // RemainingDevicePath -- produce all children
- FALSE // Recursive
- );
- DEBUG ((EFI_ERROR (Status) ? EFI_D_ERROR : EFI_D_VERBOSE, "%a: %s: %r\n",
- __FUNCTION__, ReportText, Status));
- }
- /**
- This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the
- handle, and adds it to ConOut and ErrOut.
- **/
- STATIC
- VOID
- EFIAPI
- AddOutput (
- IN EFI_HANDLE Handle,
- IN CONST CHAR16 *ReportText
- )
- {
- EFI_STATUS Status;
- EFI_DEVICE_PATH_PROTOCOL *DevicePath;
- DevicePath = DevicePathFromHandle (Handle);
- if (DevicePath == NULL) {
- DEBUG ((EFI_D_ERROR, "%a: %s: handle %p: device path not found\n",
- __FUNCTION__, ReportText, Handle));
- return;
- }
- Status = EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
- if (EFI_ERROR (Status)) {
- DEBUG ((EFI_D_ERROR, "%a: %s: adding to ConOut: %r\n", __FUNCTION__,
- ReportText, Status));
- return;
- }
- Status = EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
- if (EFI_ERROR (Status)) {
- DEBUG ((EFI_D_ERROR, "%a: %s: adding to ErrOut: %r\n", __FUNCTION__,
- ReportText, Status));
- return;
- }
- DEBUG ((EFI_D_VERBOSE, "%a: %s: added to ConOut and ErrOut\n", __FUNCTION__,
- ReportText));
- }
- STATIC
- VOID
- PlatformRegisterFvBootOption (
- EFI_GUID *FileGuid,
- CHAR16 *Description,
- UINT32 Attributes
- )
- {
- EFI_STATUS Status;
- INTN OptionIndex;
- EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
- EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
- UINTN BootOptionCount;
- MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
- EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
- EFI_DEVICE_PATH_PROTOCOL *DevicePath;
- Status = gBS->HandleProtocol (
- gImageHandle,
- &gEfiLoadedImageProtocolGuid,
- (VOID **) &LoadedImage
- );
- ASSERT_EFI_ERROR (Status);
- EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
- DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);
- ASSERT (DevicePath != NULL);
- DevicePath = AppendDevicePathNode (
- DevicePath,
- (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
- );
- ASSERT (DevicePath != NULL);
- Status = EfiBootManagerInitializeLoadOption (
- &NewOption,
- LoadOptionNumberUnassigned,
- LoadOptionTypeBoot,
- Attributes,
- Description,
- DevicePath,
- NULL,
- 0
- );
- ASSERT_EFI_ERROR (Status);
- FreePool (DevicePath);
- BootOptions = EfiBootManagerGetLoadOptions (
- &BootOptionCount, LoadOptionTypeBoot
- );
- OptionIndex = EfiBootManagerFindLoadOption (
- &NewOption, BootOptions, BootOptionCount
- );
- if (OptionIndex == -1) {
- Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);
- ASSERT_EFI_ERROR (Status);
- }
- EfiBootManagerFreeLoadOption (&NewOption);
- EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
- }
- /**
- Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options
- whose device paths do not resolve exactly to an FvFile in the system.
- This removes any boot options that point to binaries built into the firmware
- and have become stale due to any of the following:
- - FvMain's base address or size changed (historical),
- - FvMain's FvNameGuid changed,
- - the FILE_GUID of the pointed-to binary changed,
- - the referenced binary is no longer built into the firmware.
- EfiBootManagerFindLoadOption() used in PlatformRegisterFvBootOption() only
- avoids exact duplicates.
- **/
- STATIC
- VOID
- RemoveStaleFvFileOptions (
- VOID
- )
- {
- EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
- UINTN BootOptionCount;
- UINTN Index;
- BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount,
- LoadOptionTypeBoot);
- for (Index = 0; Index < BootOptionCount; ++Index) {
- EFI_DEVICE_PATH_PROTOCOL *Node1, *Node2, *SearchNode;
- EFI_STATUS Status;
- EFI_HANDLE FvHandle;
- //
- // If the device path starts with neither MemoryMapped(...) nor Fv(...),
- // then keep the boot option.
- //
- Node1 = BootOptions[Index].FilePath;
- if (!(DevicePathType (Node1) == HARDWARE_DEVICE_PATH &&
- DevicePathSubType (Node1) == HW_MEMMAP_DP) &&
- !(DevicePathType (Node1) == MEDIA_DEVICE_PATH &&
- DevicePathSubType (Node1) == MEDIA_PIWG_FW_VOL_DP)) {
- continue;
- }
- //
- // If the second device path node is not FvFile(...), then keep the boot
- // option.
- //
- Node2 = NextDevicePathNode (Node1);
- if (DevicePathType (Node2) != MEDIA_DEVICE_PATH ||
- DevicePathSubType (Node2) != MEDIA_PIWG_FW_FILE_DP) {
- continue;
- }
- //
- // Locate the Firmware Volume2 protocol instance that is denoted by the
- // boot option. If this lookup fails (i.e., the boot option references a
- // firmware volume that doesn't exist), then we'll proceed to delete the
- // boot option.
- //
- SearchNode = Node1;
- Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid,
- &SearchNode, &FvHandle);
- if (!EFI_ERROR (Status)) {
- //
- // The firmware volume was found; now let's see if it contains the FvFile
- // identified by GUID.
- //
- EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol;
- MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFileNode;
- UINTN BufferSize;
- EFI_FV_FILETYPE FoundType;
- EFI_FV_FILE_ATTRIBUTES FileAttributes;
- UINT32 AuthenticationStatus;
- Status = gBS->HandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid,
- (VOID **)&FvProtocol);
- ASSERT_EFI_ERROR (Status);
- FvFileNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)Node2;
- //
- // Buffer==NULL means we request metadata only: BufferSize, FoundType,
- // FileAttributes.
- //
- Status = FvProtocol->ReadFile (
- FvProtocol,
- &FvFileNode->FvFileName, // NameGuid
- NULL, // Buffer
- &BufferSize,
- &FoundType,
- &FileAttributes,
- &AuthenticationStatus
- );
- if (!EFI_ERROR (Status)) {
- //
- // The FvFile was found. Keep the boot option.
- //
- continue;
- }
- }
- //
- // Delete the boot option.
- //
- Status = EfiBootManagerDeleteLoadOptionVariable (
- BootOptions[Index].OptionNumber, LoadOptionTypeBoot);
- DEBUG_CODE (
- CHAR16 *DevicePathString;
- DevicePathString = ConvertDevicePathToText(BootOptions[Index].FilePath,
- FALSE, FALSE);
- DEBUG ((
- EFI_ERROR (Status) ? EFI_D_WARN : EFI_D_VERBOSE,
- "%a: removing stale Boot#%04x %s: %r\n",
- __FUNCTION__,
- (UINT32)BootOptions[Index].OptionNumber,
- DevicePathString == NULL ? L"<unavailable>" : DevicePathString,
- Status
- ));
- if (DevicePathString != NULL) {
- FreePool (DevicePathString);
- }
- );
- }
- EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
- }
- STATIC
- VOID
- PlatformRegisterOptionsAndKeys (
- VOID
- )
- {
- EFI_STATUS Status;
- EFI_INPUT_KEY Enter;
- EFI_INPUT_KEY F2;
- EFI_INPUT_KEY Esc;
- EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
- //
- // Register ENTER as CONTINUE key
- //
- Enter.ScanCode = SCAN_NULL;
- Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
- Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
- ASSERT_EFI_ERROR (Status);
- //
- // Map F2 and ESC to Boot Manager Menu
- //
- F2.ScanCode = SCAN_F2;
- F2.UnicodeChar = CHAR_NULL;
- Esc.ScanCode = SCAN_ESC;
- Esc.UnicodeChar = CHAR_NULL;
- Status = EfiBootManagerGetBootManagerMenu (&BootOption);
- ASSERT_EFI_ERROR (Status);
- Status = EfiBootManagerAddKeyOptionVariable (
- NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL
- );
- ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
- Status = EfiBootManagerAddKeyOptionVariable (
- NULL, (UINT16) BootOption.OptionNumber, 0, &Esc, NULL
- );
- ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
- }
- //
- // BDS Platform Functions
- //
- /**
- Do the platform init, can be customized by OEM/IBV
- Possible things that can be done in PlatformBootManagerBeforeConsole:
- > Update console variable: 1. include hot-plug devices;
- > 2. Clear ConIn and add SOL for AMT
- > Register new Driver#### or Boot####
- > Register new Key####: e.g.: F12
- > Signal ReadyToLock event
- > Authentication action: 1. connect Auth devices;
- > 2. Identify auto logon user.
- **/
- VOID
- EFIAPI
- 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
- // them.
- //
- FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid, NULL, Connect);
- //
- // Signal the ACPI platform driver that it can download QEMU ACPI tables.
- //
- EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid);
- //
- // Find all display class PCI devices (using the handles from the previous
- // step), and connect them non-recursively. This should produce a number of
- // child handles with GOPs on them.
- //
- FilterAndProcess (&gEfiPciIoProtocolGuid, IsPciDisplay, Connect);
- //
- // Now add the device path of all handles with GOP on them to ConOut and
- // ErrOut.
- //
- FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput);
- //
- // Add the hardcoded short-form USB keyboard device path to ConIn.
- //
- EfiBootManagerUpdateConsoleVariable (ConIn,
- (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard, NULL);
- //
- // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.
- //
- CopyGuid (&mSerialConsole.TermType.Guid,
- PcdGetPtr (PcdTerminalTypeGuidBuffer));
- EfiBootManagerUpdateConsoleVariable (ConIn,
- (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
- EfiBootManagerUpdateConsoleVariable (ConOut,
- (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
- EfiBootManagerUpdateConsoleVariable (ErrOut,
- (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
- //
- // Set the front page timeout from the QEMU configuration.
- //
- 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);
- }
- /**
- 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 scenario
- > Signal console ready platform customized event
- > Run diagnostics like memory testing
- > Connect certain devices
- > Dispatch additional option roms
- > Special boot: e.g.: USB boot, enter UI
- **/
- VOID
- EFIAPI
- PlatformBootManagerAfterConsole (
- VOID
- )
- {
- RETURN_STATUS Status;
- //
- // Show the splash screen.
- //
- BootLogoEnableLogo ();
- //
- // Process QEMU's -kernel command line option. The kernel booted this way
- // will receive ACPI tables: in PlatformBootManagerBeforeConsole(), we
- // connected any and all PCI root bridges, and then signaled the ACPI
- // platform driver.
- //
- TryRunningQemuKernel ();
- //
- // Connect the purported boot devices.
- //
- Status = ConnectDevicesFromQemu ();
- if (RETURN_ERROR (Status)) {
- //
- // Connect the rest of the devices.
- //
- EfiBootManagerConnectAll ();
- }
- //
- // Enumerate all possible boot options, then filter and reorder them based on
- // the QEMU configuration.
- //
- EfiBootManagerRefreshAllBootOption ();
- //
- // Register UEFI Shell
- //
- PlatformRegisterFvBootOption (
- &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE
- );
- RemoveStaleFvFileOptions ();
- SetBootOrderFromQemu ();
- PlatformBmPrintScRegisterHandler ();
- }
- /**
- This function is called each second during the boot manager waits the
- timeout.
- @param TimeoutRemain The remaining timeout.
- **/
- VOID
- EFIAPI
- PlatformBootManagerWaitCallback (
- UINT16 TimeoutRemain
- )
- {
- EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;
- EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;
- UINT16 Timeout;
- Timeout = PcdGet16 (PcdPlatformBootTimeOut);
- Black.Raw = 0x00000000;
- White.Raw = 0x00FFFFFF;
- BootLogoUpdateProgress (
- White.Pixel,
- Black.Pixel,
- L"Start boot option",
- White.Pixel,
- (Timeout - TimeoutRemain) * 100 / Timeout,
- 0
- );
- }
- /**
- 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);
- }
- }
|