The Library provides Boot Manager interfaces. Signed-off-by: xianglai li <lixiang...@loongson.cn> --- .../PlatformBootManagerLib/PlatformBm.c | 761 ++++++++++++++++++ .../PlatformBootManagerLib/PlatformBm.h | 126 +++ .../PlatformBootManagerLib.inf | 78 ++ .../PlatformBootManagerLib/QemuKernel.c | 449 +++++++++++ 4 files changed, 1414 insertions(+) create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.c create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.h create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/QemuKernel.c
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.c b/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.c new file mode 100644 index 0000000000..1805a6a9b3 --- /dev/null +++ b/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.c @@ -0,0 +1,761 @@ +/** @file + Implementation for PlatformBootManagerLib library class interfaces. + + Copyright (c) 2021 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. + // + DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole, func: %a, line: %d\n", __func__, __LINE__)); + BootLogoEnableLogo (); + DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole, func: %a, line: %d\n", __func__, __LINE__)); + + // + // Connect the rest of the devices. + // + DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole, func: %a, line: %d\n", __func__, __LINE__)); + EfiBootManagerConnectAll (); + DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole, func: %a, line: %d\n", __func__, __LINE__)); + + SetBootParams (); + // + // 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. + // + DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole, func: %a, line: %d\n", __func__, __LINE__)); + TryRunningQemuKernel (); + DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole, func: %a, line: %d\n", __func__, __LINE__)); + + // + // Enumerate all possible boot options, then filter and reorder them based on + // the QEMU configuration. + // + DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole, func: %a, line: %d\n", __func__, __LINE__)); + EfiBootManagerRefreshAllBootOption (); + DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole, func: %a, line: %d\n", __func__, __LINE__)); + + // + // Register UEFI Shell + // + DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole, func: %a, line: %d\n", __func__, __LINE__)); + PlatformRegisterFvBootOption ( + &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE + ); + DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole, func: %a, line: %d\n", __func__, __LINE__)); + + RemoveStaleFvFileOptions (); + DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole, func: %a, line: %d\n", __func__, __LINE__)); + SetBootOrderFromQemu (); + DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole, func: %a, line: %d\n", __func__, __LINE__)); +} + +/** + 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.h new file mode 100644 index 0000000000..5b7dd20794 --- /dev/null +++ b/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.h @@ -0,0 +1,126 @@ +/** @file + Head file for BDS Platform specific code + + Copyright (c) 2021 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 + ); + +/* + Setup the boot parameter. + + @param VOID + + @retval EFI_SUCCESS The boot parameter was established successfully. + @retval EFI_INVALID_PARAMETER Input GUID is NULL. + @retval EFI_NOT_FOUND Attempted to delete non-existant entry + @retval EFI_OUT_OF_RESOURCES Not enough memory available + */ +EFI_STATUS +EFIAPI +SetBootParams (VOID); + +#endif // _PLATFORM_BM_H_ diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf b/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf new file mode 100644 index 0000000000..0242381fc5 --- /dev/null +++ b/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf @@ -0,0 +1,78 @@ +## @file +# Implementation for PlatformBootManagerLib library class interfaces. +# +# Copyright (c) 2021 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 + +# +# The following information is for reference only and not required by the build tools. +# +# 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 + QemuFwCfgLib + UefiBootManagerLib + UefiBootServicesTableLib + UefiLib + UefiRuntimeServicesTableLib + BpiLib + +[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 + gEfiSimpleFileSystemProtocolGuid diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/QemuKernel.c b/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/QemuKernel.c new file mode 100644 index 0000000000..bb25edcada --- /dev/null +++ b/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/QemuKernel.c @@ -0,0 +1,449 @@ +/** @file + Try to run Linux kernel. + + Copyright (c) 2021 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 <Uefi.h> + +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/LoadLinuxLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/QemuFwCfgLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h> +#include <Library/Bpi.h> +#include <string.h> +#include <Library/BaseMemoryLib.h> +#include "PlatformBm.h" + +/* + Calculates the checksum. + + @param buffer A pointer to the data to calculate the checksum. + @param length The number of data involved in calculating the checksum. + + @retval the value of checksum. + */ +UINT8 +CalculateCheckSum8 ( + IN CONST UINT8 *buffer, IN UINTN length + ) +{ + UINT8 checksum; + UINTN count; + + for (checksum = 0, count = 0; count < length; count++) { + checksum = (UINT8) (checksum + * (buffer + count)); + } + return (UINT8) (0x100 - checksum); +} +/* + Iterates through all memory maps merging adjacent memory regions. + + @param array A pointer to a memory-mapped table. + @param length The length of the memory-mapped table. + @param bpmem Adjusted memory information table. + @param index The Index of Adjusted memory information table. + @param memtype Specifies the memory type. + + @retval the value of checksum. + */ +UINT32 +memmap_sort ( + IN MEMMAP array[], + IN UINT32 length, + OUT MEM_MAP * bpmem, + IN UINT32 index, + IN UINT32 memtype + ) +{ + UINT64 tempmemsize = 0; + UINT32 j = 0; + UINT32 t = 0; + + for (j = 0; j < length; ) { + tempmemsize = array[j].MemSize; + for (t = j + 1; t < length; t++) { + if (array[j].MemStart + tempmemsize == array[t].MemStart) { + tempmemsize += array[t].MemSize; + } else { + break; + } + } + + bpmem->Map[index].MemType = memtype; + bpmem->Map[index].MemStart = array[j].MemStart; + bpmem->Map[index].MemSize = tempmemsize; + DEBUG ((DEBUG_INFO, "map[%d]:type %x, start 0x%llx, end 0x%llx\n", + index, + bpmem->Map[index].MemType, + bpmem->Map[index].MemStart, + bpmem->Map[index].MemStart+ bpmem->Map[index].MemSize + )); + j = t; + index++; + } + return index; +} +/* + Look for memory-mapped information. + + @param Bpi A pointer to the boot parameter interface. + + @retval The address of the memory-mapped table. + */ +MEM_MAP * +FindNewInterfaceMem ( + IN BootParamsInterface *Bpi + ) +{ + CHAR8 *p =NULL; + MEM_MAP *new_interface_mem = NULL; + EXT_LIST *listpointer = NULL; + + if (Bpi == NULL) { + return new_interface_mem; + } + + p = (CHAR8 *)& (Bpi->Signature); + if (AsciiStrnCmp (p, "BPI", 3) == 0) { + listpointer = Bpi->ExtList; + for (; listpointer != NULL; listpointer = listpointer->next) { + CHAR8 *pl = (CHAR8 *) & (listpointer->Signature); + if (AsciiStrnCmp (pl, "MEM", 3) == 0) { + new_interface_mem = (MEM_MAP *)listpointer; + } + } + } + + return new_interface_mem; +} +/** + Gets the system memory mapping information. + + @param MapKey memory-mapped key. + @param MemoryMapSize The size of the memory-mapped information. + @param DescriptorSize The size of the memory-mapped information descriptor. + + @retval VOID +**/ +EFI_MEMORY_DESCRIPTOR * +GetSystemMemap ( + OUT UINTN *MapKey, + OUT UINTN *MemoryMapSize, + OUT UINTN *DescriptorSize + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + EFI_MEMORY_DESCRIPTOR *MemoryMap = NULL; + UINTN MemoryMapSizeTemp = 0; + UINTN DescriptorSizeTemp = 0; + UINT8 TmpMemoryMap[1]; + UINT32 DescriptorVersion = 0; + + // Get System MemoryMapSize + MemoryMapSizeTemp = sizeof (TmpMemoryMap); + Status = gBS->GetMemoryMap ( + &MemoryMapSizeTemp, + (EFI_MEMORY_DESCRIPTOR *)TmpMemoryMap, + MapKey, + &DescriptorSizeTemp, + &DescriptorVersion + ); + ASSERT (Status == EFI_BUFFER_TOO_SMALL); + + DEBUG ((DEBUG_INFO, "%a %a:%d Status 0x%x\n", __FILE__, __func__, __LINE__, Status)); + // Enlarge space here, because we will allocate pool now. + MemoryMapSizeTemp += EFI_PAGE_SIZE; + Status = gBS->AllocatePool ( + EfiLoaderData, + MemoryMapSizeTemp, + (VOID **) &MemoryMap + ); + ASSERT_EFI_ERROR (Status); + + DEBUG ((DEBUG_INFO, "%a %a:%d Status 0x%x\n", __FILE__, __func__, __LINE__, Status)); + + *MemoryMapSize = MemoryMapSizeTemp; + *DescriptorSize = DescriptorSizeTemp; + if (NULL == MemoryMap) { + return NULL; + } + + // Get System MemoryMap + Status = gBS->GetMemoryMap ( + &MemoryMapSizeTemp, + MemoryMap, + MapKey, + &DescriptorSizeTemp, + &DescriptorVersion + ); + ASSERT_EFI_ERROR (Status); + + DEBUG ((DEBUG_INFO, "%a %a:%d Status 0x%x\n", __FILE__, __func__, __LINE__, Status)); + *MemoryMapSize = MemoryMapSizeTemp; + *DescriptorSize = DescriptorSizeTemp; + + return MemoryMap; +} +/** + Memory-mapped information is processed according to the different types + of memory in the memory-mapped table. + + @param new_interface_mem A pointer to a memory-mapped table. + @param MemoryMapPtr A pointer to the memory descriptor struct. + @param MemoryMapSize The size of the memory-mapped table. + @param DescriptorSize The size of the descriptor. + + @retval VOID +**/ +VOID +MemMapSort ( + IN OUT MEM_MAP *new_interface_mem, + IN EFI_MEMORY_DESCRIPTOR *MemoryMapPtr, + IN UINTN MemoryMapSize, + IN UINTN DescriptorSize + ) +{ + MEMMAP reserve_mem[MAX_MEM_MAP]; + MEMMAP free_mem[MAX_MEM_MAP]; + MEMMAP acpi_table_mem[MAX_MEM_MAP]; + MEMMAP acpi_nvs_mem[MAX_MEM_MAP]; + UINT32 free_index = 0; + UINT32 reserve_index = 0; + UINT32 acpi_table_index = 0; + UINT32 acpi_nvs_index = 0; + UINT64 tempMemsize = 0; + UINT32 tmp_index = 0; + UINT32 Index, j, t; + UINT8 checksum = 0; + + if ((NULL == new_interface_mem) + || (NULL == MemoryMapPtr)) + { + return ; + } + + ZeroMem(reserve_mem, sizeof(MEMMAP) * MAX_MEM_MAP); + ZeroMem(free_mem, sizeof(MEMMAP) * MAX_MEM_MAP); + ZeroMem(acpi_table_mem, sizeof(MEMMAP) * MAX_MEM_MAP); + ZeroMem(acpi_nvs_mem, sizeof(MEMMAP) * MAX_MEM_MAP); + + tmp_index = new_interface_mem->MapCount; + + for (Index = 0; Index < (MemoryMapSize / DescriptorSize); Index++) { + if (MemoryMapPtr->NumberOfPages == 0) { + continue; + } + + switch (MemoryMapPtr->Type) { + case EfiACPIReclaimMemory: + acpi_table_mem[acpi_table_index].MemType = ACPI_TABLE; + acpi_table_mem[acpi_table_index].MemStart = (MemoryMapPtr->PhysicalStart) & 0xffffffffffff; + acpi_table_mem[acpi_table_index].MemSize = MemoryMapPtr->NumberOfPages * 4096; + acpi_table_index++; + break; + + case EfiACPIMemoryNVS: + acpi_nvs_mem[acpi_nvs_index].MemType = ACPI_NVS; + acpi_nvs_mem[acpi_nvs_index].MemStart = (MemoryMapPtr->PhysicalStart) & 0xffffffffffff; + acpi_nvs_mem[acpi_nvs_index].MemSize = MemoryMapPtr->NumberOfPages * 4096; + acpi_nvs_index++; + break; + + case EfiRuntimeServicesData: + case EfiRuntimeServicesCode: + case EfiReservedMemoryType: + case EfiPalCode: + reserve_mem[reserve_index].MemType = SYSTEM_RAM_RESERVED; + reserve_mem[reserve_index].MemStart = (MemoryMapPtr->PhysicalStart) & 0xffffffffffff; + reserve_mem[reserve_index].MemSize = MemoryMapPtr->NumberOfPages * 4096; + reserve_index++; + break; + + default : + free_mem[free_index].MemType = SYSTEM_RAM; + free_mem[free_index].MemStart = (MemoryMapPtr->PhysicalStart) & 0xffffffffffff; + free_mem[free_index].MemSize = MemoryMapPtr->NumberOfPages * 4096; + free_index++; + break; + }; + // Get next item + MemoryMapPtr = (EFI_MEMORY_DESCRIPTOR *) ((UINTN)MemoryMapPtr + DescriptorSize); + } + + /* Recovery sort */ + for (j = 0; j < free_index; ) { + tempMemsize = free_mem[j].MemSize; + for (t = j + 1; t < free_index; t++) { + if ((free_mem[j].MemStart + tempMemsize == free_mem[t].MemStart) + && (free_mem[j].MemType == free_mem[t].MemType)) + { + tempMemsize += free_mem[t].MemSize; + } else { + break; + } + } + + new_interface_mem->Map[tmp_index].MemType = SYSTEM_RAM; + new_interface_mem->Map[tmp_index].MemStart = free_mem[j].MemStart; + new_interface_mem->Map[tmp_index].MemSize = tempMemsize; + + j = t; + tmp_index++; + } + + tmp_index = memmap_sort (reserve_mem, reserve_index, new_interface_mem, tmp_index, SYSTEM_RAM_RESERVED); + + new_interface_mem->MapCount = tmp_index; + new_interface_mem->Header.CheckSum = 0; + + checksum = CalculateCheckSum8 ((CONST UINT8 *)new_interface_mem, new_interface_mem->Header.Length); + new_interface_mem->Header.CheckSum = checksum; + + return ; +} +/** + Establish linux kernel boot parameters. + + @param Bpi A pointer to the boot parameter interface. + + @retval VOID +**/ +VOID +SetupLinuxBootParams ( + IN OUT BootParamsInterface *Bpi + ) +{ + EFI_MEMORY_DESCRIPTOR *MemoryMapPtr = NULL; + MEM_MAP *new_interface_mem = NULL; + UINTN MapKey = 0; + UINTN MemoryMapSize = 0; + UINTN DescriptorSize = 0; + + new_interface_mem = FindNewInterfaceMem (Bpi); + MemoryMapPtr = GetSystemMemap (&MapKey, &MemoryMapSize, &DescriptorSize); + + DEBUG ((DEBUG_INFO, "new_interface_mem %p MemoryMapPtr %p MapKey %x.\n", + new_interface_mem, MemoryMapPtr, MapKey)); + MemMapSort (new_interface_mem, MemoryMapPtr, MemoryMapSize, DescriptorSize); + + gBS->ExitBootServices (gImageHandle, MapKey); + + return ; +} + +/** + 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; + UINT32 Size; + UINT32 Argc; + VOID **Argv; + UINTN CommandLineSize; + CHAR8 *CommandLine; + VOID *KernelEntryPoint; + VOID *Bpi; + EFI_PHYSICAL_ADDRESS Address; + + CommandLine = NULL; + CHAR8 *Args[] = {"a0", CommandLine}; + Argc = ARRAY_SIZE (Args); + Size = Argc * sizeof (VOID **); + Size += sizeof (VOID **); + + Size += ALIGN_UP (AsciiStrLen (Args[0]) + 1, 4); + + if (!QemuFwCfgIsAvailable ()) { + return EFI_NOT_FOUND; + } + + /* get command line size */ + QemuFwCfgSelectItem (QemuFwCfgItemCommandLineSize); + CommandLineSize = (UINTN) QemuFwCfgRead32 (); + DEBUG ((DEBUG_INFO, "command line size: %d.\n", CommandLineSize)); + + Size += ALIGN_UP (CommandLineSize + 1, 4); + DEBUG ((DEBUG_INFO, "kernel args size: %d.\n", Size)); + //Argv = LoadLinuxAllocateCommandLinePages (EFI_SIZE_TO_PAGES (Size)); + Status = gBS->AllocatePages ( + AllocateAnyPages, + EfiRuntimeServicesData, + EFI_SIZE_TO_PAGES (Size), + &Address + ); + if (EFI_ERROR (Status)) { + return Status; + } + Argv = (VOID *) (UINTN) Address; + DEBUG ((DEBUG_INFO, "kernel argv address: 0x%0x.\n", Argv)); + + VOID **P = Argv; + CHAR8 *Pos = (CHAR8 *) (Argv + (Argc + 1)); + AsciiStrCpyS (Pos, 256, Args[0]); + *P++ = Pos; + + Pos += ALIGN_UP (AsciiStrLen (Args[0]) + 1, 4); + /* get command line content */ + QemuFwCfgSelectItem (QemuFwCfgItemCommandLineData); + QemuFwCfgReadBytes (CommandLineSize, Pos); + *P++ = Pos; + + *P = NULL; + + /* get kernel entry point */ + QemuFwCfgSelectItem (QemuFwCfgItemKernelEntry); + KernelEntryPoint = (VOID *) ((UINTN) ((UINT32)QemuFwCfgRead64 ())); + + DEBUG ((DEBUG_INFO, "kernel entry point: %p.\n", KernelEntryPoint)); + if (KernelEntryPoint == NULL) { + DEBUG ((DEBUG_INFO, "kernel entry point invalid.\n")); + return EFI_NOT_FOUND; + } + + Status = EfiGetSystemConfigurationTable ( + &gEfiLoongsonBootparamsTableGuid, + (VOID **) &Bpi + ); + if ((EFI_ERROR (Status)) + || (Bpi == NULL)) + { + DEBUG ((DEBUG_ERROR, "Get Boot Params Table Failed!\n")); + return EFI_NOT_FOUND; + } + + SetupLinuxBootParams ((BootParamsInterface *)Bpi); + + DEBUG ((DEBUG_INFO, "kernel argc: %d, argv: 0x%0x, bpi: 0x%0x.\n", Argc, Argv, Bpi)); + DEBUG ((DEBUG_INFO, "entry kernel ...\n")); + ((EFI_KERNEL_ENTRY_POINT)KernelEntryPoint) (Argc, Argv, Bpi, NULL); + + return EFI_SUCCESS; +} -- 2.27.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#87211): https://edk2.groups.io/g/devel/message/87211 Mute This Topic: https://groups.io/mt/89497240/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-