Thanks,
Chao
--------
The Library provides Boot Manager interfaces.REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4054Cc: Bibo Mao <maobibo@loongson.cn>Cc: Chao Li <lichao@loongson.cn>Cc: Leif Lindholm <quic_llindhol@quicinc.com>Cc: Liming Gao <gaoliming@byosoft.com.cn>Cc: Michael D Kinney <michael.d.kinney@intel.com>Signed-off-by: xianglai li <lixianglai@loongson.cn>---.../PlatformBootManagerLib/PlatformBm.c | 742 ++++++++++++++++++.../PlatformBootManagerLib/PlatformBm.h | 112 +++.../PlatformBootManagerLib.inf | 75 ++.../PlatformBootManagerLib/QemuKernel.c | 81 ++4 files changed, 1010 insertions(+)create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.ccreate mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.hcreate mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.infcreate mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/QemuKernel.cdiff --git a/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.c b/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.cnew file mode 100644index 0000000000..eb7f4241f0--- /dev/null+++ b/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.c@@ -0,0 +1,742 @@+/** @file+ Implementation for PlatformBootManagerLib library class interfaces.++ Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>++ SPDX-License-Identifier: BSD-2-Clause-Patent++**/++#include <IndustryStandard/Pci22.h>+#include <Library/BootLogoLib.h>+#include <Library/PcdLib.h>+#include <Library/QemuBootOrderLib.h>+#include <Library/UefiBootManagerLib.h>+#include <Protocol/FirmwareVolume2.h>+#include <Protocol/LoadedImage.h>+#include <Protocol/PciIo.h>+#include <Library/UefiBootServicesTableLib.h>+#include <Library/DebugLib.h>+#include <Library/MemoryAllocationLib.h>+#include <Library/UefiLib.h>+#include <Library/BaseMemoryLib.h>+#include "PlatformBm.h"++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)+ }+};++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)+ }+};++/**+ 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.+**/+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 ((DEBUG_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.++ @param Handle The handle to check+ @param ReportText A pointer to a string at the time of the error.++ @retval TURE THe handle corresponds to a PCI display device.+ @retval FALSE THe handle does not corresponds to a PCI display device.+**/+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 ((DEBUG_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status));+ return FALSE;+ }++ return IS_PCI_DISPLAY (&Pci);+}++/**+ This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking+ the matching driver to produce all first-level child handles.++ @param Handle The handle to connect.+ @param ReportText A pointer to a string at the time of the error.++ @retval VOID+**/+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) ? DEBUG_ERROR : DEBUG_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.++ @param Handle The handle to retrieves.+ @param ReportText A pointer to a string at the time of the error.++ @retval VOID+**/+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 ((DEBUG_ERROR, "%a: %s: handle %p: device path not found\n",+ __FUNCTION__, ReportText, Handle));+ return;+ }++ Status = EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);+ if (EFI_ERROR (Status)) {+ DEBUG ((DEBUG_ERROR, "%a: %s: adding to ConOut: %r\n", __FUNCTION__,+ ReportText, Status));+ return;+ }++ Status = EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);+ if (EFI_ERROR (Status)) {+ DEBUG ((DEBUG_ERROR, "%a: %s: adding to ErrOut: %r\n", __FUNCTION__,+ ReportText, Status));+ return;+ }++ DEBUG ((DEBUG_VERBOSE, "%a: %s: added to ConOut and ErrOut\n", __FUNCTION__,+ ReportText));+}+/**+ Register the boot option.++ @param FileGuid File Guid.+ @param Description Option descriptor.+ @param Attributes Option Attributes.++ @retval VOID+**/+VOID+PlatformRegisterFvBootOption (+ IN EFI_GUID *FileGuid,+ IN CHAR16 *Description,+ IN 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.+**/+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 : DEBUG_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);+}++/**+ Register the boot option And Keys.++ @param VOID++ @retval VOID+**/+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, &gEfiTtyTermGuid);+ 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 ();+}++/**+ 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+ )+{+ //+ // Show the splash screen.+ //+ BootLogoEnableLogo ();++ //+ // Connect the rest of the devices.+ //+ EfiBootManagerConnectAll ();++ //+ // 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.+ //+ TryRunningQemuKernel ();++ //+ // 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 ();+}++/**+ This function is called each second during the boot manager waits the+ timeout.++ @param TimeoutRemain The remaining timeout.+**/+VOID+EFIAPI+PlatformBootManagerWaitCallback (+ IN 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);+ }+}diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.h b/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.hnew file mode 100644index 0000000000..f20c78252f--- /dev/null+++ b/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.h@@ -0,0 +1,112 @@+/** @file+ Head file for BDS Platform specific code++ Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>++ SPDX-License-Identifier: BSD-2-Clause-Patent++**/++#ifndef PLATFORM_BM_H_+#define PLATFORM_BM_H_++#include <Library/DevicePathLib.h>++#define DP_NODE_LEN(Type) { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) }++#define SERIAL_DXE_FILE_GUID { \+ 0xD3987D4B, 0x971A, 0x435F, \+ { 0x8C, 0xAF, 0x49, 0x67, 0xEB, 0x62, 0x72, 0x41 } \+ }++#define ALIGN_UP(addr, align) \+ ((addr + (typeof (addr)) align - 1) & ~((typeof (addr)) align - 1))++#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 ()++#pragma pack (1)+typedef struct {+ USB_CLASS_DEVICE_PATH Keyboard;+ EFI_DEVICE_PATH_PROTOCOL End;+} PLATFORM_USB_KEYBOARD;+#pragma pack ()++/**+ 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+ );++/**+ * execute from kernel entry point.+ *+ * @param[in] Argc The count of args.+ * @param[in] Argv The pointer to args array.+ * @param[in] Bpi The pointer to bootparaminterface struct.+ * @param[in] Vec The fourth args for kernel.+ ***/+typedef+VOID+(EFIAPI *EFI_KERNEL_ENTRY_POINT) (+ IN UINTN Argc,+ IN VOID *Argv,+ IN VOID *Bpi,+ IN VOID *Vec+ );++/**+ Download the kernel, the initial ramdisk, and the kernel command line from+ QEMU's fw_cfg. Construct a minimal SimpleFileSystem that contains the two+ image files, and load and start the kernel from it.++ The kernel will be instructed via its command line to load the initrd from+ the same Simple FileSystem.++ @retval EFI_NOT_FOUND Kernel image was not found.+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.+ @retval EFI_PROTOCOL_ERROR Unterminated kernel command line.++ @return Error codes from any of the underlying+ functions. On success, the function doesn't+ return.+**/+EFI_STATUS+EFIAPI+TryRunningQemuKernel (+ VOID+ );++#endif // PLATFORM_BM_H_diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf b/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.infnew file mode 100644index 0000000000..0ea6fea5c5--- /dev/null+++ b/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf@@ -0,0 +1,75 @@+## @file+# Implementation for PlatformBootManagerLib library class interfaces.+#+# Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>+#+# SPDX-License-Identifier: BSD-2-Clause-Patent+#+##++[Defines]+ INF_VERSION = 0x00010005+ BASE_NAME = PlatformBootManagerLib+ FILE_GUID = 469184E8-FADA-41E4-8823-012CA19B40D4+ MODULE_TYPE = DXE_DRIVER+ VERSION_STRING = 1.0+ LIBRARY_CLASS = PlatformBootManagerLib|DXE_DRIVER++#+# VALID_ARCHITECTURES = LOONGARCH64+#++[Sources]+ PlatformBm.c+ QemuKernel.c++[Packages]+ Platform/Loongson/LoongArchQemuPkg/Loongson.dec+ MdeModulePkg/MdeModulePkg.dec+ MdePkg/MdePkg.dec+ OvmfPkg/OvmfPkg.dec+ ShellPkg/ShellPkg.dec++[LibraryClasses]+ BaseLib+ BaseMemoryLib+ BootLogoLib+ DebugLib+ DevicePathLib+ MemoryAllocationLib+ PcdLib+ PrintLib+ QemuBootOrderLib+ QemuLoadImageLib+ QemuFwCfgLib+ UefiBootManagerLib+ UefiBootServicesTableLib+ UefiLib+ UefiRuntimeServicesTableLib++[FixedPcd]+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits++[Pcd]+ gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut++[Guids]+ gEfiFileInfoGuid+ gEfiFileSystemInfoGuid+ gEfiFileSystemVolumeLabelInfoIdGuid+ gEfiEndOfDxeEventGroupGuid+ gRootBridgesConnectedEventGroupGuid+ gUefiShellFileGuid+ gEfiLoongsonBootparamsTableGuid ## SOMETIMES_PRODUCES ## SystemTable+ gEfiTtyTermGuid++[Protocols]+ gEfiDevicePathProtocolGuid+ gEfiFirmwareVolume2ProtocolGuid+ gEfiGraphicsOutputProtocolGuid+ gEfiLoadedImageProtocolGuid+ gEfiPciRootBridgeIoProtocolGuid+ gEfiSimpleFileSystemProtocolGuiddiff --git a/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/QemuKernel.c b/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/QemuKernel.cnew file mode 100644index 0000000000..386003a8d7--- /dev/null+++ b/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/QemuKernel.c@@ -0,0 +1,81 @@+/** @file+ Try to run Linux kernel.++ Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>++ SPDX-License-Identifier: BSD-2-Clause-Patent++ @par Glossary:+ - mem - Memory+ - Bpi - Boot Parameter Interface+ - FwCfg - FirmWare Configure+**/++#include <Library/QemuLoadImageLib.h>+#include <Library/ReportStatusCodeLib.h>++#include <Library/BaseLib.h>+#include <Library/BaseMemoryLib.h>+#include <Library/DebugLib.h>+#include <Library/DevicePathLib.h>+#include <Library/MemoryAllocationLib.h>+#include <Library/UefiBootServicesTableLib.h>+#include <Library/UefiLib.h>+#include <Library/UefiRuntimeServicesTableLib.h>++/**+ Download the kernel, the initial ramdisk, and the kernel command line from+ QEMU's fw_cfg. Construct a minimal SimpleFileSystem that contains the two+ image files, and load and start the kernel from it.++ The kernel will be instructed via its command line to load the initrd from+ the same Simple FileSystem.++ @retval EFI_NOT_FOUND Kernel image was not found.+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.+ @retval EFI_PROTOCOL_ERROR Unterminated kernel command line.++ @return Error codes from any of the underlying+ functions. On success, the function doesn't+ return.+**/+EFI_STATUS+TryRunningQemuKernel (+ VOID+ )+{+ EFI_STATUS Status;+ EFI_HANDLE KernelImageHandle;++ Status = QemuLoadKernelImage (&KernelImageHandle);+ if (EFI_ERROR (Status)) {+ return Status;+ }++ //+ // Signal the EFI_EVENT_GROUP_READY_TO_BOOT event.+ //+ EfiSignalEventReadyToBoot ();++ REPORT_STATUS_CODE (+ EFI_PROGRESS_CODE,+ (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT)+ );++ //+ // Start the image.+ //+ Status = QemuStartKernelImage (&KernelImageHandle);+ if (EFI_ERROR (Status)) {+ DEBUG ((+ DEBUG_ERROR,+ "%a: QemuStartKernelImage(): %r\n",+ __FUNCTION__,+ Status+ ));+ }++ QemuUnloadKernelImage (KernelImageHandle);++ return Status;+}--2.31.1