ArmPkg/BdsLib: Remove Linux loader from BdsLib

This change removes the embedded Linux Loder from BdsLib.
BdsLib becomes OS agnostic.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Olivier Martin <Olivier.Martin@arm.com>
Reviewed-by: Ronald Cron <Ronald.Cron@arm.com>



git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17969 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
Olivier Martin 2015-07-14 14:35:20 +00:00 committed by oliviermartin
parent 0ead5ec47d
commit c75d3eb6be
12 changed files with 8 additions and 1934 deletions

View File

@ -137,43 +137,6 @@ 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
@param[in] LinuxKernelDevicePath Device Path to the Linux Kernel
@param[in] InitrdDevicePath Device Path to the Initrd
@param[in] Arguments 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
BdsBootLinuxFdt (
IN EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath,
IN EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath,
IN CONST CHAR8* Arguments
);
/**
Start an EFI Application from a Device Path

View File

@ -1,355 +0,0 @@
/** @file
*
* Copyright (c) 2011-2014, ARM Limited. All rights reserved.
*
* This program and the accompanying materials
* are licensed and made available under the terms and conditions of the BSD License
* which accompanies this distribution. The full text of the license may be found at
* http://opensource.org/licenses/bsd-license.php
*
* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*
**/
#include <Library/ArmGicLib.h>
#include <Ppi/ArmMpCoreInfo.h>
#include <Library/IoLib.h>
#include <Guid/Fdt.h>
#include <libfdt.h>
#include "BdsInternal.h"
#include "BdsLinuxLoader.h"
/*
Linux kernel booting: Look at the doc in the Kernel source :
Documentation/arm64/booting.txt
The kernel image must be placed at the start of the memory to be used by the
kernel (2MB aligned) + 0x80000.
The Device tree blob is expected to be under 2MB and be within the first 512MB
of kernel memory and be 2MB aligned.
A Flattened Device Tree (FDT) used to boot linux needs to be updated before
the kernel is started. It needs to indicate how secondary cores are brought up
and where they are waiting before loading Linux. The FDT also needs to hold
the correct kernel command line and filesystem RAM-disk information.
At the moment we do not fully support generating this FDT information at
runtime. A prepared FDT should be provided at boot. FDT is the only supported
method for booting the AArch64 Linux kernel.
Linux does not use any runtime services at this time, so we can let it
overwrite UEFI.
*/
#define LINUX_ALIGN_VAL (0x080000) // 2MB + 0x80000 mask
#define LINUX_ALIGN_MASK (0x1FFFFF) // Bottom 21bits
#define ALIGN_2MB(addr) ALIGN_POINTER(addr , (2*1024*1024))
/* ARM32 and AArch64 kernel handover differ.
* x0 is set to FDT base.
* x1-x3 are reserved for future use and should be set to zero.
*/
typedef VOID (*LINUX_KERNEL64)(UINTN ParametersBase, UINTN Reserved0,
UINTN Reserved1, UINTN Reserved2);
/* These externs are used to relocate some ASM code into Linux memory. */
extern VOID *SecondariesPenStart;
extern VOID *SecondariesPenEnd;
extern UINTN *AsmMailboxbase;
STATIC
EFI_STATUS
PreparePlatformHardware (
VOID
)
{
//Note: Interrupts will be disabled by the GIC driver when ExitBootServices() will be called.
// Clean before Disable else the Stack gets corrupted with old data.
ArmCleanDataCache ();
ArmDisableDataCache ();
// Invalidate all the entries that might have snuck in.
ArmInvalidateDataCache ();
// Disable and invalidate the instruction cache
ArmDisableInstructionCache ();
ArmInvalidateInstructionCache ();
// Turn off MMU
ArmDisableMmu();
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
StartLinux (
IN EFI_PHYSICAL_ADDRESS LinuxImage,
IN UINTN LinuxImageSize,
IN EFI_PHYSICAL_ADDRESS FdtBlobBase,
IN UINTN FdtBlobSize
)
{
EFI_STATUS Status;
LINUX_KERNEL64 LinuxKernel = (LINUX_KERNEL64)LinuxImage;
// Send msg to secondary cores to go to the kernel pen.
ArmGicSendSgiTo (PcdGet32(PcdGicDistributorBase), ARM_GIC_ICDSGIR_FILTER_EVERYONEELSE, 0x0E, PcdGet32 (PcdGicSgiIntId));
// 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.
Status = ShutdownUefiBootServices ();
if(EFI_ERROR(Status)) {
DEBUG((EFI_D_ERROR,"ERROR: Can not shutdown UEFI boot services. Status=0x%X\n", Status));
goto Exit;
}
// Check if the Linux Image is a uImage
if (*(UINTN*)LinuxKernel == LINUX_UIMAGE_SIGNATURE) {
// Assume the Image Entry Point is just after the uImage header (64-byte size)
LinuxKernel = (LINUX_KERNEL64)((UINTN)LinuxKernel + 64);
LinuxImageSize -= 64;
}
//
// Switch off interrupts, caches, mmu, etc
//
Status = PreparePlatformHardware ();
ASSERT_EFI_ERROR(Status);
// Register and print out performance information
PERF_END (NULL, "BDS", NULL, 0);
if (PerformanceMeasurementEnabled ()) {
PrintPerformance ();
}
//
// Start the Linux Kernel
//
// x1-x3 are reserved (set to zero) for future use.
LinuxKernel ((UINTN)FdtBlobBase, 0, 0, 0);
// Kernel should never exit
// After Life services are not provided
ASSERT(FALSE);
Exit:
// Only be here if we fail to start Linux
Print (L"ERROR : Can not start the kernel. Status=0x%X\n", Status);
// 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
)
{
// NOTE : AArch64 Linux kernel does not support ATAG, FDT only.
ASSERT(0);
return RETURN_UNSUPPORTED;
}
/**
Start a Linux kernel from a Device Path
@param[in] LinuxKernelDevicePath Device Path to the Linux Kernel
@param[in] InitrdDevicePath Device Path to the Initrd
@param[in] Arguments 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
BdsBootLinuxFdt (
IN EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath,
IN EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath,
IN CONST CHAR8* Arguments
)
{
EFI_STATUS Status;
EFI_STATUS PenBaseStatus;
UINTN LinuxImageSize;
UINTN InitrdImageSize;
UINTN InitrdImageBaseSize;
VOID *InstalledFdtBase;
UINTN FdtBlobSize;
EFI_PHYSICAL_ADDRESS FdtBlobBase;
EFI_PHYSICAL_ADDRESS LinuxImage;
EFI_PHYSICAL_ADDRESS InitrdImage;
EFI_PHYSICAL_ADDRESS InitrdImageBase;
ARM_PROCESSOR_TABLE *ArmProcessorTable;
ARM_CORE_INFO *ArmCoreInfoTable;
UINTN Index;
EFI_PHYSICAL_ADDRESS PenBase;
UINTN PenSize;
UINTN MailBoxBase;
PenBaseStatus = EFI_UNSUPPORTED;
PenSize = 0;
InitrdImage = 0;
InitrdImageSize = 0;
InitrdImageBase = 0;
InitrdImageBaseSize = 0;
PERF_START (NULL, "BDS", NULL, 0);
//
// Load the Linux kernel from a device path
//
// Try to put the kernel at the start of RAM so as to give it access to all memory.
// If that fails fall back to try loading it within LINUX_KERNEL_MAX_OFFSET of memory start.
LinuxImage = PcdGet64 (PcdSystemMemoryBase) + 0x80000;
Status = BdsLoadImage (LinuxKernelDevicePath, AllocateAddress, &LinuxImage, &LinuxImageSize);
if (EFI_ERROR(Status)) {
// Try again but give the loader more freedom of where to put the image.
LinuxImage = LINUX_KERNEL_MAX_OFFSET;
Status = BdsLoadImage (LinuxKernelDevicePath, AllocateMaxAddress, &LinuxImage, &LinuxImageSize);
if (EFI_ERROR(Status)) {
Print (L"ERROR: Did not find Linux kernel (%r).\n", Status);
return Status;
}
}
// Adjust the kernel location slightly if required. The kernel needs to be placed at start
// of memory (2MB aligned) + 0x80000.
if ((LinuxImage & LINUX_ALIGN_MASK) != LINUX_ALIGN_VAL) {
LinuxImage = (EFI_PHYSICAL_ADDRESS)CopyMem (ALIGN_2MB(LinuxImage) + 0x80000, (VOID*)(UINTN)LinuxImage, LinuxImageSize);
}
if (InitrdDevicePath) {
InitrdImageBase = LINUX_KERNEL_MAX_OFFSET;
Status = BdsLoadImage (InitrdDevicePath, AllocateMaxAddress, &InitrdImageBase, &InitrdImageBaseSize);
if (Status == EFI_OUT_OF_RESOURCES) {
Status = BdsLoadImage (InitrdDevicePath, AllocateAnyPages, &InitrdImageBase, &InitrdImageBaseSize);
}
if (EFI_ERROR (Status)) {
Print (L"ERROR: Did not find initrd image (%r).\n", Status);
goto EXIT_FREE_LINUX;
}
// Check if the initrd is a uInitrd
if (*(UINTN*)((UINTN)InitrdImageBase) == LINUX_UIMAGE_SIGNATURE) {
// Skip the 64-byte image header
InitrdImage = (EFI_PHYSICAL_ADDRESS)((UINTN)InitrdImageBase + 64);
InitrdImageSize = InitrdImageBaseSize - 64;
} else {
InitrdImage = InitrdImageBase;
InitrdImageSize = InitrdImageBaseSize;
}
}
//
// Get the FDT from the Configuration Table.
// The FDT will be reloaded in PrepareFdt() to a more appropriate
// location for the Linux Kernel.
//
Status = EfiGetSystemConfigurationTable (&gFdtTableGuid, &InstalledFdtBase);
if (EFI_ERROR (Status)) {
Print (L"ERROR: Did not get the Device Tree blob (%r).\n", Status);
goto EXIT_FREE_INITRD;
}
FdtBlobBase = (EFI_PHYSICAL_ADDRESS)InstalledFdtBase;
FdtBlobSize = fdt_totalsize (InstalledFdtBase);
//
// Install secondary core pens if the Power State Coordination Interface is not supported
//
if (FeaturePcdGet (PcdArmLinuxSpinTable)) {
// Place Pen at the start of Linux memory. We can then tell Linux to not use this bit of memory
PenBase = LinuxImage - 0x80000;
PenSize = (UINTN)&SecondariesPenEnd - (UINTN)&SecondariesPenStart;
// Reserve the memory as RuntimeServices
PenBaseStatus = gBS->AllocatePages (AllocateAddress, EfiRuntimeServicesCode, EFI_SIZE_TO_PAGES (PenSize), &PenBase);
if (EFI_ERROR (PenBaseStatus)) {
Print (L"Warning: Failed to reserve the memory required for the secondary cores at 0x%lX, Status = %r\n", PenBase, PenBaseStatus);
// Even if there is a risk of memory corruption we carry on
}
// Put mailboxes below the pen code so we know where they are relative to code.
MailBoxBase = (UINTN)PenBase + ((UINTN)&SecondariesPenEnd - (UINTN)&SecondariesPenStart);
// Make sure this is 8 byte aligned.
if (MailBoxBase % sizeof(MailBoxBase) != 0) {
MailBoxBase += sizeof(MailBoxBase) - MailBoxBase % sizeof(MailBoxBase);
}
CopyMem ( (VOID*)(PenBase), (VOID*)&SecondariesPenStart, PenSize);
// Update the MailboxBase variable used in the pen code
*(UINTN*)(PenBase + ((UINTN)&AsmMailboxbase - (UINTN)&SecondariesPenStart)) = MailBoxBase;
for (Index=0; Index < gST->NumberOfTableEntries; Index++) {
// Check for correct GUID type
if (CompareGuid (&gArmMpCoreInfoGuid, &(gST->ConfigurationTable[Index].VendorGuid))) {
UINTN i;
// Get them under our control. Move from depending on 32bit reg(sys_flags) and SWI
// to 64 bit addr and WFE
ArmProcessorTable = (ARM_PROCESSOR_TABLE *)gST->ConfigurationTable[Index].VendorTable;
ArmCoreInfoTable = ArmProcessorTable->ArmCpus;
for (i = 0; i < ArmProcessorTable->NumberOfEntries; i++ ) {
// This goes into the SYSFLAGS register for the VE platform. We only have one 32bit reg to use
MmioWrite32(ArmCoreInfoTable[i].MailboxSetAddress, (UINTN)PenBase);
// So FDT can set the mailboxes correctly with the parser. These are 64bit Memory locations.
ArmCoreInfoTable[i].MailboxSetAddress = (UINTN)MailBoxBase + i*sizeof(MailBoxBase);
// Clear the mailboxes for the respective cores
*((UINTN*)(ArmCoreInfoTable[i].MailboxSetAddress)) = 0x0;
}
}
}
// Flush caches to make sure our pen gets to mem before we free the cores.
ArmCleanDataCache();
}
// By setting address=0 we leave the memory allocation to the function
Status = PrepareFdt (Arguments, InitrdImage, InitrdImageSize, &FdtBlobBase, &FdtBlobSize);
if (EFI_ERROR(Status)) {
Print(L"ERROR: Can not load Linux kernel with Device Tree. Status=0x%X\n", Status);
goto EXIT_FREE_FDT;
}
return StartLinux (LinuxImage, LinuxImageSize, FdtBlobBase, FdtBlobSize);
EXIT_FREE_FDT:
if (!EFI_ERROR (PenBaseStatus)) {
gBS->FreePages (PenBase, EFI_SIZE_TO_PAGES (PenSize));
}
gBS->FreePages (FdtBlobBase, EFI_SIZE_TO_PAGES (FdtBlobSize));
EXIT_FREE_INITRD:
if (InitrdDevicePath) {
gBS->FreePages (InitrdImageBase, EFI_SIZE_TO_PAGES (InitrdImageBaseSize));
}
EXIT_FREE_LINUX:
gBS->FreePages (LinuxImage, EFI_SIZE_TO_PAGES (LinuxImageSize));
return Status;
}

View File

@ -1,58 +0,0 @@
//
// Copyright (c) 2011-2013, ARM Limited. All rights reserved.
//
// This program and the accompanying materials
// are licensed and made available under the terms and conditions of the BSD License
// which accompanies this distribution. The full text of the license may be found at
// http://opensource.org/licenses/bsd-license.php
//
// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
//
//
/* Secondary core pens for AArch64 Linux booting.
This code it placed in Linux kernel memory and marked reserved. UEFI ensures
that the secondary cores get to this pen and the kernel can then start the
cores from here.
NOTE: This code must be self-contained.
*/
#include <Library/ArmLib.h>
.text
.align 3
GCC_ASM_EXPORT(SecondariesPenStart)
ASM_GLOBAL SecondariesPenEnd
ASM_PFX(SecondariesPenStart):
// Registers x0-x3 are reserved for future use and should be set to zero.
mov x0, xzr
mov x1, xzr
mov x2, xzr
mov x3, xzr
// Get core position. Taken from ArmPlatformGetCorePosition().
// Assumes max 4 cores per cluster.
mrs x4, mpidr_el1 // Get MPCore register.
and x5, x4, #ARM_CORE_MASK // Get core number.
and x4, x4, #ARM_CLUSTER_MASK // Get cluster number.
add x4, x5, x4, LSR #6 // Add scaled cluster number to core number.
lsl x4, x4, 3 // Get mailbox offset for this core.
ldr x5, AsmMailboxbase // Get mailbox addr relative to pc (36 bytes ahead).
add x4, x4, x5 // Add core mailbox offset to base of mailbox.
1: ldr x5, [x4] // Load value from mailbox.
cmp xzr, x5 // Has the mailbox been set?
b.ne 2f // If so break out of loop.
wfe // If not, wait a bit.
b 1b // Wait over, check if mailbox set again.
2: br x5 // Jump to mailbox value.
.align 3 // Make sure the variable below is 8 byte aligned.
.global AsmMailboxbase
AsmMailboxbase: .xword 0xdeaddeadbeefbeef
SecondariesPenEnd:

View File

@ -1,173 +0,0 @@
/** @file
*
* Copyright (c) 2011-2012, ARM Limited. All rights reserved.
*
* This program and the accompanying materials
* are licensed and made available under the terms and conditions of the BSD License
* which accompanies this distribution. The full text of the license may be found at
* http://opensource.org/licenses/bsd-license.php
*
* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*
**/
#include "BdsInternal.h"
#include "BdsLinuxLoader.h"
// Point to the current ATAG
STATIC LINUX_ATAG *mLinuxKernelCurrentAtag;
STATIC
VOID
SetupCoreTag (
IN UINT32 PageSize
)
{
mLinuxKernelCurrentAtag->header.size = tag_size(LINUX_ATAG_CORE);
mLinuxKernelCurrentAtag->header.type = ATAG_CORE;
mLinuxKernelCurrentAtag->body.core_tag.flags = 1; /* ensure read-only */
mLinuxKernelCurrentAtag->body.core_tag.pagesize = PageSize; /* systems PageSize (4k) */
mLinuxKernelCurrentAtag->body.core_tag.rootdev = 0; /* zero root device (typically overridden from kernel command line )*/
// move pointer to next tag
mLinuxKernelCurrentAtag = next_tag_address(mLinuxKernelCurrentAtag);
}
STATIC
VOID
SetupMemTag (
IN UINTN StartAddress,
IN UINT32 Size
)
{
mLinuxKernelCurrentAtag->header.size = tag_size(LINUX_ATAG_MEM);
mLinuxKernelCurrentAtag->header.type = ATAG_MEM;
mLinuxKernelCurrentAtag->body.mem_tag.start = StartAddress; /* Start of memory chunk for AtagMem */
mLinuxKernelCurrentAtag->body.mem_tag.size = Size; /* Size of memory chunk for AtagMem */
// move pointer to next tag
mLinuxKernelCurrentAtag = next_tag_address(mLinuxKernelCurrentAtag);
}
STATIC
VOID
SetupCmdlineTag (
IN CONST CHAR8 *CmdLine
)
{
UINT32 LineLength;
// Increment the line length by 1 to account for the null string terminator character
LineLength = AsciiStrLen(CmdLine) + 1;
/* Check for NULL strings.
* Do not insert a tag for an empty CommandLine, don't even modify the tag address pointer.
* Remember, you have at least one null string terminator character.
*/
if(LineLength > 1) {
mLinuxKernelCurrentAtag->header.size = ((UINT32)sizeof(LINUX_ATAG_HEADER) + LineLength + (UINT32)3) >> 2;
mLinuxKernelCurrentAtag->header.type = ATAG_CMDLINE;
/* place CommandLine into tag */
AsciiStrCpy(mLinuxKernelCurrentAtag->body.cmdline_tag.cmdline, CmdLine);
// move pointer to next tag
mLinuxKernelCurrentAtag = next_tag_address(mLinuxKernelCurrentAtag);
}
}
STATIC
VOID
SetupInitrdTag (
IN UINT32 InitrdImage,
IN UINT32 InitrdImageSize
)
{
mLinuxKernelCurrentAtag->header.size = tag_size(LINUX_ATAG_INITRD2);
mLinuxKernelCurrentAtag->header.type = ATAG_INITRD2;
mLinuxKernelCurrentAtag->body.initrd2_tag.start = InitrdImage;
mLinuxKernelCurrentAtag->body.initrd2_tag.size = InitrdImageSize;
// Move pointer to next tag
mLinuxKernelCurrentAtag = next_tag_address(mLinuxKernelCurrentAtag);
}
STATIC
VOID
SetupEndTag (
VOID
)
{
// Empty tag ends list; this has zero length and no body
mLinuxKernelCurrentAtag->header.type = ATAG_NONE;
mLinuxKernelCurrentAtag->header.size = 0;
/* We can not calculate the next address by using the standard macro:
* Params = next_tag_address(Params);
* because it relies on the header.size, which here it is 0 (zero).
* The easiest way is to add the sizeof(mLinuxKernelCurrentAtag->header).
*/
mLinuxKernelCurrentAtag = (LINUX_ATAG*)((UINT32)mLinuxKernelCurrentAtag + sizeof(mLinuxKernelCurrentAtag->header));
}
EFI_STATUS
PrepareAtagList (
IN CONST CHAR8* CommandLineString,
IN EFI_PHYSICAL_ADDRESS InitrdImage,
IN UINTN InitrdImageSize,
OUT EFI_PHYSICAL_ADDRESS *AtagBase,
OUT UINT32 *AtagSize
)
{
EFI_STATUS Status;
LIST_ENTRY *ResourceLink;
LIST_ENTRY ResourceList;
EFI_PHYSICAL_ADDRESS AtagStartAddress;
BDS_SYSTEM_MEMORY_RESOURCE *Resource;
AtagStartAddress = LINUX_ATAG_MAX_OFFSET;
Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData, EFI_SIZE_TO_PAGES(ATAG_MAX_SIZE), &AtagStartAddress);
if (EFI_ERROR(Status)) {
DEBUG ((EFI_D_WARN, "Warning: Failed to allocate Atag at 0x%lX (%r). The Atag will be allocated somewhere else in System Memory.\n", AtagStartAddress, Status));
Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, EFI_SIZE_TO_PAGES(ATAG_MAX_SIZE), &AtagStartAddress);
ASSERT_EFI_ERROR(Status);
}
// Ready to setup the atag list
mLinuxKernelCurrentAtag = (LINUX_ATAG*)(UINTN)AtagStartAddress;
// Standard core tag 4k PageSize
SetupCoreTag( (UINT32)SIZE_4KB );
// Physical memory setup
GetSystemMemoryResources (&ResourceList);
ResourceLink = ResourceList.ForwardLink;
while (ResourceLink != NULL && ResourceLink != &ResourceList) {
Resource = (BDS_SYSTEM_MEMORY_RESOURCE*)ResourceLink;
DEBUG((EFI_D_INFO,"- [0x%08X,0x%08X]\n",(UINT32)Resource->PhysicalStart,(UINT32)Resource->PhysicalStart+(UINT32)Resource->ResourceLength));
SetupMemTag( (UINT32)Resource->PhysicalStart, (UINT32)Resource->ResourceLength );
ResourceLink = ResourceLink->ForwardLink;
}
// CommandLine setting root device
if (CommandLineString) {
SetupCmdlineTag (CommandLineString);
}
if (InitrdImageSize > 0 && InitrdImage != 0) {
SetupInitrdTag ((UINT32)InitrdImage, (UINT32)InitrdImageSize);
}
// End of tags
SetupEndTag();
// Calculate atag list size
*AtagBase = AtagStartAddress;
*AtagSize = (UINT32)mLinuxKernelCurrentAtag - (UINT32)AtagStartAddress + 1;
return EFI_SUCCESS;
}

