mirror of https://github.com/acidanthera/audk.git
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:
parent
0ead5ec47d
commit
c75d3eb6be
|
@ -137,43 +137,6 @@ 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
|
|
||||||
|
|
||||||
@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
|
Start an EFI Application from a Device Path
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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:
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/** @file
|
/** @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
|
* This program and the accompanying materials
|
||||||
* are licensed and made available under the terms and conditions of the BSD License
|
* are licensed and made available under the terms and conditions of the BSD License
|
||||||
|
@ -14,19 +14,6 @@
|
||||||
|
|
||||||
#include "BdsInternal.h"
|
#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
|
EFI_STATUS
|
||||||
ShutdownUefiBootServices (
|
ShutdownUefiBootServices (
|
||||||
VOID
|
VOID
|
||||||
|
@ -129,169 +116,6 @@ BdsConnectAllDrivers (
|
||||||
return EFI_SUCCESS;
|
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
|
EFI_STATUS
|
||||||
GetGlobalEnvironmentVariable (
|
GetGlobalEnvironmentVariable (
|
||||||
IN CONST CHAR16* VariableName,
|
IN CONST CHAR16* VariableName,
|
||||||
|
|
|
@ -28,11 +28,9 @@
|
||||||
#include <Library/DebugLib.h>
|
#include <Library/DebugLib.h>
|
||||||
#include <Library/BdsLib.h>
|
#include <Library/BdsLib.h>
|
||||||
#include <Library/PcdLib.h>
|
#include <Library/PcdLib.h>
|
||||||
#include <Library/PerformanceLib.h>
|
|
||||||
#include <Library/PrintLib.h>
|
#include <Library/PrintLib.h>
|
||||||
#include <Library/UefiRuntimeServicesTableLib.h>
|
#include <Library/UefiRuntimeServicesTableLib.h>
|
||||||
|
|
||||||
#include <Guid/ArmMpCoreInfo.h>
|
|
||||||
#include <Guid/GlobalVariable.h>
|
#include <Guid/GlobalVariable.h>
|
||||||
#include <Guid/FileInfo.h>
|
#include <Guid/FileInfo.h>
|
||||||
|
|
||||||
|
@ -102,17 +100,6 @@ typedef struct {
|
||||||
UINT64 LastReportedNbOfBytes;
|
UINT64 LastReportedNbOfBytes;
|
||||||
} BDS_TFTP_CONTEXT;
|
} BDS_TFTP_CONTEXT;
|
||||||
|
|
||||||
// BdsHelper.c
|
|
||||||
EFI_STATUS
|
|
||||||
GetSystemMemoryResources (
|
|
||||||
LIST_ENTRY *ResourceList
|
|
||||||
);
|
|
||||||
|
|
||||||
VOID
|
|
||||||
PrintPerformance (
|
|
||||||
VOID
|
|
||||||
);
|
|
||||||
|
|
||||||
EFI_STATUS
|
EFI_STATUS
|
||||||
BdsLoadImage (
|
BdsLoadImage (
|
||||||
IN EFI_DEVICE_PATH *DevicePath,
|
IN EFI_DEVICE_PATH *DevicePath,
|
||||||
|
|
|
@ -25,15 +25,6 @@
|
||||||
BdsAppLoader.c
|
BdsAppLoader.c
|
||||||
BdsHelper.c
|
BdsHelper.c
|
||||||
BdsLoadOption.c
|
BdsLoadOption.c
|
||||||
BdsLinuxFdt.c
|
|
||||||
|
|
||||||
[Sources.ARM]
|
|
||||||
Arm/BdsLinuxLoader.c
|
|
||||||
Arm/BdsLinuxAtag.c
|
|
||||||
|
|
||||||
[Sources.AARCH64]
|
|
||||||
AArch64/BdsLinuxLoader.c
|
|
||||||
AArch64/BdsLinuxLoaderHelper.S
|
|
||||||
|
|
||||||
[Packages]
|
[Packages]
|
||||||
EmbeddedPkg/EmbeddedPkg.dec
|
EmbeddedPkg/EmbeddedPkg.dec
|
||||||
|
@ -44,26 +35,16 @@
|
||||||
|
|
||||||
[LibraryClasses]
|
[LibraryClasses]
|
||||||
ArmLib
|
ArmLib
|
||||||
ArmSmcLib
|
|
||||||
BaseLib
|
BaseLib
|
||||||
DebugLib
|
DebugLib
|
||||||
DevicePathLib
|
DevicePathLib
|
||||||
HobLib
|
HobLib
|
||||||
PcdLib
|
PcdLib
|
||||||
PerformanceLib
|
|
||||||
SerialPortLib
|
|
||||||
FdtLib
|
|
||||||
TimerLib
|
|
||||||
NetLib
|
NetLib
|
||||||
|
|
||||||
[LibraryClasses.AARCH64]
|
|
||||||
ArmGicLib
|
|
||||||
|
|
||||||
[Guids]
|
[Guids]
|
||||||
gEfiFileInfoGuid
|
gEfiFileInfoGuid
|
||||||
gArmMpCoreInfoGuid
|
|
||||||
gArmGlobalVariableGuid
|
gArmGlobalVariableGuid
|
||||||
gFdtTableGuid
|
|
||||||
|
|
||||||
[Protocols]
|
[Protocols]
|
||||||
gEfiBdsArchProtocolGuid
|
gEfiBdsArchProtocolGuid
|
||||||
|
@ -82,27 +63,8 @@
|
||||||
gEfiMtftp4ServiceBindingProtocolGuid
|
gEfiMtftp4ServiceBindingProtocolGuid
|
||||||
gEfiMtftp4ProtocolGuid
|
gEfiMtftp4ProtocolGuid
|
||||||
|
|
||||||
[FeaturePcd]
|
|
||||||
gArmTokenSpaceGuid.PcdArmLinuxSpinTable
|
|
||||||
|
|
||||||
[Pcd]
|
|
||||||
gArmTokenSpaceGuid.PcdSystemMemoryBase
|
|
||||||
gArmTokenSpaceGuid.PcdSystemMemorySize
|
|
||||||
|
|
||||||
[FixedPcd]
|
[FixedPcd]
|
||||||
gArmTokenSpaceGuid.PcdArmMachineType
|
|
||||||
gArmTokenSpaceGuid.PcdArmLinuxFdtMaxOffset
|
|
||||||
gArmTokenSpaceGuid.PcdArmLinuxFdtAlignment
|
|
||||||
gArmTokenSpaceGuid.PcdArmLinuxKernelMaxOffset
|
|
||||||
|
|
||||||
gArmTokenSpaceGuid.PcdMaxTftpFileSize
|
gArmTokenSpaceGuid.PcdMaxTftpFileSize
|
||||||
|
|
||||||
[FixedPcd.ARM]
|
|
||||||
gArmTokenSpaceGuid.PcdArmLinuxAtagMaxOffset
|
|
||||||
|
|
||||||
[Pcd.AARCH64]
|
|
||||||
gArmTokenSpaceGuid.PcdGicDistributorBase
|
|
||||||
gArmTokenSpaceGuid.PcdGicSgiIntId
|
|
||||||
|
|
||||||
[Depex]
|
[Depex]
|
||||||
TRUE
|
TRUE
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -39,6 +39,9 @@
|
||||||
EmbeddedPkg/EmbeddedPkg.dec
|
EmbeddedPkg/EmbeddedPkg.dec
|
||||||
IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
|
IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
|
||||||
|
|
||||||
|
[Guids]
|
||||||
|
gFdtTableGuid
|
||||||
|
|
||||||
[LibraryClasses]
|
[LibraryClasses]
|
||||||
BdsLib
|
BdsLib
|
||||||
TimerLib
|
TimerLib
|
||||||
|
@ -49,6 +52,7 @@
|
||||||
DebugLib
|
DebugLib
|
||||||
PrintLib
|
PrintLib
|
||||||
BaseLib
|
BaseLib
|
||||||
|
FdtLib
|
||||||
NetLib
|
NetLib
|
||||||
|
|
||||||
[Guids]
|
[Guids]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/** @file
|
/** @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
|
* This program and the accompanying materials
|
||||||
* are licensed and made available under the terms and conditions of the BSD License
|
* are licensed and made available under the terms and conditions of the BSD License
|
||||||
|
@ -23,10 +23,6 @@ BootOptionStart (
|
||||||
EFI_STATUS Status;
|
EFI_STATUS Status;
|
||||||
UINT32 LoaderType;
|
UINT32 LoaderType;
|
||||||
ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData;
|
ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData;
|
||||||
ARM_BDS_LINUX_ARGUMENTS* LinuxArguments;
|
|
||||||
UINTN CmdLineSize;
|
|
||||||
UINTN InitrdSize;
|
|
||||||
EFI_DEVICE_PATH* Initrd;
|
|
||||||
UINT16 LoadOptionIndexSize;
|
UINT16 LoadOptionIndexSize;
|
||||||
|
|
||||||
if (IS_ARM_BDS_BOOTENTRY (BootOption)) {
|
if (IS_ARM_BDS_BOOTENTRY (BootOption)) {
|
||||||
|
@ -42,34 +38,9 @@ BootOptionStart (
|
||||||
|
|
||||||
Status = BdsStartEfiApplication (gImageHandle, BootOption->FilePathList, 0, NULL);
|
Status = BdsStartEfiApplication (gImageHandle, BootOption->FilePathList, 0, NULL);
|
||||||
} else if (LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) {
|
} else if (LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) {
|
||||||
LinuxArguments = &(OptionalData->Arguments.LinuxArguments);
|
ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
|
||||||
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
|
|
||||||
} else if (LoaderType == BDS_LOADER_KERNEL_LINUX_FDT) {
|
} else if (LoaderType == BDS_LOADER_KERNEL_LINUX_FDT) {
|
||||||
LinuxArguments = &(OptionalData->Arguments.LinuxArguments);
|
ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
|
||||||
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)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Connect all the drivers if the EFI Application is not a EFI OS Loader
|
// Connect all the drivers if the EFI Application is not a EFI OS Loader
|
||||||
|
|
Loading…
Reference in New Issue