ArmPkg/BdsLib: Use two distinct functions to boot Linux either by Atag or Fdt

Separate the BdsBootLinux() function into two functions for Atag and Fdt specific Linux booting
- BdsBootLinuxAtag ()
- BdsBootLinuxFdt ()



git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12408 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
oliviermartin 2011-09-22 22:54:38 +00:00
parent 11c20f4e06
commit 76d17c3156
5 changed files with 160 additions and 96 deletions

View File

@ -96,6 +96,24 @@ BootOptionAllocateBootIndex (
VOID 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 Start a Linux kernel from a Device Path
@ -109,7 +127,7 @@ BootOptionAllocateBootIndex (
**/ **/
EFI_STATUS EFI_STATUS
BdsBootLinux ( BdsBootLinuxFdt (
IN EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath, IN EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath,
IN EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath, IN EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath,
IN CONST CHAR8* Arguments, IN CONST CHAR8* Arguments,

View File

@ -16,14 +16,17 @@
#define __BDS_INTERNAL_H__ #define __BDS_INTERNAL_H__
#include <PiDxe.h> #include <PiDxe.h>
#include <Library/ArmLib.h>
#include <Library/BaseLib.h> #include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h> #include <Library/BaseMemoryLib.h>
#include <Library/HobLib.h>
#include <Library/UefiBootServicesTableLib.h> #include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h> #include <Library/UefiLib.h>
#include <Library/DevicePathLib.h> #include <Library/DevicePathLib.h>
#include <Library/MemoryAllocationLib.h> #include <Library/MemoryAllocationLib.h>
#include <Library/DebugLib.h> #include <Library/DebugLib.h>
#include <Library/BdsLib.h> #include <Library/BdsLib.h>
#include <Library/PcdLib.h>
#include <Library/PerformanceLib.h> #include <Library/PerformanceLib.h>
#include <Library/PrintLib.h> #include <Library/PrintLib.h>
#include <Library/UefiRuntimeServicesTableLib.h> #include <Library/UefiRuntimeServicesTableLib.h>
@ -38,6 +41,7 @@
#include <Protocol/LoadFile.h> #include <Protocol/LoadFile.h>
#include <Protocol/PxeBaseCode.h> #include <Protocol/PxeBaseCode.h>
#include "BdsLinuxLoader.h"
typedef BOOLEAN (*BDS_FILE_LOADER_SUPPORT) ( typedef BOOLEAN (*BDS_FILE_LOADER_SUPPORT) (
IN EFI_DEVICE_PATH *DevicePath, IN EFI_DEVICE_PATH *DevicePath,

View File

@ -13,17 +13,9 @@
**/ **/
#include "BdsInternal.h" #include "BdsInternal.h"
#include "BdsLinuxLoader.h"
#include <Library/PcdLib.h>
#include <Library/ArmLib.h>
#include <Library/HobLib.h>
#define ALIGN32_BELOW(addr) ALIGN_POINTER(addr - 32,32) #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 // Point to the current ATAG
STATIC LINUX_ATAG *mLinuxKernelCurrentAtag; STATIC LINUX_ATAG *mLinuxKernelCurrentAtag;
@ -178,7 +170,7 @@ PreparePlatformHardware (
{ {
//Note: Interrupts will be disabled by the GIC driver when ExitBootServices() will be called. //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(); ArmCleanInvalidateDataCache();
ArmDisableDataCache(); ArmDisableDataCache();
@ -186,97 +178,24 @@ PreparePlatformHardware (
ArmInvalidateInstructionCache (); ArmInvalidateInstructionCache ();
ArmDisableInstructionCache (); ArmDisableInstructionCache ();
// turn off MMU // Turn off MMU
ArmDisableMmu(); ArmDisableMmu();
return EFI_SUCCESS; return EFI_SUCCESS;
} }
/** STATIC
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 EFI_STATUS
BdsBootLinux ( StartLinux (
IN EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath, IN EFI_PHYSICAL_ADDRESS LinuxImage,
IN EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath, IN UINTN LinuxImageSize,
IN CONST CHAR8* Arguments, IN EFI_PHYSICAL_ADDRESS KernelParamsAddress,
IN EFI_DEVICE_PATH_PROTOCOL* FdtDevicePath IN UINTN KernelParamsSize,
IN UINT32 MachineType
) )
{ {
EFI_STATUS Status; EFI_STATUS Status;
UINT32 LinuxImageSize;
UINT32 InitrdImageSize;
UINT32 KernelParamsSize;
EFI_PHYSICAL_ADDRESS KernelParamsAddress;
UINT32 MachineType;
BOOLEAN FdtSupported;
LINUX_KERNEL LinuxKernel; 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 // 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. // 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) { if ((UINTN)LinuxImage > LINUX_KERNEL_MAX_OFFSET) {
//Note: There is no requirement on the alignment //Note: There is no requirement on the alignment
LinuxKernel = (LINUX_KERNEL)CopyMem (ALIGN32_BELOW(LINUX_KERNEL_MAX_OFFSET - LinuxImageSize), (VOID*)(UINTN)LinuxImage, LinuxImageSize); 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 //TODO: Check there is no overlapping between kernel and Atag
@ -322,7 +243,7 @@ BdsBootLinux (
DEBUG((EFI_D_ERROR, "\nStarting the kernel:\n\n")); DEBUG((EFI_D_ERROR, "\nStarting the kernel:\n\n"));
// jump to kernel with register set // jump to kernel with register set
LinuxKernel ((UINTN)0, (UINTN)MachineType, (UINTN)KernelParamsAddress); LinuxKernel ((UINTN)0, MachineType, (UINTN)KernelParamsAddress);
// Kernel should never exit // Kernel should never exit
// After Life services are not provided // After Life services are not provided
@ -335,3 +256,122 @@ Exit:
// Free Runtimee Memory (kernel and FDT) // Free Runtimee Memory (kernel and FDT)
return Status; 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);
}

View File

@ -15,6 +15,9 @@
#ifndef __BDSLINUXLOADER_H #ifndef __BDSLINUXLOADER_H
#define __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 #define ATAG_MAX_SIZE 0x3000
/* ATAG : list of possible tags */ /* ATAG : list of possible tags */

View File

@ -54,10 +54,9 @@ BootOptionStart (
Initrd = NULL; Initrd = NULL;
} }
Status = BdsBootLinux (BootOption->FilePathList, Status = BdsBootLinuxAtag (BootOption->FilePathList,
Initrd, // Initrd Initrd, // Initrd
(CHAR8*)(LinuxArguments + 1), // CmdLine (CHAR8*)(LinuxArguments + 1)); // CmdLine
NULL);
} else if (LoaderType == BDS_LOADER_KERNEL_LINUX_FDT) { } else if (LoaderType == BDS_LOADER_KERNEL_LINUX_FDT) {
LinuxArguments = &(OptionalData->Arguments.LinuxArguments); LinuxArguments = &(OptionalData->Arguments.LinuxArguments);
CmdLineSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->CmdLineSize); CmdLineSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->CmdLineSize);
@ -79,7 +78,7 @@ BootOptionStart (
Status = GetEnvironmentVariable ((CHAR16 *)L"FDT", DefaultFdtDevicePath, &FdtDevicePathSize, (VOID **)&FdtDevicePath); Status = GetEnvironmentVariable ((CHAR16 *)L"FDT", DefaultFdtDevicePath, &FdtDevicePathSize, (VOID **)&FdtDevicePath);
ASSERT_EFI_ERROR(Status); ASSERT_EFI_ERROR(Status);
Status = BdsBootLinux (BootOption->FilePathList, Status = BdsBootLinuxFdt (BootOption->FilePathList,
Initrd, // Initrd Initrd, // Initrd
(CHAR8*)(LinuxArguments + 1), (CHAR8*)(LinuxArguments + 1),
FdtDevicePath); FdtDevicePath);