View File

@ -1,323 +0,0 @@
/** @file
*
* Copyright (c) 2011-2014, ARM Limited. All rights reserved.
*
* This program and the accompanying materials
* are licensed and made available under the terms and conditions of the BSD License
* which accompanies this distribution. The full text of the license may be found at
* http://opensource.org/licenses/bsd-license.php
*
* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*
**/
#include <Guid/Fdt.h>
#include <libfdt.h>
#include "BdsInternal.h"
#include "BdsLinuxLoader.h"
#define ALIGN32_BELOW(addr) ALIGN_POINTER(addr - 32,32)
#define IS_ADDRESS_IN_REGION(RegionStart, RegionSize, Address) \
(((UINTN)(RegionStart) <= (UINTN)(Address)) && ((UINTN)(Address) <= ((UINTN)(RegionStart) + (UINTN)(RegionSize))))
STATIC
EFI_STATUS
PreparePlatformHardware (
VOID
)
{
//Note: Interrupts will be disabled by the GIC driver when ExitBootServices() will be called.
// Clean before Disable else the Stack gets corrupted with old data.
ArmCleanDataCache ();
ArmDisableDataCache ();
// Invalidate all the entries that might have snuck in.
ArmInvalidateDataCache ();
// Invalidate and disable the Instruction cache
ArmDisableInstructionCache ();
ArmInvalidateInstructionCache ();
// Turn off MMU
ArmDisableMmu();
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
StartLinux (
IN EFI_PHYSICAL_ADDRESS LinuxImage,
IN UINTN LinuxImageSize,
IN EFI_PHYSICAL_ADDRESS KernelParamsAddress,
IN UINTN KernelParamsSize,
IN UINT32 MachineType
)
{
EFI_STATUS Status;
LINUX_KERNEL LinuxKernel;
// 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.
Status = ShutdownUefiBootServices ();
if(EFI_ERROR(Status)) {
DEBUG((EFI_D_ERROR,"ERROR: Can not shutdown UEFI boot services. Status=0x%X\n", Status));
goto Exit;
}
// Move the kernel parameters to any address inside the first 1MB.
// This is necessary because the ARM Linux kernel requires
// the FTD / ATAG List to reside entirely inside the first 1MB of
// physical memory.
//Note: There is no requirement on the alignment
if (MachineType != ARM_FDT_MACHINE_TYPE) {
if (((UINTN)KernelParamsAddress > LINUX_ATAG_MAX_OFFSET) && (KernelParamsSize < PcdGet32(PcdArmLinuxAtagMaxOffset))) {
KernelParamsAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)CopyMem (ALIGN32_BELOW(LINUX_ATAG_MAX_OFFSET - KernelParamsSize), (VOID*)(UINTN)KernelParamsAddress, KernelParamsSize);
}
} else {
if (((UINTN)KernelParamsAddress > LINUX_FDT_MAX_OFFSET) && (KernelParamsSize < PcdGet32(PcdArmLinuxFdtMaxOffset))) {
KernelParamsAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)CopyMem (ALIGN32_BELOW(LINUX_FDT_MAX_OFFSET - KernelParamsSize), (VOID*)(UINTN)KernelParamsAddress, KernelParamsSize);
}
}
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;
}
// Check if the Linux Image is a uImage
if (*(UINT32*)LinuxKernel == LINUX_UIMAGE_SIGNATURE) {
// Assume the Image Entry Point is just after the uImage header (64-byte size)
LinuxKernel = (LINUX_KERNEL)((UINTN)LinuxKernel + 64);
LinuxImageSize -= 64;
}
// Check there is no overlapping between kernel and its parameters
// We can only assert because it is too late to fallback to UEFI (ExitBootServices has been called).
ASSERT (!IS_ADDRESS_IN_REGION(LinuxKernel, LinuxImageSize, KernelParamsAddress) &&
!IS_ADDRESS_IN_REGION(LinuxKernel, LinuxImageSize, KernelParamsAddress + KernelParamsSize));
//
// Switch off interrupts, caches, mmu, etc
//
Status = PreparePlatformHardware ();
ASSERT_EFI_ERROR(Status);
// Register and print out performance information
PERF_END (NULL, "BDS", NULL, 0);
if (PerformanceMeasurementEnabled ()) {
PrintPerformance ();
}
//
// Start the Linux Kernel
//
// Outside BootServices, so can't use Print();
DEBUG((EFI_D_ERROR, "\nStarting the kernel:\n\n"));
// Jump to kernel with register set
LinuxKernel ((UINTN)0, MachineType, (UINTN)KernelParamsAddress);
// Kernel should never exit
// After Life services are not provided
ASSERT(FALSE);
Exit:
// Only be here if we fail to start Linux
Print (L"ERROR : Can not start the kernel. Status=0x%X\n", Status);
// 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 arguments
@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* CommandLineArguments
)
{
EFI_STATUS Status;
UINT32 LinuxImageSize;
UINT32 InitrdImageBaseSize = 0;
UINT32 InitrdImageSize = 0;
UINT32 AtagSize;
EFI_PHYSICAL_ADDRESS AtagBase;
EFI_PHYSICAL_ADDRESS LinuxImage;
EFI_PHYSICAL_ADDRESS InitrdImageBase = 0;
EFI_PHYSICAL_ADDRESS InitrdImage = 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;
}
if (InitrdDevicePath) {
// Load the initrd near to the Linux kernel
InitrdImageBase = LINUX_KERNEL_MAX_OFFSET;
Status = BdsLoadImage (InitrdDevicePath, AllocateMaxAddress, &InitrdImageBase, &InitrdImageBaseSize);
if (Status == EFI_OUT_OF_RESOURCES) {
Status = BdsLoadImage (InitrdDevicePath, AllocateAnyPages, &InitrdImageBase, &InitrdImageBaseSize);
}
if (EFI_ERROR(Status)) {
Print (L"ERROR: Did not find initrd image.\n");
goto EXIT_FREE_LINUX;
}
// Check if the initrd is a uInitrd
if (*(UINT32*)((UINTN)InitrdImageBase) == LINUX_UIMAGE_SIGNATURE) {
// Skip the 64-byte image header
InitrdImage = (EFI_PHYSICAL_ADDRESS)((UINTN)InitrdImageBase + 64);
InitrdImageSize = InitrdImageBaseSize - 64;
} else {
InitrdImage = InitrdImageBase;
InitrdImageSize = InitrdImageBaseSize;
}
}
//
// Setup the Linux Kernel Parameters
//
// By setting address=0 we leave the memory allocation to the function
Status = PrepareAtagList (CommandLineArguments, InitrdImage, InitrdImageSize, &AtagBase, &AtagSize);
if (EFI_ERROR(Status)) {
Print(L"ERROR: Can not prepare ATAG list. Status=0x%X\n", Status);
goto EXIT_FREE_INITRD;
}
return StartLinux (LinuxImage, LinuxImageSize, AtagBase, AtagSize, PcdGet32(PcdArmMachineType));
EXIT_FREE_INITRD:
if (InitrdDevicePath) {
gBS->FreePages (InitrdImageBase, EFI_SIZE_TO_PAGES (InitrdImageBaseSize));
}
EXIT_FREE_LINUX:
gBS->FreePages (LinuxImage, EFI_SIZE_TO_PAGES (LinuxImageSize));
return Status;
}
/**
Start a Linux kernel from a Device Path
@param LinuxKernelDevicePath Device Path to the Linux Kernel
@param InitrdDevicePath Device Path to the Initrd
@param CommandLineArguments Linux command line
@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* CommandLineArguments
)
{
EFI_STATUS Status;
UINT32 LinuxImageSize;
UINT32 InitrdImageBaseSize = 0;
UINT32 InitrdImageSize = 0;
VOID *InstalledFdtBase;
UINT32 FdtBlobSize;
EFI_PHYSICAL_ADDRESS FdtBlobBase;
EFI_PHYSICAL_ADDRESS LinuxImage;
EFI_PHYSICAL_ADDRESS InitrdImageBase = 0;
EFI_PHYSICAL_ADDRESS InitrdImage = 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;
}
if (InitrdDevicePath) {
InitrdImageBase = LINUX_KERNEL_MAX_OFFSET;
Status = BdsLoadImage (InitrdDevicePath, AllocateMaxAddress, &InitrdImageBase, &InitrdImageBaseSize);
if (Status == EFI_OUT_OF_RESOURCES) {
Status = BdsLoadImage (InitrdDevicePath, AllocateAnyPages, &InitrdImageBase, &InitrdImageBaseSize);
}
if (EFI_ERROR(Status)) {
Print (L"ERROR: Did not find initrd image.\n");
goto EXIT_FREE_LINUX;
}
// Check if the initrd is a uInitrd
if (*(UINT32*)((UINTN)InitrdImageBase) == LINUX_UIMAGE_SIGNATURE) {
// Skip the 64-byte image header
InitrdImage = (EFI_PHYSICAL_ADDRESS)((UINTN)InitrdImageBase + 64);
InitrdImageSize = InitrdImageBaseSize - 64;
} else {
InitrdImage = InitrdImageBase;
InitrdImageSize = InitrdImageBaseSize;
}
}
//
// Get the FDT from the Configuration Table.
// The FDT will be reloaded in PrepareFdt() to a more appropriate
// location for the Linux Kernel.
//
Status = EfiGetSystemConfigurationTable (&gFdtTableGuid, &InstalledFdtBase);
if (EFI_ERROR (Status)) {
Print (L"ERROR: Did not get the Device Tree blob (%r).\n", Status);
goto EXIT_FREE_INITRD;
}
FdtBlobBase = (EFI_PHYSICAL_ADDRESS)(UINTN)InstalledFdtBase;
FdtBlobSize = fdt_totalsize (InstalledFdtBase);
// Update the Fdt with the Initrd information. The FDT will increase in size.
// By setting address=0 we leave the memory allocation to the function
Status = PrepareFdt (CommandLineArguments, InitrdImage, InitrdImageSize, &FdtBlobBase, &FdtBlobSize);
if (EFI_ERROR(Status)) {
Print(L"ERROR: Can not load kernel with FDT. Status=%r\n", Status);
goto EXIT_FREE_FDT;
}
return StartLinux (LinuxImage, LinuxImageSize, FdtBlobBase, FdtBlobSize, ARM_FDT_MACHINE_TYPE);
EXIT_FREE_FDT:
gBS->FreePages (FdtBlobBase, EFI_SIZE_TO_PAGES (FdtBlobSize));
EXIT_FREE_INITRD:
if (InitrdDevicePath) {
gBS->FreePages (InitrdImageBase, EFI_SIZE_TO_PAGES (InitrdImageBaseSize));
}
EXIT_FREE_LINUX:
gBS->FreePages (LinuxImage, EFI_SIZE_TO_PAGES (LinuxImageSize));
return Status;
}

View File

@ -1,6 +1,6 @@
/** @file
*
* Copyright (c) 2011-2013, ARM Limited. All rights reserved.
* Copyright (c) 2011-2015, ARM Limited. All rights reserved.
*
* This program and the accompanying materials
* are licensed and made available under the terms and conditions of the BSD License
@ -14,19 +14,6 @@
#include "BdsInternal.h"
#include <Library/HobLib.h>
#include <Library/TimerLib.h>
#include <Library/PrintLib.h>
#include <Library/SerialPortLib.h>
STATIC CHAR8 *mTokenList[] = {
/*"SEC",*/
"PEI",
"DXE",
"BDS",
NULL
};
EFI_STATUS
ShutdownUefiBootServices (
VOID
@ -129,169 +116,6 @@ BdsConnectAllDrivers (
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
InsertSystemMemoryResources (
LIST_ENTRY *ResourceList,
EFI_HOB_RESOURCE_DESCRIPTOR *ResHob
)
{
BDS_SYSTEM_MEMORY_RESOURCE *NewResource;
LIST_ENTRY *Link;
LIST_ENTRY *NextLink;
LIST_ENTRY AttachedResources;
BDS_SYSTEM_MEMORY_RESOURCE *Resource;
EFI_PHYSICAL_ADDRESS NewResourceEnd;
if (IsListEmpty (ResourceList)) {
NewResource = AllocateZeroPool (sizeof(BDS_SYSTEM_MEMORY_RESOURCE));
NewResource->PhysicalStart = ResHob->PhysicalStart;
NewResource->ResourceLength = ResHob->ResourceLength;
InsertTailList (ResourceList, &NewResource->Link);
return EFI_SUCCESS;
}
InitializeListHead (&AttachedResources);
Link = ResourceList->ForwardLink;
ASSERT (Link != NULL);
while (Link != ResourceList) {
Resource = (BDS_SYSTEM_MEMORY_RESOURCE*)Link;
// Sanity Check. The resources should not overlapped.
ASSERT(!((ResHob->PhysicalStart >= Resource->PhysicalStart) && (ResHob->PhysicalStart < (Resource->PhysicalStart + Resource->ResourceLength))));
ASSERT(!((ResHob->PhysicalStart + ResHob->ResourceLength - 1 >= Resource->PhysicalStart) &&
((ResHob->PhysicalStart + ResHob->ResourceLength - 1) < (Resource->PhysicalStart + Resource->ResourceLength))));
// The new resource is attached after this resource descriptor
if (ResHob->PhysicalStart == Resource->PhysicalStart + Resource->ResourceLength) {
Resource->ResourceLength = Resource->ResourceLength + ResHob->ResourceLength;
NextLink = RemoveEntryList (&Resource->Link);
InsertTailList (&AttachedResources, &Resource->Link);
Link = NextLink;
}
// The new resource is attached before this resource descriptor
else if (ResHob->PhysicalStart + ResHob->ResourceLength == Resource->PhysicalStart) {
Resource->PhysicalStart = ResHob->PhysicalStart;
Resource->ResourceLength = Resource->ResourceLength + ResHob->ResourceLength;
NextLink = RemoveEntryList (&Resource->Link);
InsertTailList (&AttachedResources, &Resource->Link);
Link = NextLink;
} else {
Link = Link->ForwardLink;
}
}
if (!IsListEmpty (&AttachedResources)) {
// See if we can merge the attached resource with other resources
NewResource = (BDS_SYSTEM_MEMORY_RESOURCE*)GetFirstNode (&AttachedResources);
Link = RemoveEntryList (&NewResource->Link);
while (!IsListEmpty (&AttachedResources)) {
// Merge resources
Resource = (BDS_SYSTEM_MEMORY_RESOURCE*)Link;
// Ensure they overlap each other
ASSERT(
((NewResource->PhysicalStart >= Resource->PhysicalStart) && (NewResource->PhysicalStart < (Resource->PhysicalStart + Resource->ResourceLength))) ||
(((NewResource->PhysicalStart + NewResource->ResourceLength) >= Resource->PhysicalStart) && ((NewResource->PhysicalStart + NewResource->ResourceLength) < (Resource->PhysicalStart + Resource->ResourceLength)))
);
NewResourceEnd = MAX (NewResource->PhysicalStart + NewResource->ResourceLength, Resource->PhysicalStart + Resource->ResourceLength);
NewResource->PhysicalStart = MIN (NewResource->PhysicalStart, Resource->PhysicalStart);
NewResource->ResourceLength = NewResourceEnd - NewResource->PhysicalStart;
Link = RemoveEntryList (Link);
}
} else {
// None of the Resource of the list is attached to this ResHob. Create a new entry for it
NewResource = AllocateZeroPool (sizeof(BDS_SYSTEM_MEMORY_RESOURCE));
NewResource->PhysicalStart = ResHob->PhysicalStart;
NewResource->ResourceLength = ResHob->ResourceLength;
}
InsertTailList (ResourceList, &NewResource->Link);
return EFI_SUCCESS;
}
EFI_STATUS
GetSystemMemoryResources (
IN LIST_ENTRY *ResourceList
)
{
EFI_HOB_RESOURCE_DESCRIPTOR *ResHob;
InitializeListHead (ResourceList);
// Find the first System Memory Resource Descriptor
ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);
while ((ResHob != NULL) && (ResHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY)) {
ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR,(VOID *)((UINTN)ResHob + ResHob->Header.HobLength));
}
// Did not find any
if (ResHob == NULL) {
return EFI_NOT_FOUND;
} else {
InsertSystemMemoryResources (ResourceList, ResHob);
}
ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR,(VOID *)((UINTN)ResHob + ResHob->Header.HobLength));
while (ResHob != NULL) {
if (ResHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {
InsertSystemMemoryResources (ResourceList, ResHob);
}
ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR,(VOID *)((UINTN)ResHob + ResHob->Header.HobLength));
}
return EFI_SUCCESS;
}
VOID
PrintPerformance (
VOID
)
{
UINTN Key;
CONST VOID *Handle;
CONST CHAR8 *Token, *Module;
UINT64 Start, Stop, TimeStamp;
UINT64 Delta, TicksPerSecond, Milliseconds;
UINTN Index;
CHAR8 Buffer[100];
UINTN CharCount;
BOOLEAN CountUp;
TicksPerSecond = GetPerformanceCounterProperties (&Start, &Stop);
if (Start < Stop) {
CountUp = TRUE;
} else {
CountUp = FALSE;
}
TimeStamp = 0;
Key = 0;
do {
Key = GetPerformanceMeasurement (Key, (CONST VOID **)&Handle, &Token, &Module, &Start, &Stop);
if (Key != 0) {
for (Index = 0; mTokenList[Index] != NULL; Index++) {
if (AsciiStriCmp (mTokenList[Index], Token) == 0) {
Delta = CountUp?(Stop - Start):(Start - Stop);
TimeStamp += Delta;
Milliseconds = DivU64x64Remainder (MultU64x32 (Delta, 1000), TicksPerSecond, NULL);
CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"%6a %6ld ms\n", Token, Milliseconds);
SerialPortWrite ((UINT8 *) Buffer, CharCount);
break;
}
}
}
} while (Key != 0);
CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"Total Time = %ld ms\n\n", DivU64x64Remainder (MultU64x32 (TimeStamp, 1000), TicksPerSecond, NULL));
SerialPortWrite ((UINT8 *) Buffer, CharCount);
}
EFI_STATUS
GetGlobalEnvironmentVariable (
IN CONST CHAR16* VariableName,

View File

@ -28,11 +28,9 @@
#include <Library/DebugLib.h>
#include <Library/BdsLib.h>
#include <Library/PcdLib.h>
#include <Library/PerformanceLib.h>
#include <Library/PrintLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Guid/ArmMpCoreInfo.h>
#include <Guid/GlobalVariable.h>
#include <Guid/FileInfo.h>
@ -102,17 +100,6 @@ typedef struct {
UINT64 LastReportedNbOfBytes;
} BDS_TFTP_CONTEXT;
// BdsHelper.c
EFI_STATUS
GetSystemMemoryResources (
LIST_ENTRY *ResourceList
);
VOID
PrintPerformance (
VOID
);
EFI_STATUS
BdsLoadImage (
IN EFI_DEVICE_PATH *DevicePath,

View File

@ -25,15 +25,6 @@
BdsAppLoader.c
BdsHelper.c
BdsLoadOption.c
BdsLinuxFdt.c
[Sources.ARM]
Arm/BdsLinuxLoader.c
Arm/BdsLinuxAtag.c
[Sources.AARCH64]
AArch64/BdsLinuxLoader.c
AArch64/BdsLinuxLoaderHelper.S
[Packages]
EmbeddedPkg/EmbeddedPkg.dec
@ -44,26 +35,16 @@
[LibraryClasses]
ArmLib
ArmSmcLib
BaseLib
DebugLib
DevicePathLib
HobLib
PcdLib
PerformanceLib
SerialPortLib
FdtLib
TimerLib
NetLib
[LibraryClasses.AARCH64]
ArmGicLib
[Guids]
gEfiFileInfoGuid
gArmMpCoreInfoGuid
gArmGlobalVariableGuid
gFdtTableGuid
[Protocols]
gEfiBdsArchProtocolGuid
@ -82,27 +63,8 @@
gEfiMtftp4ServiceBindingProtocolGuid
gEfiMtftp4ProtocolGuid
[FeaturePcd]
gArmTokenSpaceGuid.PcdArmLinuxSpinTable
[Pcd]
gArmTokenSpaceGuid.PcdSystemMemoryBase
gArmTokenSpaceGuid.PcdSystemMemorySize
[FixedPcd]
gArmTokenSpaceGuid.PcdArmMachineType
gArmTokenSpaceGuid.PcdArmLinuxFdtMaxOffset
gArmTokenSpaceGuid.PcdArmLinuxFdtAlignment
gArmTokenSpaceGuid.PcdArmLinuxKernelMaxOffset
gArmTokenSpaceGuid.PcdMaxTftpFileSize
[FixedPcd.ARM]
gArmTokenSpaceGuid.PcdArmLinuxAtagMaxOffset
[Pcd.AARCH64]
gArmTokenSpaceGuid.PcdGicDistributorBase
gArmTokenSpaceGuid.PcdGicSgiIntId
[Depex]
TRUE

View File

@ -1,572 +0,0 @@
/** @file
*
* Copyright (c) 2011-2014, ARM Limited. All rights reserved.
*
* This program and the accompanying materials
* are licensed and made available under the terms and conditions of the BSD License
* which accompanies this distribution. The full text of the license may be found at
* http://opensource.org/licenses/bsd-license.php
*
* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*
**/
#include <Library/ArmSmcLib.h>
#include <Library/PcdLib.h>
#include <libfdt.h>
#include "BdsInternal.h"
#include "BdsLinuxLoader.h"
#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
#define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a))))
#define GET_CELL(p) (p += 4, *((const UINT32 *)(p-4)))
STATIC
UINTN
cpu_to_fdtn (UINTN x) {
if (sizeof (UINTN) == sizeof (UINT32)) {
return cpu_to_fdt32 (x);
} else {
return cpu_to_fdt64 (x);
}
}
typedef struct {
UINTN Base;
UINTN Size;
} FdtRegion;
STATIC
UINTN
IsPrintableString (
IN CONST VOID* data,
IN UINTN len
)
{
CONST CHAR8 *s = data;
CONST CHAR8 *ss;
// Zero length is not
if (len == 0) {
return 0;
}
// Must terminate with zero
if (s[len - 1] != '\0') {
return 0;
}
ss = s;
while (*s/* && isprint(*s)*/) {
s++;
}
// Not zero, or not done yet
if (*s != '\0' || (s + 1 - ss) < len) {
return 0;
}
return 1;
}
STATIC
VOID
PrintData (
IN CONST CHAR8* data,
IN UINTN len
)
{
UINTN i;
CONST CHAR8 *p = data;
// No data, don't print
if (len == 0)
return;
if (IsPrintableString (data, len)) {
Print(L" = \"%a\"", (const char *)data);
} else if ((len % 4) == 0) {
Print(L" = <");
for (i = 0; i < len; i += 4) {
Print(L"0x%08x%a", fdt32_to_cpu(GET_CELL(p)),i < (len - 4) ? " " : "");
}
Print(L">");
} else {
Print(L" = [");
for (i = 0; i < len; i++)
Print(L"%02x%a", *p++, i < len - 1 ? " " : "");
Print(L"]");
}
}
VOID
DebugDumpFdt (
IN VOID* FdtBlob
)
{
struct fdt_header *bph;
UINT32 off_dt;
UINT32 off_str;
CONST CHAR8* p_struct;
CONST CHAR8* p_strings;
CONST CHAR8* p;
CONST CHAR8* s;
CONST CHAR8* t;
UINT32 tag;
UINTN sz;
UINTN depth;
UINTN shift;
UINT32 version;
{
// Can 'memreserve' be printed by below code?
INTN num = fdt_num_mem_rsv(FdtBlob);
INTN i, err;
UINT64 addr = 0,size = 0;
for (i = 0; i < num; i++) {
err = fdt_get_mem_rsv(FdtBlob, i, &addr, &size);
if (err) {
DEBUG((EFI_D_ERROR, "Error (%d) : Cannot get memreserve section (%d)\n", err, i));
}
else {
Print(L"/memreserve/ \t0x%lx \t0x%lx;\n",addr,size);
}
}
}
depth = 0;
shift = 4;
bph = FdtBlob;
off_dt = fdt32_to_cpu(bph->off_dt_struct);
off_str = fdt32_to_cpu(bph->off_dt_strings);
p_struct = (CONST CHAR8*)FdtBlob + off_dt;
p_strings = (CONST CHAR8*)FdtBlob + off_str;
version = fdt32_to_cpu(bph->version);
p = p_struct;
while ((tag = fdt32_to_cpu(GET_CELL(p))) != FDT_END) {
if (tag == FDT_BEGIN_NODE) {
s = p;
p = PALIGN(p + AsciiStrLen (s) + 1, 4);
if (*s == '\0')
s = "/";
Print(L"%*s%a {\n", depth * shift, L" ", s);
depth++;
continue;
}
if (tag == FDT_END_NODE) {
depth--;
Print(L"%*s};\n", depth * shift, L" ");
continue;
}
if (tag == FDT_NOP) {
Print(L"%*s// [NOP]\n", depth * shift, L" ");
continue;
}
if (tag != FDT_PROP) {
Print(L"%*s ** Unknown tag 0x%08x\n", depth * shift, L" ", tag);
break;
}
sz = fdt32_to_cpu(GET_CELL(p));
s = p_strings + fdt32_to_cpu(GET_CELL(p));
if (version < 16 && sz >= 8)
p = PALIGN(p, 8);
t = p;
p = PALIGN(p + sz, 4);
Print(L"%*s%a", depth * shift, L" ", s);
PrintData(t, sz);
Print(L";\n");
}
}
STATIC
BOOLEAN
IsLinuxReservedRegion (
IN EFI_MEMORY_TYPE MemoryType
)
{
switch(MemoryType) {
case EfiRuntimeServicesCode:
case EfiRuntimeServicesData:
case EfiUnusableMemory:
case EfiACPIReclaimMemory:
case EfiACPIMemoryNVS:
case EfiReservedMemoryType:
return TRUE;
default:
return FALSE;
}
}
/**
** Relocate the FDT blob to a more appropriate location for the Linux kernel.
** This function will allocate memory for the relocated FDT blob.
**
** @retval EFI_SUCCESS on success.
** @retval EFI_OUT_OF_RESOURCES or EFI_INVALID_PARAMETER on failure.
*/
STATIC
EFI_STATUS
RelocateFdt (
EFI_PHYSICAL_ADDRESS OriginalFdt,
UINTN OriginalFdtSize,
EFI_PHYSICAL_ADDRESS *RelocatedFdt,
UINTN *RelocatedFdtSize,
EFI_PHYSICAL_ADDRESS *RelocatedFdtAlloc
)
{
EFI_STATUS Status;
INTN Error;
UINT64 FdtAlignment;
*RelocatedFdtSize = OriginalFdtSize + FDT_ADDITIONAL_ENTRIES_SIZE;
// If FDT load address needs to be aligned, allocate more space.
FdtAlignment = PcdGet32 (PcdArmLinuxFdtAlignment);
if (FdtAlignment != 0) {
*RelocatedFdtSize += FdtAlignment;
}
// Try below a watermark address.
Status = EFI_NOT_FOUND;
if (PcdGet32 (PcdArmLinuxFdtMaxOffset) != 0) {
*RelocatedFdt = LINUX_FDT_MAX_OFFSET;
Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData,
EFI_SIZE_TO_PAGES (*RelocatedFdtSize), RelocatedFdt);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_WARN, "Warning: Failed to load FDT below address 0x%lX (%r). Will try again at a random address anywhere.\n", *RelocatedFdt, Status));
}
}
// Try anywhere there is available space.
if (EFI_ERROR (Status)) {
Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData,
EFI_SIZE_TO_PAGES (*RelocatedFdtSize), RelocatedFdt);
if (EFI_ERROR (Status)) {
ASSERT_EFI_ERROR (Status);
return EFI_OUT_OF_RESOURCES;
} else {
DEBUG ((EFI_D_WARN, "WARNING: Loaded FDT at random address 0x%lX.\nWARNING: There is a risk of accidental overwriting by other code/data.\n", *RelocatedFdt));
}
}
*RelocatedFdtAlloc = *RelocatedFdt;
if (FdtAlignment != 0) {
*RelocatedFdt = ALIGN (*RelocatedFdt, FdtAlignment);
}
// Load the Original FDT tree into the new region
Error = fdt_open_into ((VOID*)(UINTN) OriginalFdt,
(VOID*)(UINTN)(*RelocatedFdt), *RelocatedFdtSize);
if (Error) {
DEBUG ((EFI_D_ERROR, "fdt_open_into(): %a\n", fdt_strerror (Error)));
gBS->FreePages (*RelocatedFdtAlloc, EFI_SIZE_TO_PAGES (*RelocatedFdtSize));
return EFI_INVALID_PARAMETER;
}
DEBUG_CODE_BEGIN();
//DebugDumpFdt (fdt);
DEBUG_CODE_END();
return EFI_SUCCESS;
}
EFI_STATUS
PrepareFdt (
IN CONST CHAR8* CommandLineArguments,
IN EFI_PHYSICAL_ADDRESS InitrdImage,
IN UINTN InitrdImageSize,
IN OUT EFI_PHYSICAL_ADDRESS *FdtBlobBase,
IN OUT UINTN *FdtBlobSize
)
{
EFI_STATUS Status;
EFI_PHYSICAL_ADDRESS NewFdtBlobBase;
EFI_PHYSICAL_ADDRESS NewFdtBlobAllocation;
UINTN NewFdtBlobSize;
VOID* fdt;
INTN err;
INTN node;
INTN cpu_node;
INT32 lenp;
CONST VOID* BootArg;
CONST VOID* Method;
EFI_PHYSICAL_ADDRESS InitrdImageStart;
EFI_PHYSICAL_ADDRESS InitrdImageEnd;
FdtRegion Region;
UINTN Index;
CHAR8 Name[10];
LIST_ENTRY ResourceList;
BDS_SYSTEM_MEMORY_RESOURCE *Resource;
ARM_PROCESSOR_TABLE *ArmProcessorTable;
ARM_CORE_INFO *ArmCoreInfoTable;
UINT32 MpId;
UINT32 ClusterId;
UINT32 CoreId;
UINT64 CpuReleaseAddr;
UINTN MemoryMapSize;
EFI_MEMORY_DESCRIPTOR *MemoryMap;
EFI_MEMORY_DESCRIPTOR *MemoryMapPtr;
UINTN MapKey;
UINTN DescriptorSize;
UINT32 DescriptorVersion;
UINTN Pages;
UINTN OriginalFdtSize;
BOOLEAN CpusNodeExist;
UINTN CoreMpId;
NewFdtBlobAllocation = 0;
//
// Sanity checks on the original FDT blob.
//
err = fdt_check_header ((VOID*)(UINTN)(*FdtBlobBase));
if (err != 0) {
Print (L"ERROR: Device Tree header not valid (err:%d)\n", err);
return EFI_INVALID_PARAMETER;
}
// The original FDT blob might have been loaded partially.
// Check that it is not the case.
OriginalFdtSize = (UINTN)fdt_totalsize ((VOID*)(UINTN)(*FdtBlobBase));
if (OriginalFdtSize > *FdtBlobSize) {
Print (L"ERROR: Incomplete FDT. Only %d/%d bytes have been loaded.\n",
*FdtBlobSize, OriginalFdtSize);
return EFI_INVALID_PARAMETER;
}
//
// Relocate the FDT to its final location.
//
Status = RelocateFdt (*FdtBlobBase, OriginalFdtSize,
&NewFdtBlobBase, &NewFdtBlobSize, &NewFdtBlobAllocation);
if (EFI_ERROR (Status)) {
goto FAIL_RELOCATE_FDT;
}
fdt = (VOID*)(UINTN)NewFdtBlobBase;
node = fdt_subnode_offset (fdt, 0, "chosen");
if (node < 0) {
// The 'chosen' node does not exist, create it
node = fdt_add_subnode(fdt, 0, "chosen");
if (node < 0) {
DEBUG((EFI_D_ERROR,"Error on finding 'chosen' node\n"));
Status = EFI_INVALID_PARAMETER;
goto FAIL_COMPLETE_FDT;
}
}
DEBUG_CODE_BEGIN();
BootArg = fdt_getprop(fdt, node, "bootargs", &lenp);
if (BootArg != NULL) {
DEBUG((EFI_D_ERROR,"BootArg: %a\n",BootArg));
}
DEBUG_CODE_END();
//
// Set Linux CmdLine
//
if ((CommandLineArguments != NULL) && (AsciiStrLen (CommandLineArguments) > 0)) {
err = fdt_setprop(fdt, node, "bootargs", CommandLineArguments, AsciiStrSize(CommandLineArguments));
if (err) {
DEBUG((EFI_D_ERROR,"Fail to set new 'bootarg' (err:%d)\n",err));
}
}
//
// Set Linux Initrd
//
if (InitrdImageSize != 0) {
InitrdImageStart = cpu_to_fdt64 (InitrdImage);
err = fdt_setprop(fdt, node, "linux,initrd-start", &InitrdImageStart, sizeof(EFI_PHYSICAL_ADDRESS));
if (err) {
DEBUG((EFI_D_ERROR,"Fail to set new 'linux,initrd-start' (err:%d)\n",err));
}
InitrdImageEnd = cpu_to_fdt64 (InitrdImage + InitrdImageSize);
err = fdt_setprop(fdt, node, "linux,initrd-end", &InitrdImageEnd, sizeof(EFI_PHYSICAL_ADDRESS));
if (err) {
DEBUG((EFI_D_ERROR,"Fail to set new 'linux,initrd-start' (err:%d)\n",err));
}
}
//
// Set Physical memory setup if does not exist
//
node = fdt_subnode_offset(fdt, 0, "memory");
if (node < 0) {
// The 'memory' node does not exist, create it
node = fdt_add_subnode(fdt, 0, "memory");
if (node >= 0) {
fdt_setprop_string(fdt, node, "name", "memory");
fdt_setprop_string(fdt, node, "device_type", "memory");
GetSystemMemoryResources (&ResourceList);
Resource = (BDS_SYSTEM_MEMORY_RESOURCE*)ResourceList.ForwardLink;
Region.Base = cpu_to_fdtn ((UINTN)Resource->PhysicalStart);
Region.Size = cpu_to_fdtn ((UINTN)Resource->ResourceLength);
err = fdt_setprop(fdt, node, "reg", &Region, sizeof(Region));
if (err) {
DEBUG((EFI_D_ERROR,"Fail to set new 'memory region' (err:%d)\n",err));
}
}
}
//
// Add the memory regions reserved by the UEFI Firmware
//
// Retrieve the UEFI Memory Map
MemoryMap = NULL;
MemoryMapSize = 0;
Status = gBS->GetMemoryMap (&MemoryMapSize, MemoryMap, &MapKey, &DescriptorSize, &DescriptorVersion);
if (Status == EFI_BUFFER_TOO_SMALL) {
// The UEFI specification advises to allocate more memory for the MemoryMap buffer between successive
// calls to GetMemoryMap(), since allocation of the new buffer may potentially increase memory map size.
Pages = EFI_SIZE_TO_PAGES (MemoryMapSize) + 1;
MemoryMap = AllocatePages (Pages);
if (MemoryMap == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto FAIL_COMPLETE_FDT;
}
Status = gBS->GetMemoryMap (&MemoryMapSize, MemoryMap, &MapKey, &DescriptorSize, &DescriptorVersion);
}
// Go through the list and add the reserved region to the Device Tree
if (!EFI_ERROR(Status)) {
MemoryMapPtr = MemoryMap;
for (Index = 0; Index < (MemoryMapSize / DescriptorSize); Index++) {
if (IsLinuxReservedRegion ((EFI_MEMORY_TYPE)MemoryMapPtr->Type)) {
DEBUG((DEBUG_VERBOSE, "Reserved region of type %d [0x%lX, 0x%lX]\n",
MemoryMapPtr->Type,
(UINTN)MemoryMapPtr->PhysicalStart,
(UINTN)(MemoryMapPtr->PhysicalStart + MemoryMapPtr->NumberOfPages * EFI_PAGE_SIZE)));
err = fdt_add_mem_rsv(fdt, MemoryMapPtr->PhysicalStart, MemoryMapPtr->NumberOfPages * EFI_PAGE_SIZE);
if (err != 0) {
Print(L"Warning: Fail to add 'memreserve' (err:%d)\n", err);
}
}
MemoryMapPtr = (EFI_MEMORY_DESCRIPTOR*)((UINTN)MemoryMapPtr + DescriptorSize);
}
}
//
// Setup Arm Mpcore Info if it is a multi-core or multi-cluster platforms.
//
// For 'cpus' and 'cpu' device tree nodes bindings, refer to this file
// in the kernel documentation:
// Documentation/devicetree/bindings/arm/cpus.txt
//
for (Index=0; Index < gST->NumberOfTableEntries; Index++) {
// Check for correct GUID type
if (CompareGuid (&gArmMpCoreInfoGuid, &(gST->ConfigurationTable[Index].VendorGuid))) {
MpId = ArmReadMpidr ();
ClusterId = GET_CLUSTER_ID(MpId);
CoreId = GET_CORE_ID(MpId);
node = fdt_subnode_offset(fdt, 0, "cpus");
if (node < 0) {
// Create the /cpus node
node = fdt_add_subnode(fdt, 0, "cpus");
fdt_setprop_string(fdt, node, "name", "cpus");
fdt_setprop_cell (fdt, node, "#address-cells", sizeof (UINTN) / 4);
fdt_setprop_cell(fdt, node, "#size-cells", 0);
CpusNodeExist = FALSE;
} else {
CpusNodeExist = TRUE;
}
// Get pointer to ARM processor table
ArmProcessorTable = (ARM_PROCESSOR_TABLE *)gST->ConfigurationTable[Index].VendorTable;
ArmCoreInfoTable = ArmProcessorTable->ArmCpus;
for (Index = 0; Index < ArmProcessorTable->NumberOfEntries; Index++) {
CoreMpId = (UINTN) GET_MPID (ArmCoreInfoTable[Index].ClusterId,
ArmCoreInfoTable[Index].CoreId);
AsciiSPrint (Name, 10, "cpu@%x", CoreMpId);
// If the 'cpus' node did not exist then create all the 'cpu' nodes.
// In case 'cpus' node is provided in the original FDT then we do not add
// any 'cpu' node.
if (!CpusNodeExist) {
cpu_node = fdt_add_subnode (fdt, node, Name);
if (cpu_node < 0) {
DEBUG ((EFI_D_ERROR, "Error on creating '%s' node\n", Name));
Status = EFI_INVALID_PARAMETER;
goto FAIL_COMPLETE_FDT;
}
fdt_setprop_string (fdt, cpu_node, "device_type", "cpu");
CoreMpId = cpu_to_fdtn (CoreMpId);
fdt_setprop (fdt, cpu_node, "reg", &CoreMpId, sizeof (CoreMpId));
} else {
cpu_node = fdt_subnode_offset(fdt, node, Name);
}
if (cpu_node >= 0) {
Method = fdt_getprop (fdt, cpu_node, "enable-method", &lenp);
// We only care when 'enable-method' == 'spin-table'. If the enable-method is not defined
// or defined as 'psci' then we ignore its properties.
if ((Method != NULL) && (AsciiStrCmp ((CHAR8 *)Method, "spin-table") == 0)) {
// There are two cases;
// - UEFI firmware parked the secondary cores and/or UEFI firmware is aware of the CPU
// release addresses (PcdArmLinuxSpinTable == TRUE)
// - the parking of the secondary cores has been managed before starting UEFI and/or UEFI
// does not anything about the CPU release addresses - in this case we do nothing
if (FeaturePcdGet (PcdArmLinuxSpinTable)) {
CpuReleaseAddr = cpu_to_fdt64 (ArmCoreInfoTable[Index].MailboxSetAddress);
fdt_setprop (fdt, cpu_node, "cpu-release-addr", &CpuReleaseAddr, sizeof(CpuReleaseAddr));
// If it is not the primary core than the cpu should be disabled
if (((ArmCoreInfoTable[Index].ClusterId != ClusterId) || (ArmCoreInfoTable[Index].CoreId != CoreId))) {
fdt_setprop_string(fdt, cpu_node, "status", "disabled");
}
}
}
}
}
break;
}
}
DEBUG_CODE_BEGIN();
//DebugDumpFdt (fdt);
DEBUG_CODE_END();
// If we succeeded to generate the new Device Tree then free the old Device Tree
gBS->FreePages (*FdtBlobBase, EFI_SIZE_TO_PAGES (*FdtBlobSize));
// Update the real size of the Device Tree
fdt_pack ((VOID*)(UINTN)(NewFdtBlobBase));
*FdtBlobBase = NewFdtBlobBase;
*FdtBlobSize = (UINTN)fdt_totalsize ((VOID*)(UINTN)(NewFdtBlobBase));
return EFI_SUCCESS;
FAIL_COMPLETE_FDT:
gBS->FreePages (NewFdtBlobAllocation, EFI_SIZE_TO_PAGES (NewFdtBlobSize));
FAIL_RELOCATE_FDT:
*FdtBlobSize = (UINTN)fdt_totalsize ((VOID*)(UINTN)(*FdtBlobBase));
// Return success even if we failed to update the FDT blob.
// The original one is still valid.
return EFI_SUCCESS;
}

