diff --git a/ArmPkg/Include/Library/BdsLib.h b/ArmPkg/Include/Library/BdsLib.h index e9337d68cb..c8e02c934e 100644 --- a/ArmPkg/Include/Library/BdsLib.h +++ b/ArmPkg/Include/Library/BdsLib.h @@ -96,6 +96,24 @@ BootOptionAllocateBootIndex ( VOID ); +/** + Start a Linux kernel from a Device Path + + @param LinuxKernel Device Path to the Linux Kernel + @param Parameters Linux kernel arguments + + @retval EFI_SUCCESS All drivers have been connected + @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found + @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results. + +**/ +EFI_STATUS +BdsBootLinuxAtag ( + IN EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath, + IN EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath, + IN CONST CHAR8* Arguments + ); + /** Start a Linux kernel from a Device Path @@ -109,7 +127,7 @@ BootOptionAllocateBootIndex ( **/ EFI_STATUS -BdsBootLinux ( +BdsBootLinuxFdt ( IN EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath, IN EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath, IN CONST CHAR8* Arguments, diff --git a/ArmPkg/Library/BdsLib/BdsInternal.h b/ArmPkg/Library/BdsLib/BdsInternal.h index d450e8e6b2..9b73376f96 100644 --- a/ArmPkg/Library/BdsLib/BdsInternal.h +++ b/ArmPkg/Library/BdsLib/BdsInternal.h @@ -16,14 +16,17 @@ #define __BDS_INTERNAL_H__ #include +#include #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -38,6 +41,7 @@ #include #include +#include "BdsLinuxLoader.h" typedef BOOLEAN (*BDS_FILE_LOADER_SUPPORT) ( IN EFI_DEVICE_PATH *DevicePath, diff --git a/ArmPkg/Library/BdsLib/BdsLinuxLoader.c b/ArmPkg/Library/BdsLib/BdsLinuxLoader.c index ce4b2a43b6..06baf49c55 100644 --- a/ArmPkg/Library/BdsLib/BdsLinuxLoader.c +++ b/ArmPkg/Library/BdsLib/BdsLinuxLoader.c @@ -13,17 +13,9 @@ **/ #include "BdsInternal.h" -#include "BdsLinuxLoader.h" - -#include -#include -#include #define ALIGN32_BELOW(addr) ALIGN_POINTER(addr - 32,32) -#define LINUX_ATAG_MAX_OFFSET (PcdGet32(PcdSystemMemoryBase) + PcdGet32(PcdArmLinuxAtagMaxOffset)) -#define LINUX_KERNEL_MAX_OFFSET (PcdGet32(PcdSystemMemoryBase) + PcdGet32(PcdArmLinuxKernelMaxOffset)) - // Point to the current ATAG STATIC LINUX_ATAG *mLinuxKernelCurrentAtag; @@ -178,7 +170,7 @@ PreparePlatformHardware ( { //Note: Interrupts will be disabled by the GIC driver when ExitBootServices() will be called. - // clean, invalidate, disable data cache + // Clean, invalidate, disable data cache ArmCleanInvalidateDataCache(); ArmDisableDataCache(); @@ -186,97 +178,24 @@ PreparePlatformHardware ( ArmInvalidateInstructionCache (); ArmDisableInstructionCache (); - // turn off MMU + // Turn off MMU ArmDisableMmu(); return EFI_SUCCESS; } -/** - Start a Linux kernel from a Device Path - - @param LinuxKernel Device Path to the Linux Kernel - @param Parameters Linux kernel agruments - @param Fdt Device Path to the Flat Device Tree - - @retval EFI_SUCCESS All drivers have been connected - @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found - @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results. - -**/ +STATIC EFI_STATUS -BdsBootLinux ( - IN EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath, - IN EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath, - IN CONST CHAR8* Arguments, - IN EFI_DEVICE_PATH_PROTOCOL* FdtDevicePath +StartLinux ( + IN EFI_PHYSICAL_ADDRESS LinuxImage, + IN UINTN LinuxImageSize, + IN EFI_PHYSICAL_ADDRESS KernelParamsAddress, + IN UINTN KernelParamsSize, + IN UINT32 MachineType ) { EFI_STATUS Status; - UINT32 LinuxImageSize; - UINT32 InitrdImageSize; - UINT32 KernelParamsSize; - EFI_PHYSICAL_ADDRESS KernelParamsAddress; - UINT32 MachineType; - BOOLEAN FdtSupported; LINUX_KERNEL LinuxKernel; - EFI_PHYSICAL_ADDRESS LinuxImage; - EFI_PHYSICAL_ADDRESS InitrdImage; - - InitrdImageSize = 0; - FdtSupported = FALSE; - - // Ensure the System Memory PCDs have been initialized (PcdSystemMemoryBase and PcdSystemMemorySize) - ASSERT (PcdGet32(PcdSystemMemorySize) != 0); - - PERF_START (NULL, "BDS", NULL, 0); - - // Load the Linux kernel from a device path - LinuxImage = LINUX_KERNEL_MAX_OFFSET; - Status = BdsLoadImage (LinuxKernelDevicePath, AllocateMaxAddress, &LinuxImage, &LinuxImageSize); - if (EFI_ERROR(Status)) { - Print (L"ERROR: Did not find Linux kernel.\n"); - return Status; - } - LinuxKernel = (LINUX_KERNEL)(UINTN)LinuxImage; - - if (InitrdDevicePath) { - Status = BdsLoadImage (InitrdDevicePath, AllocateAnyPages, &InitrdImage, &InitrdImageSize); - if (EFI_ERROR(Status)) { - Print (L"ERROR: Did not find initrd image.\n"); - return Status; - } - } - - if (FdtDevicePath) { - // Load the FDT binary from a device path - KernelParamsAddress = LINUX_ATAG_MAX_OFFSET; - Status = BdsLoadImage (FdtDevicePath, AllocateMaxAddress, &KernelParamsAddress, &KernelParamsSize); - if (EFI_ERROR(Status)) { - Print (L"ERROR: Did not find Device Tree blob.\n"); - return Status; - } - FdtSupported = TRUE; - } - - // - // Setup the Linux Kernel Parameters - // - if (!FdtSupported) { - // Non-FDT requires a specific machine type. - // This OS Boot loader supports just one machine type, - // but that could change in the future. - MachineType = PcdGet32(PcdArmMachineType); - - // By setting address=0 we leave the memory allocation to the function - Status = PrepareAtagList (Arguments, InitrdImage, InitrdImageSize, (LINUX_ATAG**)&KernelParamsAddress, &KernelParamsSize); - if(EFI_ERROR(Status)) { - Print(L"ERROR: Can not prepare ATAG list. Status=0x%X\n", Status); - goto Exit; - } - } else { - MachineType = 0xFFFFFFFF; - } // Shut down UEFI boot services. ExitBootServices() will notify every driver that created an event on // ExitBootServices event. Example the Interrupt DXE driver will disable the interrupts on this event. @@ -298,6 +217,8 @@ BdsBootLinux ( if ((UINTN)LinuxImage > LINUX_KERNEL_MAX_OFFSET) { //Note: There is no requirement on the alignment LinuxKernel = (LINUX_KERNEL)CopyMem (ALIGN32_BELOW(LINUX_KERNEL_MAX_OFFSET - LinuxImageSize), (VOID*)(UINTN)LinuxImage, LinuxImageSize); + } else { + LinuxKernel = (LINUX_KERNEL)(UINTN)LinuxImage; } //TODO: Check there is no overlapping between kernel and Atag @@ -322,7 +243,7 @@ BdsBootLinux ( DEBUG((EFI_D_ERROR, "\nStarting the kernel:\n\n")); // jump to kernel with register set - LinuxKernel ((UINTN)0, (UINTN)MachineType, (UINTN)KernelParamsAddress); + LinuxKernel ((UINTN)0, MachineType, (UINTN)KernelParamsAddress); // Kernel should never exit // After Life services are not provided @@ -335,3 +256,122 @@ Exit: // Free Runtimee Memory (kernel and FDT) return Status; } + +/** + Start a Linux kernel from a Device Path + + @param LinuxKernel Device Path to the Linux Kernel + @param Parameters Linux kernel agruments + @param Fdt Device Path to the Flat Device Tree + + @retval EFI_SUCCESS All drivers have been connected + @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found + @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results. + +**/ +EFI_STATUS +BdsBootLinuxAtag ( + IN EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath, + IN EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath, + IN CONST CHAR8* Arguments + ) +{ + EFI_STATUS Status; + UINT32 LinuxImageSize; + UINT32 InitrdImageSize = 0; + UINT32 KernelParamsSize; + EFI_PHYSICAL_ADDRESS KernelParamsAddress; + EFI_PHYSICAL_ADDRESS LinuxImage; + EFI_PHYSICAL_ADDRESS InitrdImage; + + PERF_START (NULL, "BDS", NULL, 0); + + // Load the Linux kernel from a device path + LinuxImage = LINUX_KERNEL_MAX_OFFSET; + Status = BdsLoadImage (LinuxKernelDevicePath, AllocateMaxAddress, &LinuxImage, &LinuxImageSize); + if (EFI_ERROR(Status)) { + Print (L"ERROR: Did not find Linux kernel.\n"); + return Status; + } + + if (InitrdDevicePath) { + Status = BdsLoadImage (InitrdDevicePath, AllocateAnyPages, &InitrdImage, &InitrdImageSize); + if (EFI_ERROR(Status)) { + Print (L"ERROR: Did not find initrd image.\n"); + return Status; + } + } + + // + // Setup the Linux Kernel Parameters + // + + // By setting address=0 we leave the memory allocation to the function + Status = PrepareAtagList (Arguments, InitrdImage, InitrdImageSize, (LINUX_ATAG**)&KernelParamsAddress, &KernelParamsSize); + if (EFI_ERROR(Status)) { + Print(L"ERROR: Can not prepare ATAG list. Status=0x%X\n", Status); + return Status; + } + + return StartLinux (LinuxImage, LinuxImageSize, KernelParamsAddress, KernelParamsSize, PcdGet32(PcdArmMachineType)); +} + +/** + Start a Linux kernel from a Device Path + + @param LinuxKernel Device Path to the Linux Kernel + @param Parameters Linux kernel agruments + @param Fdt Device Path to the Flat Device Tree + + @retval EFI_SUCCESS All drivers have been connected + @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found + @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results. + +**/ +EFI_STATUS +BdsBootLinuxFdt ( + IN EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath, + IN EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath, + IN CONST CHAR8* Arguments, + IN EFI_DEVICE_PATH_PROTOCOL* FdtDevicePath + ) +{ + EFI_STATUS Status; + UINT32 LinuxImageSize; + UINT32 InitrdImageSize = 0; + UINT32 KernelParamsSize; + EFI_PHYSICAL_ADDRESS KernelParamsAddress; + UINT32 FdtMachineType; + EFI_PHYSICAL_ADDRESS LinuxImage; + EFI_PHYSICAL_ADDRESS InitrdImage; + + FdtMachineType = 0xFFFFFFFF; + + PERF_START (NULL, "BDS", NULL, 0); + + // Load the Linux kernel from a device path + LinuxImage = LINUX_KERNEL_MAX_OFFSET; + Status = BdsLoadImage (LinuxKernelDevicePath, AllocateMaxAddress, &LinuxImage, &LinuxImageSize); + if (EFI_ERROR(Status)) { + Print (L"ERROR: Did not find Linux kernel.\n"); + return Status; + } + + if (InitrdDevicePath) { + Status = BdsLoadImage (InitrdDevicePath, AllocateAnyPages, &InitrdImage, &InitrdImageSize); + if (EFI_ERROR(Status)) { + Print (L"ERROR: Did not find initrd image.\n"); + return Status; + } + } + + // Load the FDT binary from a device path + KernelParamsAddress = LINUX_ATAG_MAX_OFFSET; + Status = BdsLoadImage (FdtDevicePath, AllocateMaxAddress, &KernelParamsAddress, &KernelParamsSize); + if (EFI_ERROR(Status)) { + Print (L"ERROR: Did not find Device Tree blob.\n"); + return Status; + } + return StartLinux (LinuxImage, LinuxImageSize, KernelParamsAddress, KernelParamsSize, FdtMachineType); +} + diff --git a/ArmPkg/Library/BdsLib/BdsLinuxLoader.h b/ArmPkg/Library/BdsLib/BdsLinuxLoader.h index 82b7a4f081..e951e2a4be 100644 --- a/ArmPkg/Library/BdsLib/BdsLinuxLoader.h +++ b/ArmPkg/Library/BdsLib/BdsLinuxLoader.h @@ -15,6 +15,9 @@ #ifndef __BDSLINUXLOADER_H #define __BDSLINUXLOADER_H +#define LINUX_ATAG_MAX_OFFSET (PcdGet32(PcdSystemMemoryBase) + PcdGet32(PcdArmLinuxAtagMaxOffset)) +#define LINUX_KERNEL_MAX_OFFSET (PcdGet32(PcdSystemMemoryBase) + PcdGet32(PcdArmLinuxKernelMaxOffset)) + #define ATAG_MAX_SIZE 0x3000 /* ATAG : list of possible tags */ diff --git a/ArmPlatformPkg/Bds/BootOption.c b/ArmPlatformPkg/Bds/BootOption.c index 86f2ac2dca..305892a8d6 100644 --- a/ArmPlatformPkg/Bds/BootOption.c +++ b/ArmPlatformPkg/Bds/BootOption.c @@ -54,10 +54,9 @@ BootOptionStart ( Initrd = NULL; } - Status = BdsBootLinux (BootOption->FilePathList, + Status = BdsBootLinuxAtag (BootOption->FilePathList, Initrd, // Initrd - (CHAR8*)(LinuxArguments + 1), // CmdLine - NULL); + (CHAR8*)(LinuxArguments + 1)); // CmdLine } else if (LoaderType == BDS_LOADER_KERNEL_LINUX_FDT) { LinuxArguments = &(OptionalData->Arguments.LinuxArguments); CmdLineSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->CmdLineSize); @@ -79,7 +78,7 @@ BootOptionStart ( Status = GetEnvironmentVariable ((CHAR16 *)L"FDT", DefaultFdtDevicePath, &FdtDevicePathSize, (VOID **)&FdtDevicePath); ASSERT_EFI_ERROR(Status); - Status = BdsBootLinux (BootOption->FilePathList, + Status = BdsBootLinuxFdt (BootOption->FilePathList, Initrd, // Initrd (CHAR8*)(LinuxArguments + 1), FdtDevicePath);