View File

@ -1,156 +0,0 @@
/** @file
*
* Copyright (c) 2011-2013, ARM Limited. All rights reserved.
*
* This program and the accompanying materials
* are licensed and made available under the terms and conditions of the BSD License
* which accompanies this distribution. The full text of the license may be found at
* http://opensource.org/licenses/bsd-license.php
*
* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*
**/
#ifndef __BDSLINUXLOADER_H
#define __BDSLINUXLOADER_H
#define LINUX_UIMAGE_SIGNATURE 0x56190527
#define LINUX_KERNEL_MAX_OFFSET (PcdGet64 (PcdSystemMemoryBase) + PcdGet32(PcdArmLinuxKernelMaxOffset))
#define LINUX_ATAG_MAX_OFFSET (PcdGet64 (PcdSystemMemoryBase) + PcdGet32(PcdArmLinuxAtagMaxOffset))
#define LINUX_FDT_MAX_OFFSET (PcdGet64 (PcdSystemMemoryBase) + PcdGet32(PcdArmLinuxFdtMaxOffset))
// Additional size that could be used for FDT entries added by the UEFI OS Loader
// Estimation based on: EDID (300bytes) + bootargs (200bytes) + initrd region (20bytes)
// + system memory region (20bytes) + mp_core entries (200 bytes)
#define FDT_ADDITIONAL_ENTRIES_SIZE 0x300
#define ARM_FDT_MACHINE_TYPE 0xFFFFFFFF
typedef VOID (*LINUX_KERNEL)(UINT32 Zero, UINT32 Arch, UINTN ParametersBase);
//
// ATAG Definitions
//
#define ATAG_MAX_SIZE 0x3000
/* ATAG : list of possible tags */
#define ATAG_NONE 0x00000000
#define ATAG_CORE 0x54410001
#define ATAG_MEM 0x54410002
#define ATAG_VIDEOTEXT 0x54410003
#define ATAG_RAMDISK 0x54410004
#define ATAG_INITRD2 0x54420005
#define ATAG_SERIAL 0x54410006
#define ATAG_REVISION 0x54410007
#define ATAG_VIDEOLFB 0x54410008
#define ATAG_CMDLINE 0x54410009
#define ATAG_ARM_MP_CORE 0x5441000A
#define next_tag_address(t) ((LINUX_ATAG*)((UINT32)(t) + (((t)->header.size) << 2) ))
#define tag_size(type) ((UINT32)((sizeof(LINUX_ATAG_HEADER) + sizeof(type)) >> 2))
typedef struct {
UINT32 size; /* length of tag in words including this header */
UINT32 type; /* tag type */
} LINUX_ATAG_HEADER;
typedef struct {
UINT32 flags;
UINT32 pagesize;
UINT32 rootdev;
} LINUX_ATAG_CORE;
typedef struct {
UINT32 size;
UINTN start;
} LINUX_ATAG_MEM;
typedef struct {
UINT8 x;
UINT8 y;
UINT16 video_page;
UINT8 video_mode;
UINT8 video_cols;
UINT16 video_ega_bx;
UINT8 video_lines;
UINT8 video_isvga;
UINT16 video_points;
} LINUX_ATAG_VIDEOTEXT;
typedef struct {
UINT32 flags;
UINT32 size;
UINTN start;
} LINUX_ATAG_RAMDISK;
typedef struct {
UINT32 start;
UINT32 size;
} LINUX_ATAG_INITRD2;
typedef struct {
UINT32 low;
UINT32 high;
} LINUX_ATAG_SERIALNR;
typedef struct {
UINT32 rev;
} LINUX_ATAG_REVISION;
typedef struct {
UINT16 lfb_width;
UINT16 lfb_height;
UINT16 lfb_depth;
UINT16 lfb_linelength;
UINT32 lfb_base;
UINT32 lfb_size;
UINT8 red_size;
UINT8 red_pos;
UINT8 green_size;
UINT8 green_pos;
UINT8 blue_size;
UINT8 blue_pos;
UINT8 rsvd_size;
UINT8 rsvd_pos;
} LINUX_ATAG_VIDEOLFB;
typedef struct {
CHAR8 cmdline[1];
} LINUX_ATAG_CMDLINE;
typedef struct {
LINUX_ATAG_HEADER header;
union {
LINUX_ATAG_CORE core_tag;
LINUX_ATAG_MEM mem_tag;
LINUX_ATAG_VIDEOTEXT videotext_tag;
LINUX_ATAG_RAMDISK ramdisk_tag;
LINUX_ATAG_INITRD2 initrd2_tag;
LINUX_ATAG_SERIALNR serialnr_tag;
LINUX_ATAG_REVISION revision_tag;
LINUX_ATAG_VIDEOLFB videolfb_tag;
LINUX_ATAG_CMDLINE cmdline_tag;
} body;
} LINUX_ATAG;
EFI_STATUS
PrepareAtagList (
IN CONST CHAR8* CommandLineString,
IN EFI_PHYSICAL_ADDRESS InitrdImage,
IN UINTN InitrdImageSize,
OUT EFI_PHYSICAL_ADDRESS *AtagBase,
OUT UINT32 *AtagSize
);
EFI_STATUS
PrepareFdt (
IN CONST CHAR8* CommandLineArguments,
IN EFI_PHYSICAL_ADDRESS InitrdImage,
IN UINTN InitrdImageSize,
IN OUT EFI_PHYSICAL_ADDRESS *FdtBlobBase,
IN OUT UINTN *FdtBlobSize
);
#endif

View File

@ -39,6 +39,9 @@
EmbeddedPkg/EmbeddedPkg.dec
IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
[Guids]
gFdtTableGuid
[LibraryClasses]
BdsLib
TimerLib
@ -49,6 +52,7 @@
DebugLib
PrintLib
BaseLib
FdtLib
NetLib
[Guids]

View File

@ -1,6 +1,6 @@
/** @file
*
* Copyright (c) 2011-2014, ARM Limited. All rights reserved.
* Copyright (c) 2011-2015, ARM Limited. All rights reserved.
*
* This program and the accompanying materials
* are licensed and made available under the terms and conditions of the BSD License
@ -23,10 +23,6 @@ BootOptionStart (
EFI_STATUS Status;
UINT32 LoaderType;
ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData;
ARM_BDS_LINUX_ARGUMENTS* LinuxArguments;
UINTN CmdLineSize;
UINTN InitrdSize;
EFI_DEVICE_PATH* Initrd;
UINT16 LoadOptionIndexSize;
if (IS_ARM_BDS_BOOTENTRY (BootOption)) {
@ -42,34 +38,9 @@ BootOptionStart (
Status = BdsStartEfiApplication (gImageHandle, BootOption->FilePathList, 0, NULL);
} else if (LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) {
LinuxArguments = &(OptionalData->Arguments.LinuxArguments);
CmdLineSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->CmdLineSize);
InitrdSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->InitrdSize);
if (InitrdSize > 0) {
Initrd = GetAlignedDevicePath ((EFI_DEVICE_PATH*)((UINTN)(LinuxArguments + 1) + CmdLineSize));
} else {
Initrd = NULL;
}
Status = BdsBootLinuxAtag (BootOption->FilePathList,
Initrd, // Initrd
(CHAR8*)(LinuxArguments + 1)); // CmdLine
ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
} else if (LoaderType == BDS_LOADER_KERNEL_LINUX_FDT) {
LinuxArguments = &(OptionalData->Arguments.LinuxArguments);
CmdLineSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->CmdLineSize);
InitrdSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->InitrdSize);
if (InitrdSize > 0) {
Initrd = GetAlignedDevicePath ((EFI_DEVICE_PATH*)((UINTN)(LinuxArguments + 1) + CmdLineSize));
} else {
Initrd = NULL;
}
Status = BdsBootLinuxFdt (
BootOption->FilePathList,
Initrd,
(CHAR8*)(LinuxArguments + 1)
);
ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
}
} else {
// Connect all the drivers if the EFI Application is not a EFI OS Loader