summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ArmPkg/Application/LinuxLoader/AArch64/LinuxStarter.c370
-rw-r--r--ArmPkg/Application/LinuxLoader/AArch64/LinuxStarterHelper.S58
-rw-r--r--ArmPkg/Application/LinuxLoader/Arm/LinuxAtag.c177
-rw-r--r--ArmPkg/Application/LinuxLoader/Arm/LinuxAtag.h124
-rw-r--r--ArmPkg/Application/LinuxLoader/Arm/LinuxStarter.c346
-rw-r--r--ArmPkg/Application/LinuxLoader/LinuxAtagLoader.c103
-rw-r--r--ArmPkg/Application/LinuxLoader/LinuxAtagLoader.inf39
-rw-r--r--ArmPkg/Application/LinuxLoader/LinuxConfig.c354
-rw-r--r--ArmPkg/Application/LinuxLoader/LinuxFdtLoader.c103
-rw-r--r--ArmPkg/Application/LinuxLoader/LinuxFdtLoader.inf39
-rw-r--r--ArmPkg/Application/LinuxLoader/LinuxInternal.h50
-rw-r--r--ArmPkg/Application/LinuxLoader/LinuxLoader.c246
-rw-r--r--ArmPkg/Application/LinuxLoader/LinuxLoader.h166
-rw-r--r--ArmPkg/Application/LinuxLoader/LinuxLoader.inf91
-rw-r--r--ArmPkg/Application/LinuxLoader/LinuxLoader.unibin0 -> 8166 bytes
-rw-r--r--ArmPkg/Application/LinuxLoader/LinuxLoaderEfiApp.c303
-rw-r--r--ArmPkg/Application/LinuxLoader/LinuxLoaderFdt.c411
-rw-r--r--ArmPkg/Application/LinuxLoader/LinuxLoaderHelper.c192
-rw-r--r--ArmPkg/Application/LinuxLoader/LinuxLoaderShellApp.c298
-rw-r--r--ArmPkg/ArmPkg.dsc8
20 files changed, 2787 insertions, 691 deletions
diff --git a/ArmPkg/Application/LinuxLoader/AArch64/LinuxStarter.c b/ArmPkg/Application/LinuxLoader/AArch64/LinuxStarter.c
new file mode 100644
index 0000000000..0d540c920f
--- /dev/null
+++ b/ArmPkg/Application/LinuxLoader/AArch64/LinuxStarter.c
@@ -0,0 +1,370 @@
+/** @file
+*
+* 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
+* 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/ArmLib.h>
+#include <Library/ArmGicLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+
+#include <Ppi/ArmMpCoreInfo.h>
+
+#include <Guid/Fdt.h>
+
+#include "LinuxLoader.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
+VOID
+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 ();
+}
+
+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));
+ return Status;
+ }
+
+ // 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
+ //
+ PreparePlatformHardware ();
+
+ // 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);
+
+ // We cannot recover the execution at this stage
+ while (1);
+}
+
+/**
+ Start a Linux kernel from a Device Path
+
+ @param SystemMemoryBase Base of the system memory
+ @param LinuxKernel Device Path to the Linux Kernel
+ @param Parameters Linux kernel arguments
+ @param Fdt Device Path to the Flat Device Tree
+ @param MachineType ARM machine type value
+
+ @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.
+ @retval RETURN_UNSUPPORTED ATAG is not support by this architecture
+
+**/
+EFI_STATUS
+BootLinuxAtag (
+ IN EFI_PHYSICAL_ADDRESS SystemMemoryBase,
+ IN EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath,
+ IN CONST CHAR8* CommandLineArguments,
+ IN UINTN MachineType
+ )
+{
+ // NOTE : AArch64 Linux kernel does not support ATAG, FDT only.
+ ASSERT (0);
+
+ return EFI_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
+BootLinuxFdt (
+ IN EFI_PHYSICAL_ADDRESS SystemMemoryBase,
+ IN EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL* FdtDevicePath,
+ 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 = SystemMemoryBase + 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;
+ }
+ }
+
+ if (FdtDevicePath == NULL) {
+ //
+ // 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);
+ } else {
+ //
+ // FDT device path explicitly defined. The FDT is relocated later to a
+ // more appropriate location for the Linux kernel.
+ //
+ FdtBlobBase = LINUX_KERNEL_MAX_OFFSET;
+ Status = BdsLoadImage (FdtDevicePath, AllocateMaxAddress, &FdtBlobBase, &FdtBlobSize);
+ if (EFI_ERROR (Status)) {
+ Print (L"ERROR: Did not find Device Tree blob (%r).\n", Status);
+ goto EXIT_FREE_INITRD;
+ }
+ }
+
+ //
+ // 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 (SystemMemoryBase, 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;
+}
diff --git a/ArmPkg/Application/LinuxLoader/AArch64/LinuxStarterHelper.S b/ArmPkg/Application/LinuxLoader/AArch64/LinuxStarterHelper.S
new file mode 100644
index 0000000000..525c1287ef
--- /dev/null
+++ b/ArmPkg/Application/LinuxLoader/AArch64/LinuxStarterHelper.S
@@ -0,0 +1,58 @@
+//
+// 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:
diff --git a/ArmPkg/Application/LinuxLoader/Arm/LinuxAtag.c b/ArmPkg/Application/LinuxLoader/Arm/LinuxAtag.c
new file mode 100644
index 0000000000..fd7ee9c862
--- /dev/null
+++ b/ArmPkg/Application/LinuxLoader/Arm/LinuxAtag.c
@@ -0,0 +1,177 @@
+/** @file
+*
+* 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
+* 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 "LinuxAtag.h"
+#include "LinuxLoader.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 EFI_PHYSICAL_ADDRESS SystemMemoryBase,
+ 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;
+ 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);
+ if (EFI_ERROR (Status)) {
+ return 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 = (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;
+}
diff --git a/ArmPkg/Application/LinuxLoader/Arm/LinuxAtag.h b/ArmPkg/Application/LinuxLoader/Arm/LinuxAtag.h
new file mode 100644
index 0000000000..b4c7e5986e
--- /dev/null
+++ b/ArmPkg/Application/LinuxLoader/Arm/LinuxAtag.h
@@ -0,0 +1,124 @@
+/** @file
+*
+* 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
+* 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 __LINUX_ATAG_H__
+#define __LINUX_ATAG_H__
+
+//
+// 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;
+
+#endif /* __LINUX_ATAG_H__ */
diff --git a/ArmPkg/Application/LinuxLoader/Arm/LinuxStarter.c b/ArmPkg/Application/LinuxLoader/Arm/LinuxStarter.c
new file mode 100644
index 0000000000..960fdd6b3c
--- /dev/null
+++ b/ArmPkg/Application/LinuxLoader/Arm/LinuxStarter.c
@@ -0,0 +1,346 @@
+/** @file
+*
+* 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
+* 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/ArmLib.h>
+#include <Library/PcdLib.h>
+
+#include <Guid/Fdt.h>
+
+#include "LinuxLoader.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))))
+
+EFI_STATUS
+PrepareAtagList (
+ IN EFI_PHYSICAL_ADDRESS SystemMemoryBase,
+ IN CONST CHAR8* CommandLineString,
+ IN EFI_PHYSICAL_ADDRESS InitrdImage,
+ IN UINTN InitrdImageSize,
+ OUT EFI_PHYSICAL_ADDRESS *AtagBase,
+ OUT UINT32 *AtagSize
+ );
+
+STATIC
+VOID
+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 ();
+}
+
+STATIC
+EFI_STATUS
+StartLinux (
+ IN EFI_PHYSICAL_ADDRESS SystemMemoryBase,
+ 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));
+ return Status;
+ }
+
+ // 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
+ //
+ PreparePlatformHardware ();
+
+ // 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);
+ // We cannot recover the execution at this stage
+ while (1);
+}
+
+/**
+ Start a Linux kernel from a Device Path
+
+ @param SystemMemoryBase Base of the system memory
+ @param LinuxKernel Device Path to the Linux Kernel
+ @param Parameters Linux kernel arguments
+ @param Fdt Device Path to the Flat Device Tree
+ @param MachineType ARM machine type value
+
+ @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.
+ @retval RETURN_UNSUPPORTED ATAG is not support by this architecture
+
+**/
+EFI_STATUS
+BootLinuxAtag (
+ IN EFI_PHYSICAL_ADDRESS SystemMemoryBase,
+ IN EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath,
+ IN CONST CHAR8* CommandLineArguments,
+ IN UINTN MachineType
+ )
+{
+ 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 (SystemMemoryBase, 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 (SystemMemoryBase, LinuxImage, LinuxImageSize, AtagBase, AtagSize, MachineType);
+
+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
+BootLinuxFdt (
+ IN EFI_PHYSICAL_ADDRESS SystemMemoryBase,
+ IN EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL* FdtDevicePath,
+ 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;
+ }
+ }
+
+ if (FdtDevicePath == NULL) {
+ //
+ // 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);
+ } else {
+ //
+ // FDT device path explicitly defined. The FDT is relocated later to a
+ // more appropriate location for the Linux kernel.
+ //
+ FdtBlobBase = LINUX_KERNEL_MAX_OFFSET;
+ Status = BdsLoadImage (FdtDevicePath, AllocateMaxAddress, &FdtBlobBase, &FdtBlobSize);
+ if (EFI_ERROR (Status)) {
+ Print (L"ERROR: Did not find Device Tree blob (%r).\n", Status);
+ goto EXIT_FREE_INITRD;
+ }
+ }
+
+ // 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 (SystemMemoryBase, 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 (SystemMemoryBase, 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;
+}
diff --git a/ArmPkg/Application/LinuxLoader/LinuxAtagLoader.c b/ArmPkg/Application/LinuxLoader/LinuxAtagLoader.c
deleted file mode 100644
index 50a4b474cf..0000000000
--- a/ArmPkg/Application/LinuxLoader/LinuxAtagLoader.c
+++ /dev/null
@@ -1,103 +0,0 @@
-/** @file
-*
-* Copyright (c) 2011, 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 "LinuxInternal.h"
-
-#include <Library/PrintLib.h>
-#include <Library/UefiApplicationEntryPoint.h>
-
-/**
- The user Entry Point for Application. The user code starts with this function
- as the real entry point for the application.
-
- @param[in] ImageHandle The firmware allocated handle for the EFI image.
- @param[in] SystemTable A pointer to the EFI System Table.
-
- @retval EFI_SUCCESS The entry point is executed successfully.
- @retval other Some error occurs when executing this entry point.
-
-**/
-EFI_STATUS
-EFIAPI
-UefiMain (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- EFI_STATUS Status;
- EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
- LINUX_LOADER_OPTIONAL_DATA* LinuxOptionalData;
- EFI_DEVICE_PATH* DevicePathKernel;
- EFI_DEVICE_PATH* InitrdDevicePath;
- CHAR16* OptionalDataInitrd;
- CHAR8* OptionalDataArguments;
- CHAR16* Initrd;
-
- Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&LoadedImage);
- ASSERT_EFI_ERROR (Status);
-
- if (LoadedImage->LoadOptionsSize == 0) {
- Status = LinuxLoaderConfig (LoadedImage);
- } else {
- // Ensure the signature is correct
- LinuxOptionalData = (LINUX_LOADER_OPTIONAL_DATA*)LoadedImage->LoadOptions;
- if (LinuxOptionalData->Signature != LINUX_LOADER_SIGNATURE) {
- return EFI_UNSUPPORTED;
- }
-
- // Generate the File Path Node for the Linux Kernel
- DevicePathKernel = FileDevicePath (LoadedImage->DeviceHandle, LINUX_KERNEL_NAME);
-
- if (LinuxOptionalData->CmdLineLength > 0) {
- OptionalDataArguments = (CHAR8*)LinuxOptionalData + sizeof(LINUX_LOADER_OPTIONAL_DATA);
- } else {
- OptionalDataArguments = NULL;
- }
-
- if (LinuxOptionalData->InitrdPathListLength > 0) {
- if (OptionalDataArguments != NULL) {
- OptionalDataInitrd = (CHAR16*)(OptionalDataArguments + LinuxOptionalData->CmdLineLength);
- } else {
- OptionalDataInitrd = (CHAR16*)LinuxOptionalData + sizeof(LINUX_LOADER_OPTIONAL_DATA);
- }
-
- // If pointer not aligned
- if ((UINTN)OptionalDataInitrd & 0x1) {
- Initrd = (CHAR16*)AllocateCopyPool (LinuxOptionalData->InitrdPathListLength, OptionalDataInitrd);
- } else {
- Initrd = OptionalDataInitrd;
- }
-
- InitrdDevicePath = FileDevicePath (LoadedImage->DeviceHandle, Initrd);
- } else {
- OptionalDataInitrd = NULL;
- InitrdDevicePath = NULL;
- Initrd = NULL;
- }
-
- // Load and Start the Linux Kernel (we should never return)
- Status = BdsBootLinuxAtag (DevicePathKernel, InitrdDevicePath, OptionalDataArguments);
-
- if ((UINTN)OptionalDataInitrd & 0x1) {
- FreePool (Initrd);
- }
-
- FreePool (DevicePathKernel);
- if (InitrdDevicePath) {
- FreePool (InitrdDevicePath);
- }
- }
-
- return Status;
-}
diff --git a/ArmPkg/Application/LinuxLoader/LinuxAtagLoader.inf b/ArmPkg/Application/LinuxLoader/LinuxAtagLoader.inf
deleted file mode 100644
index dcc2597c24..0000000000
--- a/ArmPkg/Application/LinuxLoader/LinuxAtagLoader.inf
+++ /dev/null
@@ -1,39 +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.
-#
-#*/
-
-[Defines]
- INF_VERSION = 0x00010006
- BASE_NAME = LinuxAtagLoader
- FILE_GUID = a912f198-7f0e-4803-b908-b757b806ec83
- MODULE_TYPE = UEFI_APPLICATION
- VERSION_STRING = 0.1
- ENTRY_POINT = UefiMain
-
-[Sources]
- LinuxAtagLoader.c
- LinuxConfig.c
-
-[Packages]
- ArmPkg/ArmPkg.dec
- MdePkg/MdePkg.dec
-
-[LibraryClasses]
- BdsLib
- DxeServicesTableLib
- UefiLib
- UefiApplicationEntryPoint
-
-[Protocols]
- gEfiLoadedImageProtocolGuid
- gEfiDevicePathToTextProtocolGuid
-
diff --git a/ArmPkg/Application/LinuxLoader/LinuxConfig.c b/ArmPkg/Application/LinuxLoader/LinuxConfig.c
deleted file mode 100644
index c88dc65e93..0000000000
--- a/ArmPkg/Application/LinuxLoader/LinuxConfig.c
+++ /dev/null
@@ -1,354 +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.
-*
-**/
-
-#include "LinuxInternal.h"
-
-#define DEFAULT_BOOT_ENTRY_DESCRIPTION L"Linux"
-#define MAX_STR_INPUT 300
-#define MAX_ASCII_INPUT 300
-
-typedef enum {
- LINUX_LOADER_NEW = 1,
- LINUX_LOADER_UPDATE
-} LINUX_LOADER_ACTION;
-
-STATIC
-EFI_STATUS
-EditHIInputStr (
- IN OUT CHAR16 *CmdLine,
- IN UINTN MaxCmdLine
- )
-{
- UINTN CmdLineIndex;
- UINTN WaitIndex;
- CHAR8 Char;
- EFI_INPUT_KEY Key;
- EFI_STATUS Status;
-
- Print (CmdLine);
-
- for (CmdLineIndex = StrLen (CmdLine); CmdLineIndex < MaxCmdLine; ) {
- Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &WaitIndex);
- ASSERT_EFI_ERROR (Status);
-
- Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
- ASSERT_EFI_ERROR (Status);
-
- // Unicode character is valid when Scancode is NUll
- if (Key.ScanCode == SCAN_NULL) {
- // Scan code is NUll, hence read Unicode character
- Char = (CHAR8)Key.UnicodeChar;
- } else {
- Char = CHAR_NULL;
- }
-
- if ((Char == CHAR_LINEFEED) || (Char == CHAR_CARRIAGE_RETURN) || (Char == 0x7f)) {
- CmdLine[CmdLineIndex] = '\0';
- Print (L"\n\r");
-
- return EFI_SUCCESS;
- } else if ((Key.UnicodeChar == L'\b') || (Key.ScanCode == SCAN_LEFT) || (Key.ScanCode == SCAN_DELETE)){
- if (CmdLineIndex != 0) {
- CmdLineIndex--;
- Print (L"\b \b");
- }
- } else if ((Key.ScanCode == SCAN_ESC) || (Char == 0x1B) || (Char == 0x0)) {
- return EFI_INVALID_PARAMETER;
- } else {
- CmdLine[CmdLineIndex++] = Key.UnicodeChar;
- Print (L"%c", Key.UnicodeChar);
- }
- }
-
- return EFI_SUCCESS;
-}
-
-STATIC
-EFI_STATUS
-EditHIInputAscii (
- IN OUT CHAR8 *CmdLine,
- IN UINTN MaxCmdLine
- )
-{
- CHAR16* Str;
- EFI_STATUS Status;
-
- Str = (CHAR16*)AllocatePool (MaxCmdLine * sizeof(CHAR16));
- AsciiStrToUnicodeStr (CmdLine, Str);
-
- Status = EditHIInputStr (Str, MaxCmdLine);
-
- UnicodeStrToAsciiStr (Str, CmdLine);
- FreePool (Str);
-
- return Status;
-}
-
-STATIC
-EFI_STATUS
-GetHIInputInteger (
- OUT UINTN *Integer
- )
-{
- CHAR16 CmdLine[255];
- EFI_STATUS Status;
-
- CmdLine[0] = '\0';
- Status = EditHIInputStr (CmdLine, 255);
- if (!EFI_ERROR(Status)) {
- *Integer = StrDecimalToUintn (CmdLine);
- }
-
- return Status;
-}
-
-#if 0
-EFI_STATUS
-GenerateDeviceDescriptionName (
- IN EFI_HANDLE Handle,
- IN OUT CHAR16* Description
- )
-{
- EFI_STATUS Status;
- EFI_COMPONENT_NAME_PROTOCOL* ComponentName2Protocol;
- EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;
- EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol;
- CHAR16* DriverName;
- CHAR16* DevicePathTxt;
- EFI_DEVICE_PATH* DevicePathNode;
-
- ComponentName2Protocol = NULL;
- Status = gBS->HandleProtocol (Handle, &gEfiComponentName2ProtocolGuid, (VOID **)&ComponentName2Protocol);
- if (!EFI_ERROR(Status)) {
- //TODO: Fixme. we must find the best langague
- Status = ComponentName2Protocol->GetDriverName (ComponentName2Protocol,"en",&DriverName);
- if (!EFI_ERROR(Status)) {
- StrnCpy (Description,DriverName,BOOT_DEVICE_DESCRIPTION_MAX);
- }
- }
-
- if (EFI_ERROR(Status)) {
- // Use the lastest non null entry of the Device path as a description
- Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);
- if (EFI_ERROR(Status)) {
- return Status;
- }
-
- // Convert the last non end-type Device Path Node in text for the description
- DevicePathNode = GetLastDevicePathNode (DevicePathProtocol);
- Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);
- ASSERT_EFI_ERROR(Status);
- DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText(DevicePathNode,TRUE,TRUE);
- StrnCpy (Description, DevicePathTxt, BOOT_DEVICE_DESCRIPTION_MAX);
- FreePool (DevicePathTxt);
- }
-
- return EFI_SUCCESS;
-}
-#endif
-
-EFI_STATUS
-LinuxLoaderConfig (
- IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage
- )
-{
- EFI_STATUS Status;
- LINUX_LOADER_ACTION Choice;
- UINTN BootOrderSize;
- UINT16* BootOrder;
- UINTN BootOrderCount;
- UINTN Index;
- CHAR16 Description[MAX_ASCII_INPUT];
- CHAR8 CmdLine[MAX_ASCII_INPUT];
- CHAR16 Initrd[MAX_STR_INPUT];
- UINT16 InitrdPathListLength;
- UINT16 CmdLineLength;
- BDS_LOAD_OPTION* BdsLoadOption;
- BDS_LOAD_OPTION** SupportedBdsLoadOptions;
- UINTN SupportedBdsLoadOptionCount;
- LINUX_LOADER_OPTIONAL_DATA* LinuxOptionalData;
- EFI_DEVICE_PATH* DevicePathRoot;
-
- Choice = (LINUX_LOADER_ACTION)0;
- SupportedBdsLoadOptions = NULL;
- SupportedBdsLoadOptionCount = 0;
-
- do {
- Print (L"[%d] Create new Linux Boot Entry\n",LINUX_LOADER_NEW);
- Print (L"[%d] Update Linux Boot Entry\n",LINUX_LOADER_UPDATE);
-
- Print (L"Option: ");
- Status = GetHIInputInteger ((UINTN*)&Choice);
- if (Status == EFI_INVALID_PARAMETER) {
- Print (L"\n");
- return Status;
- } else if ((Choice != LINUX_LOADER_NEW) && (Choice != LINUX_LOADER_UPDATE)) {
- Print (L"Error: the option should be either '%d' or '%d'\n",LINUX_LOADER_NEW,LINUX_LOADER_UPDATE);
- Status = EFI_INVALID_PARAMETER;
- }
- } while (EFI_ERROR(Status));
-
- if (Choice == LINUX_LOADER_UPDATE) {
- // If no compatible entry then we just create a new entry
- Choice = LINUX_LOADER_NEW;
-
- // Scan the OptionalData of every entry for the correct signature
- Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
- if (!EFI_ERROR(Status)) {
- BootOrderCount = BootOrderSize / sizeof(UINT16);
-
- // Allocate an array to handle maximum number of supported Boot Entry
- SupportedBdsLoadOptions = (BDS_LOAD_OPTION**)AllocatePool(sizeof(BDS_LOAD_OPTION*) * BootOrderCount);
-
- SupportedBdsLoadOptionCount = 0;
-
- // Check if the signature is present in the list of the current Boot entries
- for (Index = 0; Index < BootOrderCount; Index++) {
- Status = BootOptionFromLoadOptionIndex (BootOrder[Index], &BdsLoadOption);
- if (!EFI_ERROR(Status)) {
- if ((BdsLoadOption->OptionalDataSize >= sizeof(UINT32)) &&
- (*(UINT32*)BdsLoadOption->OptionalData == LINUX_LOADER_SIGNATURE)) {
- SupportedBdsLoadOptions[SupportedBdsLoadOptionCount++] = BdsLoadOption;
- Choice = LINUX_LOADER_UPDATE;
- }
- }
- }
- }
- FreePool (BootOrder);
- }
-
- if (Choice == LINUX_LOADER_NEW) {
- Description[0] = '\0';
- CmdLine[0] = '\0';
- Initrd[0] = '\0';
-
- BdsLoadOption = (BDS_LOAD_OPTION*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION));
-
- DEBUG_CODE_BEGIN();
- CHAR16* DevicePathTxt;
- EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;
-
- Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);
- ASSERT_EFI_ERROR(Status);
- DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (LoadedImage->FilePath, TRUE, TRUE);
-
- Print(L"EFI OS Loader: %s\n",DevicePathTxt);
-
- FreePool(DevicePathTxt);
- DEBUG_CODE_END();
-
- //
- // Fill the known fields of BdsLoadOption
- //
-
- BdsLoadOption->Attributes = LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_BOOT;
-
- // Get the full Device Path for this file
- Status = gBS->HandleProtocol (LoadedImage->DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathRoot);
- ASSERT_EFI_ERROR(Status);
-
- BdsLoadOption->FilePathList = AppendDevicePath (DevicePathRoot, LoadedImage->FilePath);
- BdsLoadOption->FilePathListLength = GetDevicePathSize (BdsLoadOption->FilePathList);
- } else {
- if (SupportedBdsLoadOptionCount > 1) {
- for (Index = 0; Index < SupportedBdsLoadOptionCount; Index++) {
- Print (L"[%d] %s\n",Index + 1,SupportedBdsLoadOptions[Index]->Description);
- }
-
- do {
- Print (L"Update Boot Entry: ");
- Status = GetHIInputInteger ((UINTN*)&Choice);
- if (Status == EFI_INVALID_PARAMETER) {
- Print (L"\n");
- return Status;
- } else if ((Choice < 1) && (Choice > SupportedBdsLoadOptionCount)) {
- Print (L"Choose entry from 1 to %d\n",SupportedBdsLoadOptionCount);
- Status = EFI_INVALID_PARAMETER;
- }
- } while (EFI_ERROR(Status));
- BdsLoadOption = SupportedBdsLoadOptions[Choice-1];
- }
- StrnCpy (Description, BdsLoadOption->Description, MAX_STR_INPUT);
-
- LinuxOptionalData = (LINUX_LOADER_OPTIONAL_DATA*)BdsLoadOption->OptionalData;
- if (LinuxOptionalData->CmdLineLength > 0) {
- CopyMem (CmdLine, (CHAR8*)LinuxOptionalData + sizeof(LINUX_LOADER_OPTIONAL_DATA), LinuxOptionalData->CmdLineLength);
- } else {
- CmdLine[0] = '\0';
- }
-
- if (LinuxOptionalData->InitrdPathListLength > 0) {
- CopyMem (Initrd, (CHAR8*)LinuxOptionalData + sizeof(LINUX_LOADER_OPTIONAL_DATA) + LinuxOptionalData->CmdLineLength, LinuxOptionalData->InitrdPathListLength);
- } else {
- Initrd[0] = L'\0';
- }
- DEBUG((EFI_D_ERROR,"L\n"));
- }
-
- // Description
- Print (L"Description: ");
- Status = EditHIInputStr (Description, MAX_STR_INPUT);
- if (EFI_ERROR(Status)) {
- return Status;
- }
- if (StrLen (Description) == 0) {
- StrnCpy (Description, DEFAULT_BOOT_ENTRY_DESCRIPTION, MAX_STR_INPUT);
- }
- BdsLoadOption->Description = Description;
-
- // CmdLine
- Print (L"Command Line: ");
- Status = EditHIInputAscii (CmdLine, MAX_ASCII_INPUT);
- if (EFI_ERROR(Status)) {
- return Status;
- }
-
- // Initrd
- Print (L"Initrd name: ");
- Status = EditHIInputStr (Initrd, MAX_STR_INPUT);
- if (EFI_ERROR(Status)) {
- return Status;
- }
-
- CmdLineLength = AsciiStrLen (CmdLine);
- if (CmdLineLength > 0) {
- CmdLineLength += sizeof(CHAR8);
- }
-
- InitrdPathListLength = StrLen (Initrd) * sizeof(CHAR16);
- if (InitrdPathListLength > 0) {
- InitrdPathListLength += sizeof(CHAR16);
- }
-
- BdsLoadOption->OptionalDataSize = sizeof(LINUX_LOADER_OPTIONAL_DATA) + CmdLineLength + InitrdPathListLength;
-
- LinuxOptionalData = (LINUX_LOADER_OPTIONAL_DATA*)AllocatePool (BdsLoadOption->OptionalDataSize);
- BdsLoadOption->OptionalData = LinuxOptionalData;
-
- LinuxOptionalData->Signature = LINUX_LOADER_SIGNATURE;
- LinuxOptionalData->CmdLineLength = CmdLineLength;
- LinuxOptionalData->InitrdPathListLength = InitrdPathListLength;
-
- if (CmdLineLength > 0) {
- CopyMem (LinuxOptionalData + 1, CmdLine, CmdLineLength);
- }
- if (InitrdPathListLength > 0) {
- CopyMem ((UINT8*)(LinuxOptionalData + 1) + CmdLineLength, Initrd, InitrdPathListLength);
- }
-
- // Create or Update the boot entry
- Status = BootOptionToLoadOptionVariable (BdsLoadOption);
-
- return Status;
-}
diff --git a/ArmPkg/Application/LinuxLoader/LinuxFdtLoader.c b/ArmPkg/Application/LinuxLoader/LinuxFdtLoader.c
deleted file mode 100644
index 8e5d1c6aa0..0000000000
--- a/ArmPkg/Application/LinuxLoader/LinuxFdtLoader.c
+++ /dev/null
@@ -1,103 +0,0 @@
-/** @file
-*
-* Copyright (c) 2011, 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 "LinuxInternal.h"
-
-#include <Library/PrintLib.h>
-#include <Library/UefiApplicationEntryPoint.h>
-
-/**
- The user Entry Point for Application. The user code starts with this function
- as the real entry point for the application.
-
- @param[in] ImageHandle The firmware allocated handle for the EFI image.
- @param[in] SystemTable A pointer to the EFI System Table.
-
- @retval EFI_SUCCESS The entry point is executed successfully.
- @retval other Some error occurs when executing this entry point.
-
-**/
-EFI_STATUS
-EFIAPI
-UefiMain (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- EFI_STATUS Status;
- EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
- LINUX_LOADER_OPTIONAL_DATA* LinuxOptionalData;
- EFI_DEVICE_PATH* DevicePathKernel;
- EFI_DEVICE_PATH* InitrdDevicePath;
- CHAR16* OptionalDataInitrd;
- CHAR8* OptionalDataArguments;
- CHAR16* Initrd;
-
- Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&LoadedImage);
- ASSERT_EFI_ERROR (Status);
-
- if (LoadedImage->LoadOptionsSize == 0) {
- Status = LinuxLoaderConfig (LoadedImage);
- } else {
- // Ensure the signature is correct
- LinuxOptionalData = (LINUX_LOADER_OPTIONAL_DATA*)LoadedImage->LoadOptions;
- if (LinuxOptionalData->Signature != LINUX_LOADER_SIGNATURE) {
- return EFI_UNSUPPORTED;
- }
-
- // Generate the File Path Node for the Linux Kernel
- DevicePathKernel = FileDevicePath (LoadedImage->DeviceHandle, LINUX_KERNEL_NAME);
-
- if (LinuxOptionalData->CmdLineLength > 0) {
- OptionalDataArguments = (CHAR8*)LinuxOptionalData + sizeof(LINUX_LOADER_OPTIONAL_DATA);
- } else {
- OptionalDataArguments = NULL;
- }
-
- if (LinuxOptionalData->InitrdPathListLength > 0) {
- if (OptionalDataArguments != NULL) {
- OptionalDataInitrd = (CHAR16*)(OptionalDataArguments + LinuxOptionalData->CmdLineLength);
- } else {
- OptionalDataInitrd = (CHAR16*)LinuxOptionalData + sizeof(LINUX_LOADER_OPTIONAL_DATA);
- }
-
- // If pointer not aligned
- if ((UINTN)OptionalDataInitrd & 0x1) {
- Initrd = (CHAR16*)AllocateCopyPool (LinuxOptionalData->InitrdPathListLength, OptionalDataInitrd);
- } else {
- Initrd = OptionalDataInitrd;
- }
-
- InitrdDevicePath = FileDevicePath (LoadedImage->DeviceHandle, Initrd);
- } else {
- OptionalDataInitrd = NULL;
- InitrdDevicePath = NULL;
- Initrd = NULL;
- }
-
- // Load and Start the Linux Kernel (we should never return)
- Status = BdsBootLinuxFdt (DevicePathKernel, InitrdDevicePath, OptionalDataArguments);
-
- if ((UINTN)OptionalDataInitrd & 0x1) {
- FreePool (Initrd);
- }
-
- FreePool (DevicePathKernel);
- if (InitrdDevicePath) {
- FreePool (InitrdDevicePath);
- }
- }
-
- return Status;
-}
diff --git a/ArmPkg/Application/LinuxLoader/LinuxFdtLoader.inf b/ArmPkg/Application/LinuxLoader/LinuxFdtLoader.inf
deleted file mode 100644
index 55a6969bb8..0000000000
--- a/ArmPkg/Application/LinuxLoader/LinuxFdtLoader.inf
+++ /dev/null
@@ -1,39 +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.
-#
-#*/
-
-[Defines]
- INF_VERSION = 0x00010006
- BASE_NAME = LinuxFdtLoader
- FILE_GUID = f536d559-459f-48fa-8bbc-43b554ecae8d
- MODULE_TYPE = UEFI_APPLICATION
- VERSION_STRING = 0.1
- ENTRY_POINT = UefiMain
-
-[Sources]
- LinuxFdtLoader.c
- LinuxConfig.c
-
-[Packages]
- ArmPkg/ArmPkg.dec
- MdePkg/MdePkg.dec
-
-[LibraryClasses]
- BdsLib
- DxeServicesTableLib
- UefiLib
- UefiApplicationEntryPoint
-
-[Protocols]
- gEfiLoadedImageProtocolGuid
- gEfiDevicePathToTextProtocolGuid
-
diff --git a/ArmPkg/Application/LinuxLoader/LinuxInternal.h b/ArmPkg/Application/LinuxLoader/LinuxInternal.h
deleted file mode 100644
index 88d786f693..0000000000
--- a/ArmPkg/Application/LinuxLoader/LinuxInternal.h
+++ /dev/null
@@ -1,50 +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 __LOADER_INTERNAL_H
-#define __LOADER_INTERNAL_H
-
-#include <Uefi.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/BdsLib.h>
-#include <Library/DebugLib.h>
-#include <Library/DevicePathLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/UefiBootServicesTableLib.h>
-#include <Library/UefiLib.h>
-
-#include <Protocol/LoadedImage.h>
-#include <Protocol/DevicePathToText.h>
-
-#define LINUX_KERNEL_NAME L"zImage"
-#define FDT_NAME L"platform.dtb"
-
-#define LINUX_LOADER_SIGNATURE SIGNATURE_32('l', 'i', 'l', 'o')
-
-typedef struct {
- UINT32 Signature;
- UINT16 CmdLineLength;
- UINT16 InitrdPathListLength;
-
- // These following fields have variable length:
- //CHAR8* CmdLine;
- //CHAR16* Initrd;
-} LINUX_LOADER_OPTIONAL_DATA;
-
-EFI_STATUS
-LinuxLoaderConfig (
- IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage
- );
-
-#endif
diff --git a/ArmPkg/Application/LinuxLoader/LinuxLoader.c b/ArmPkg/Application/LinuxLoader/LinuxLoader.c
new file mode 100644
index 0000000000..70b960b66f
--- /dev/null
+++ b/ArmPkg/Application/LinuxLoader/LinuxLoader.c
@@ -0,0 +1,246 @@
+/** @file
+*
+* 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
+* 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/UefiApplicationEntryPoint.h>
+#include <Library/BaseMemoryLib.h>
+
+#include <Protocol/DevicePathFromText.h>
+
+#include "LinuxLoader.h"
+
+/**
+ The user Entry Point for Application. The user code starts with this function
+ as the real entry point for the application.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point was executed successfully.
+ @retval EFI_NOT_FOUND Protocol not found.
+ @retval EFI_NOT_FOUND Path to the Linux kernel not found.
+ @retval EFI_ABORTED The initialisation of the Shell Library failed.
+ @retval EFI_INVALID_PARAMETER At least one parameter is not valid or there is a
+ conflict between two parameters.
+ @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
+
+**/
+EFI_STATUS
+EFIAPI
+LinuxLoaderEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol;
+ EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters;
+ CHAR16 *KernelPath;
+ CHAR16 *FdtPath;
+ CHAR16 *InitrdPath;
+ CHAR16 *KernelTextDevicePath;
+ CHAR16 *FdtTextDevicePath;
+ CHAR16 *InitrdTextDevicePath;
+ CHAR16 *LinuxCommandLine;
+ UINTN AtagMachineType;
+ EFI_DEVICE_PATH *KernelDevicePath;
+ EFI_DEVICE_PATH *FdtDevicePath;
+ EFI_DEVICE_PATH *InitrdDevicePath;
+ CHAR8 *AsciiLinuxCommandLine;
+ LIST_ENTRY ResourceList;
+ LIST_ENTRY *ResourceLink;
+ SYSTEM_MEMORY_RESOURCE *Resource;
+ EFI_PHYSICAL_ADDRESS SystemMemoryBase;
+
+ Status = gBS->LocateProtocol (
+ &gEfiDevicePathFromTextProtocolGuid,
+ NULL,
+ (VOID **)&EfiDevicePathFromTextProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Register the strings for the user interface in the HII Database.
+ // This shows the way to the multi-language support, even if
+ // only the English language is actually supported. The strings to register
+ // are stored in the "LinuxLoaderStrings[]" array. This array is
+ // built by the building process from the "*.uni" file associated to
+ // the present application (cf. LinuxLoader.inf). Examine the Build
+ // folder of the application and you will find the array defined in the
+ // LinuxLoaderStrDefs.h file.
+ //
+ mLinuxLoaderHiiHandle = HiiAddPackages (
+ &mLinuxLoaderHiiGuid,
+ ImageHandle,
+ LinuxLoaderStrings,
+ NULL
+ );
+ if (mLinuxLoaderHiiHandle == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ Status = gBS->HandleProtocol (
+ ImageHandle,
+ &gEfiShellParametersProtocolGuid,
+ (VOID**)&ShellParameters
+ );
+
+ KernelDevicePath = NULL;
+ FdtDevicePath = NULL;
+ InitrdDevicePath = NULL;
+ AsciiLinuxCommandLine = NULL;
+
+ //
+ // Call the proper function to handle the command line
+ // depending on whether the application has been called
+ // from the Shell or not.
+ //
+
+ if (!EFI_ERROR (Status)) {
+ KernelTextDevicePath = NULL;
+ FdtTextDevicePath = NULL;
+ InitrdTextDevicePath = NULL;
+
+ Status = ProcessShellParameters (
+ &KernelPath, &FdtPath, &InitrdPath, &LinuxCommandLine, &AtagMachineType
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ KernelDevicePath = gEfiShellProtocol->GetDevicePathFromFilePath (KernelPath);
+ if (KernelDevicePath != NULL) {
+ FreePool (KernelPath);
+ } else {
+ KernelTextDevicePath = KernelPath;
+ }
+
+ if (FdtPath != NULL) {
+ FdtDevicePath = gEfiShellProtocol->GetDevicePathFromFilePath (FdtPath);
+ if (FdtDevicePath != NULL) {
+ FreePool (FdtPath);
+ } else {
+ FdtTextDevicePath = FdtPath;
+ }
+ }
+
+ if (InitrdPath != NULL) {
+ InitrdDevicePath = gEfiShellProtocol->GetDevicePathFromFilePath (InitrdPath);
+ if (InitrdDevicePath != NULL) {
+ FreePool (InitrdPath);
+ } else {
+ InitrdTextDevicePath = InitrdPath;
+ }
+ }
+
+ } else {
+ Status = ProcessAppCommandLine (
+ &KernelTextDevicePath, &FdtTextDevicePath,
+ &InitrdTextDevicePath, &LinuxCommandLine, &AtagMachineType
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ }
+
+ Status = EFI_INVALID_PARAMETER;
+ if (KernelTextDevicePath != NULL) {
+ KernelDevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (
+ KernelTextDevicePath
+ );
+ if (KernelDevicePath == NULL) {
+ goto Error;
+ }
+ }
+ if (FdtTextDevicePath != NULL) {
+ FdtDevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (
+ FdtTextDevicePath
+ );
+ if (FdtDevicePath == NULL) {
+ goto Error;
+ }
+ }
+ if (InitrdTextDevicePath != NULL) {
+ InitrdDevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (
+ InitrdTextDevicePath
+ );
+ if (InitrdDevicePath == NULL) {
+ goto Error;
+ }
+ }
+
+ if (LinuxCommandLine != NULL) {
+ AsciiLinuxCommandLine = AllocatePool ((StrLen (LinuxCommandLine) + 1) * sizeof (CHAR8));
+ if (AsciiLinuxCommandLine == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+ UnicodeStrToAsciiStr (LinuxCommandLine, AsciiLinuxCommandLine);
+ }
+
+ //
+ // Find Base of System Memory - we keep the lowest physical address
+ //
+ SystemMemoryBase = ~0;
+ GetSystemMemoryResources (&ResourceList);
+ ResourceLink = ResourceList.ForwardLink;
+ while (ResourceLink != NULL && ResourceLink != &ResourceList) {
+ Resource = (SYSTEM_MEMORY_RESOURCE*)ResourceLink;
+ if (Resource->PhysicalStart < SystemMemoryBase) {
+ SystemMemoryBase = Resource->PhysicalStart;
+ }
+ ResourceLink = ResourceLink->ForwardLink;
+ }
+
+ if (AtagMachineType != ARM_FDT_MACHINE_TYPE) {
+ Status = BootLinuxAtag (SystemMemoryBase, KernelDevicePath, InitrdDevicePath, AsciiLinuxCommandLine, AtagMachineType);
+ } else {
+ Status = BootLinuxFdt (SystemMemoryBase, KernelDevicePath, InitrdDevicePath, FdtDevicePath, AsciiLinuxCommandLine);
+ }
+
+Error:
+ if (KernelTextDevicePath != NULL) {
+ FreePool (KernelTextDevicePath);
+ }
+ if (FdtTextDevicePath != NULL) {
+ FreePool (FdtTextDevicePath);
+ }
+ if (InitrdTextDevicePath != NULL) {
+ FreePool (InitrdTextDevicePath);
+ }
+ if (LinuxCommandLine != NULL) {
+ FreePool (LinuxCommandLine);
+ }
+ if (KernelDevicePath != NULL) {
+ FreePool (KernelDevicePath);
+ }
+ if (FdtDevicePath != NULL) {
+ FreePool (FdtDevicePath);
+ }
+ if (InitrdDevicePath != NULL) {
+ FreePool (InitrdDevicePath);
+ }
+ if (AsciiLinuxCommandLine != NULL) {
+ FreePool (AsciiLinuxCommandLine);
+ }
+
+ if (EFI_ERROR (Status)) {
+ PrintHii (NULL, STRING_TOKEN (STR_ERROR), Status);
+ }
+
+ HiiRemovePackages (mLinuxLoaderHiiHandle);
+
+ return Status;
+}
diff --git a/ArmPkg/Application/LinuxLoader/LinuxLoader.h b/ArmPkg/Application/LinuxLoader/LinuxLoader.h
new file mode 100644
index 0000000000..8a23d7f14b
--- /dev/null
+++ b/ArmPkg/Application/LinuxLoader/LinuxLoader.h
@@ -0,0 +1,166 @@
+/** @file
+*
+* 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
+* 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 __LINUX_LOADER_H__
+#define __LINUX_LOADER_H__
+
+#include <Library/BdsLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HiiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PerformanceLib.h>
+#include <Library/PrintLib.h>
+#include <Library/ShellLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Protocol/EfiShellParameters.h>
+#include <Protocol/EfiShell.h>
+
+#include <libfdt.h>
+
+//
+// Definitions
+//
+
+#define MAX_MSG_LEN 80
+
+#define LINUX_UIMAGE_SIGNATURE 0x56190527
+#define LINUX_KERNEL_MAX_OFFSET (SystemMemoryBase + PcdGet32(PcdArmLinuxKernelMaxOffset))
+#define LINUX_ATAG_MAX_OFFSET (SystemMemoryBase + PcdGet32(PcdArmLinuxAtagMaxOffset))
+#define LINUX_FDT_MAX_OFFSET (SystemMemoryBase + PcdGet32(PcdArmLinuxFdtMaxOffset))
+
+#define ARM_FDT_MACHINE_TYPE 0xFFFFFFFF
+
+// 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
+
+//
+// Global variables
+//
+extern CONST EFI_GUID mLinuxLoaderHiiGuid;
+extern EFI_HANDLE mLinuxLoaderHiiHandle;
+
+//
+// Local Types
+//
+typedef struct _SYSTEM_MEMORY_RESOURCE {
+ LIST_ENTRY Link; // This attribute must be the first entry of this structure (to avoid pointer computation)
+ EFI_PHYSICAL_ADDRESS PhysicalStart;
+ UINT64 ResourceLength;
+} SYSTEM_MEMORY_RESOURCE;
+
+typedef VOID (*LINUX_KERNEL)(UINT32 Zero, UINT32 Arch, UINTN ParametersBase);
+
+//
+// Functions
+//
+EFI_STATUS
+PrintHii (
+ IN CONST CHAR8 *Language OPTIONAL,
+ IN CONST EFI_STRING_ID HiiFormatStringId,
+ ...
+ );
+
+VOID
+PrintHelp (
+ IN CONST CHAR8 *Language OPTIONAL
+ );
+
+EFI_STATUS
+ProcessShellParameters (
+ OUT CHAR16 **KernelPath,
+ OUT CHAR16 **FdtPath,
+ OUT CHAR16 **InitrdPath,
+ OUT CHAR16 **LinuxCommandLine,
+ OUT UINTN *AtagMachineType
+ );
+
+EFI_STATUS
+ProcessAppCommandLine (
+ OUT CHAR16 **KernelTextDevicePath,
+ OUT CHAR16 **FdtTextDevicePath,
+ OUT CHAR16 **InitrdTextDevicePath,
+ OUT CHAR16 **LinuxCommandLine,
+ OUT UINTN *AtagMachineType
+ );
+
+VOID
+PrintPerformance (
+ VOID
+ );
+
+EFI_STATUS
+GetSystemMemoryResources (
+ IN LIST_ENTRY *ResourceList
+ );
+
+EFI_STATUS
+PrepareFdt (
+ IN EFI_PHYSICAL_ADDRESS SystemMemoryBase,
+ IN CONST CHAR8* CommandLineArguments,
+ IN EFI_PHYSICAL_ADDRESS InitrdImage,
+ IN UINTN InitrdImageSize,
+ IN OUT EFI_PHYSICAL_ADDRESS *FdtBlobBase,
+ IN OUT UINTN *FdtBlobSize
+ );
+
+/**
+ Start a Linux kernel from a Device Path
+
+ @param SystemMemoryBase Base of the system memory
+ @param LinuxKernel Device Path to the Linux Kernel
+ @param Parameters Linux kernel arguments
+ @param Fdt Device Path to the Flat Device Tree
+ @param MachineType ARM machine type value
+
+ @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.
+ @retval RETURN_UNSUPPORTED ATAG is not support by this architecture
+
+**/
+EFI_STATUS
+BootLinuxAtag (
+ IN EFI_PHYSICAL_ADDRESS SystemMemoryBase,
+ IN EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath,
+ IN CONST CHAR8* CommandLineArguments,
+ IN UINTN MachineType
+ );
+
+/**
+ 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
+BootLinuxFdt (
+ IN EFI_PHYSICAL_ADDRESS SystemMemoryBase,
+ IN EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL* FdtDevicePath,
+ IN CONST CHAR8* Arguments
+ );
+
+#endif /* __LINUX_LOADER_H__ */
diff --git a/ArmPkg/Application/LinuxLoader/LinuxLoader.inf b/ArmPkg/Application/LinuxLoader/LinuxLoader.inf
new file mode 100644
index 0000000000..59ab99c968
--- /dev/null
+++ b/ArmPkg/Application/LinuxLoader/LinuxLoader.inf
@@ -0,0 +1,91 @@
+#/* @file
+# Copyright (c) 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
+# 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.
+#
+#*/
+
+[Defines]
+ INF_VERSION = 0x00010006
+ BASE_NAME = LinuxLoader
+ MODULE_UNI_FILE = LinuxLoader.uni
+ FILE_GUID = 701f54f2-0d70-4b89-bc0a-d9ca25379059
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 0.1
+ ENTRY_POINT = LinuxLoaderEntryPoint
+
+[Sources]
+ LinuxLoader.c
+ LinuxLoader.h
+ LinuxLoader.uni
+ LinuxLoaderFdt.c
+ LinuxLoaderHelper.c
+ LinuxLoaderEfiApp.c
+ LinuxLoaderShellApp.c
+
+[Sources.AARCH64]
+ AArch64/LinuxStarter.c
+ AArch64/LinuxStarterHelper.S
+
+[Sources.ARM]
+ Arm/LinuxAtag.h
+ Arm/LinuxAtag.c
+ Arm/LinuxStarter.c
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ ShellPkg/ShellPkg.dec
+
+[Guids]
+ gFdtTableGuid
+
+[Guids]
+ gArmMpCoreInfoGuid
+
+[LibraryClasses]
+ ArmLib
+ BdsLib
+ DebugLib
+ DxeServicesTableLib
+ FdtLib
+ HiiLib
+ HobLib
+ PerformanceLib
+ ShellLib
+ SerialPortLib
+ TimerLib
+ UefiApplicationEntryPoint
+ UefiLib
+
+[LibraryClasses.AARCH64]
+ ArmGicLib
+ PcdLib
+
+[Protocols]
+ gEfiLoadedImageProtocolGuid
+ gEfiDevicePathToTextProtocolGuid
+ gEfiShellParametersProtocolGuid
+
+[FeaturePcd]
+ gArmTokenSpaceGuid.PcdArmLinuxSpinTable
+
+[FixedPcd]
+ gArmTokenSpaceGuid.PcdArmLinuxFdtMaxOffset
+ gArmTokenSpaceGuid.PcdArmLinuxFdtAlignment
+ gArmTokenSpaceGuid.PcdArmLinuxKernelMaxOffset
+
+[FixedPcd.ARM]
+ gArmTokenSpaceGuid.PcdArmLinuxAtagMaxOffset
+
+[Pcd.AARCH64]
+ gArmTokenSpaceGuid.PcdGicDistributorBase
+ gArmTokenSpaceGuid.PcdGicSgiIntId
diff --git a/ArmPkg/Application/LinuxLoader/LinuxLoader.uni b/ArmPkg/Application/LinuxLoader/LinuxLoader.uni
new file mode 100644
index 0000000000..861c2b4a99
--- /dev/null
+++ b/ArmPkg/Application/LinuxLoader/LinuxLoader.uni
Binary files differ
diff --git a/ArmPkg/Application/LinuxLoader/LinuxLoaderEfiApp.c b/ArmPkg/Application/LinuxLoader/LinuxLoaderEfiApp.c
new file mode 100644
index 0000000000..57a9cd38cf
--- /dev/null
+++ b/ArmPkg/Application/LinuxLoader/LinuxLoaderEfiApp.c
@@ -0,0 +1,303 @@
+/** @file
+*
+* 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
+* 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 "LinuxLoader.h"
+
+/**
+ Extract the next item from the command line.
+
+ The items are separated by spaces. Quotation marks (") are used for argument
+ grouping and the escaping character is "^" as for the EFI Shell command lines.
+
+ @param[in out] CommandLine Command line pointer.
+ @param[out] Item Pointer to the allocated buffer where the
+ item is stored.
+
+ @retval EFI_SUCCESS The token was found and extracted.
+ @retval EFI_NOT_FOUND No item found.
+ @retval EFI_OUT_OF_RESOURCES The memory allocation failed.
+
+**/
+STATIC
+EFI_STATUS
+ExtractNextItem (
+ IN OUT CONST CHAR16 **CommandLine,
+ OUT CHAR16 **Item
+ )
+{
+ CONST CHAR16 *Walker;
+ VOID *Buffer;
+ CHAR16 *WritePtr;
+ BOOLEAN InQuotedString;
+ BOOLEAN Interpret;
+
+ for (Walker = *CommandLine; *Walker == L' '; Walker++) {
+ ;
+ }
+
+ Buffer = AllocatePool (StrSize (Walker));
+ if (Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ for (WritePtr = Buffer, Interpret = TRUE, InQuotedString = FALSE;
+ ((*Walker != L' ') || InQuotedString) && (*Walker != L'\0');
+ Walker++
+ ) {
+ if (Interpret) {
+ if (*Walker == L'^') {
+ Interpret = FALSE;
+ continue;
+ }
+ if (*Walker == L'"') {
+ InQuotedString = !InQuotedString;
+ continue;
+ }
+ } else {
+ Interpret = TRUE;
+ }
+ *(WritePtr++) = *Walker;
+ }
+
+ if (WritePtr == Buffer) {
+ FreePool (Buffer);
+ return EFI_NOT_FOUND;
+ }
+
+ *WritePtr = L'\0';
+ *CommandLine = Walker;
+ *Item = Buffer;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if an item of the command line is a flag or not.
+
+ @param[in] Item Command line item.
+
+ @retval TRUE The item is a flag.
+ @retval FALSE The item is not a flag.
+
+**/
+STATIC
+BOOLEAN
+IsFlag (
+ IN CONST CHAR16 *Item
+ )
+{
+ return ((Item[0] == L'-') && (Item[2] == L'\0'));
+}
+
+/**
+ Process the application command line.
+
+ @param[out] KernelTextDevicePath A pointer to the buffer where the device
+ path to the Linux kernel is stored. The
+ address of the buffer is NULL in case of
+ an error. Otherwise, the returned address
+ is the address of a buffer allocated with
+ a call to AllocatePool() that has to be
+ freed by the caller.
+ @param[out] FdtTextDevicePath A pointer to the buffer where the device
+ path to the FDT is stored. The address of
+ the buffer is NULL in case of an error or
+ if the device path to the FDT is not
+ defined. Otherwise, the returned address
+ is the address of a buffer allocated with
+ a call to AllocatePool() that has to be
+ freed by the caller.
+ @param[out] InitrdTextDevicePath A pointer to the buffer where the device
+ path to the RAM root file system is stored.
+ The address of the buffer is NULL in case
+ of an error or if the device path to the
+ RAM root file system is not defined.
+ Otherwise, the returned address is the
+ address of a buffer allocated with a call
+ to AllocatePool() that has to be freed by
+ the caller.
+ @param[out] LinuxCommandLine A pointer to the buffer where the Linux
+ kernel command line is stored. The address
+ of the buffer is NULL in case of an error
+ or if the Linux command line is not
+ defined. Otherwise, the returned address
+ is the address of a buffer allocated with
+ a call to AllocatePool() that has to be
+ freed by the caller.
+
+ @param[out] AtagMachineType Value of the ARM Machine Type
+
+ @retval EFI_SUCCESS The processing was successfull.
+ @retval EFI_NOT_FOUND EFI_LOADED_IMAGE_PROTOCOL not found.
+ @retval EFI_NOT_FOUND Path to the Linux kernel not found.
+ @retval EFI_INVALID_PARAMETER At least one parameter is not valid or there is a
+ conflict between two parameters.
+ @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
+
+**/
+EFI_STATUS
+ProcessAppCommandLine (
+ OUT CHAR16 **KernelTextDevicePath,
+ OUT CHAR16 **FdtTextDevicePath,
+ OUT CHAR16 **InitrdTextDevicePath,
+ OUT CHAR16 **LinuxCommandLine,
+ OUT UINTN *AtagMachineType
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS Status2;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ CONST CHAR16 *Walker;
+ CHAR16 *Item;
+ CHAR16 Flag;
+ BOOLEAN HasAtagSupport;
+ BOOLEAN HasFdtSupport;
+
+ *KernelTextDevicePath = NULL;
+ *FdtTextDevicePath = NULL;
+ *InitrdTextDevicePath = NULL;
+ *LinuxCommandLine = NULL;
+ *AtagMachineType = ARM_FDT_MACHINE_TYPE;
+
+ HasAtagSupport = FALSE;
+ HasFdtSupport = FALSE;
+
+ Status = gBS->HandleProtocol (
+ gImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID**)&LoadedImage
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ Walker = (CHAR16*)LoadedImage->LoadOptions;
+ if (Walker == NULL) {
+ PrintHelp (NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get the device path to the Linux kernel.
+ //
+
+ Status = ExtractNextItem (&Walker, &Item);
+ if (!EFI_ERROR (Status)) {
+ if (!IsFlag (Item)) {
+ *KernelTextDevicePath = Item;
+ } else {
+ PrintHii (NULL, STRING_TOKEN (STR_MISSING_KERNEL_PATH));
+ FreePool (Item);
+ return EFI_NOT_FOUND;
+ }
+ } else {
+ if (Status != EFI_NOT_FOUND) {
+ return Status;
+ }
+ PrintHelp (NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_INVALID_PARAMETER;
+ while (*Walker != L'\0') {
+ Status2 = ExtractNextItem (&Walker, &Item);
+ if (Status2 == EFI_NOT_FOUND) {
+ break;
+ }
+ if (EFI_ERROR (Status2)) {
+ Status = Status2;
+ goto Error;
+ }
+
+ if (!IsFlag (Item)) {
+ PrintHii (NULL, STRING_TOKEN (STR_INVALID_FLAG), Item[0], Item[1]);
+ FreePool (Item);
+ goto Error;
+ }
+ Flag = Item[1];
+ FreePool (Item);
+
+ Status2 = ExtractNextItem (&Walker, &Item);
+ if (Status2 == EFI_NOT_FOUND) {
+ PrintHii (NULL, STRING_TOKEN (STR_MISSING_VALUE), Flag);
+ goto Error;
+ }
+ if (EFI_ERROR (Status2)) {
+ Status = Status2;
+ goto Error;
+ }
+ if (IsFlag (Item)) {
+ PrintHii (NULL, STRING_TOKEN (STR_MISSING_VALUE), Flag);
+ FreePool (Item);
+ goto Error;
+ }
+
+ switch (Flag) {
+ case L'a':
+ if (HasFdtSupport) {
+ PrintHii (NULL, STRING_TOKEN (STR_ATAG_FDT_CONFLICT));
+ goto Error;
+ }
+ *AtagMachineType = StrDecimalToUintn (Item);
+ HasAtagSupport = TRUE;
+ break;
+ case L'd':
+ *FdtTextDevicePath = Item;
+ if (HasAtagSupport) {
+ PrintHii (NULL, STRING_TOKEN (STR_ATAG_FDT_CONFLICT));
+ goto Error;
+ }
+ HasFdtSupport = TRUE;
+ break;
+
+ case L'c':
+ *LinuxCommandLine = Item;
+ break;
+
+ case L'f':
+ *InitrdTextDevicePath = Item;
+ break;
+
+ default:
+ PrintHii (NULL, STRING_TOKEN (STR_INVALID_FLAG), L'-', Flag);
+ FreePool (Item);
+ goto Error;
+ }
+ }
+
+ Status = EFI_SUCCESS;
+
+Error:
+ if (EFI_ERROR (Status)) {
+ if (*KernelTextDevicePath != NULL) {
+ FreePool (*KernelTextDevicePath);
+ *KernelTextDevicePath = NULL;
+ }
+ if (*FdtTextDevicePath != NULL) {
+ FreePool (*FdtTextDevicePath);
+ *FdtTextDevicePath = NULL;
+ }
+ if (*InitrdTextDevicePath != NULL) {
+ FreePool (*InitrdTextDevicePath);
+ *InitrdTextDevicePath = NULL;
+ }
+ if (*LinuxCommandLine != NULL) {
+ FreePool (*LinuxCommandLine);
+ *LinuxCommandLine = NULL;
+ }
+ }
+
+ return Status;
+}
diff --git a/ArmPkg/Application/LinuxLoader/LinuxLoaderFdt.c b/ArmPkg/Application/LinuxLoader/LinuxLoaderFdt.c
new file mode 100644
index 0000000000..0f5378403f
--- /dev/null
+++ b/ArmPkg/Application/LinuxLoader/LinuxLoaderFdt.c
@@ -0,0 +1,411 @@
+/** @file
+*
+* 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
+* 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 <PiDxe.h>
+#include <Library/ArmLib.h>
+#include <Library/HobLib.h>
+
+#include <Guid/ArmMpCoreInfo.h>
+
+#include "LinuxLoader.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;
+} FDT_REGION;
+
+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 SystemMemoryBase,
+ 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;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+PrepareFdt (
+ IN EFI_PHYSICAL_ADDRESS SystemMemoryBase,
+ 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;
+ FDT_REGION Region;
+ UINTN Index;
+ CHAR8 Name[10];
+ LIST_ENTRY ResourceList;
+ 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 (SystemMemoryBase, *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 = (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;
+ }
+ }
+
+ // 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;
+}
diff --git a/ArmPkg/Application/LinuxLoader/LinuxLoaderHelper.c b/ArmPkg/Application/LinuxLoader/LinuxLoaderHelper.c
new file mode 100644
index 0000000000..4d7a844584
--- /dev/null
+++ b/ArmPkg/Application/LinuxLoader/LinuxLoaderHelper.c
@@ -0,0 +1,192 @@
+/** @file
+*
+* 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
+* 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 <PiDxe.h>
+#include <Library/HobLib.h>
+#include <Library/TimerLib.h>
+#include <Library/SerialPortLib.h>
+
+#include "LinuxLoader.h"
+
+STATIC CONST CHAR8 *mTokenList[] = {
+ /*"SEC",*/
+ "PEI",
+ "DXE",
+ "BDS",
+ NULL
+};
+
+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);
+}
+
+STATIC
+EFI_STATUS
+InsertSystemMemoryResources (
+ LIST_ENTRY *ResourceList,
+ EFI_HOB_RESOURCE_DESCRIPTOR *ResHob
+ )
+{
+ SYSTEM_MEMORY_RESOURCE *NewResource;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NextLink;
+ LIST_ENTRY AttachedResources;
+ SYSTEM_MEMORY_RESOURCE *Resource;
+ EFI_PHYSICAL_ADDRESS NewResourceEnd;
+
+ if (IsListEmpty (ResourceList)) {
+ NewResource = AllocateZeroPool (sizeof (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 = (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 = (SYSTEM_MEMORY_RESOURCE*)GetFirstNode (&AttachedResources);
+ Link = RemoveEntryList (&NewResource->Link);
+ while (!IsListEmpty (&AttachedResources)) {
+ // Merge resources
+ Resource = (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 (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;
+}
diff --git a/ArmPkg/Application/LinuxLoader/LinuxLoaderShellApp.c b/ArmPkg/Application/LinuxLoader/LinuxLoaderShellApp.c
new file mode 100644
index 0000000000..2245185394
--- /dev/null
+++ b/ArmPkg/Application/LinuxLoader/LinuxLoaderShellApp.c
@@ -0,0 +1,298 @@
+/** @file
+*
+* 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
+* 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 "LinuxLoader.h"
+
+//
+// Internal variables
+//
+
+CONST EFI_GUID mLinuxLoaderHiiGuid = {
+ 0xd5d16edc, 0x35c5, 0x4866,
+ {0xbd, 0xe5, 0x2b, 0x64, 0xa2, 0x26, 0x55, 0x6e}
+ };
+EFI_HANDLE mLinuxLoaderHiiHandle;
+
+STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
+ {L"-f", TypeValue},
+ {L"-d", TypeValue},
+ {L"-c", TypeValue},
+ {L"-a", TypeValue},
+ {NULL , TypeMax }
+ };
+
+/**
+ Print a string given the "HII Id" of the format string and a list of
+ arguments.
+
+ @param[in] Language The language of the string to retrieve. If
+ this parameter is NULL, then the current
+ platform language is used.
+ @param[in] HiiFormatStringId The format string Id for getting from Hii.
+ @param[in] ... The variable argument list.
+
+ @retval EFI_SUCCESS The printing was successful.
+ @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
+
+**/
+EFI_STATUS
+PrintHii (
+ IN CONST CHAR8 *Language OPTIONAL,
+ IN CONST EFI_STRING_ID HiiFormatStringId,
+ ...
+ )
+{
+ VA_LIST Marker;
+ CHAR16 *HiiFormatString;
+ CHAR16 Buffer[MAX_MSG_LEN];
+
+ VA_START (Marker, HiiFormatStringId);
+
+ HiiFormatString = HiiGetString (mLinuxLoaderHiiHandle, HiiFormatStringId, Language);
+ if (HiiFormatString != NULL) {
+ UnicodeVSPrint (Buffer, sizeof (Buffer), HiiFormatString, Marker);
+ Print (L"%s", Buffer);
+ FreePool (HiiFormatString);
+ } else {
+ ASSERT (FALSE);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ VA_END (Marker);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Print the help.
+
+ @param[in] Language The language of the string to retrieve. If this
+ parameter is NULL, then the current platform
+ language is used.
+**/
+VOID
+PrintHelp (
+ IN CONST CHAR8 *Language OPTIONAL
+ )
+{
+ CHAR16 *Help;
+ CHAR16 *Walker;
+ CHAR16 *LineEnd;
+
+ //
+ // Print the help line by line as it is too big to be printed at once.
+ //
+
+ Help = HiiGetString (mLinuxLoaderHiiHandle, STRING_TOKEN (STR_HELP), Language);
+ if (Help != NULL) {
+ Walker = Help;
+ while (*Walker != L'\0') {
+ LineEnd = StrStr (Walker, L"\r\n");
+ if (LineEnd != NULL) {
+ *LineEnd = L'\0';
+ }
+ Print (L"%s\r\n", Walker);
+ if (LineEnd == NULL) {
+ break;
+ }
+ Walker = LineEnd + 2;
+ }
+ FreePool (Help);
+ }
+
+}
+
+/**
+ Process the Shell parameters in the case the application has been called
+ from the EFI Shell.
+
+ @param[out] KernelPath A pointer to the buffer where the path
+ to the Linux kernel (EFI Shell file path
+ or device path is stored. The address of
+ the buffer is NULL in case of an error.
+ Otherwise, the returned address is the
+ address of a buffer allocated with
+ a call to AllocatePool() that has to be
+ freed by the caller.
+ @param[out] FdtPath A pointer to the buffer where the path
+ to the FDT (EFI Shell file path or
+ device path) is stored. The address of
+ the buffer is NULL in case of an error or
+ if the path to the FDT is not defined.
+ Otherwise, the returned address is the
+ address of a buffer allocated with a call
+ to AllocatePool() that has to be freed by
+ the caller.
+ @param[out] InitrdPath A pointer to the buffer where the path
+ (EFI Shell file path or device path)
+ to the RAM root file system is stored.
+ The address of the buffer is NULL in case
+ of an error or if the path to the RAM root
+ file system is not defined. Otherwise, the
+ returned address is the address of a
+ buffer allocated with a call to
+ AllocatePool() that has to be freed by
+ the caller.
+ @param[out] LinuxCommandLine A pointer to the buffer where the Linux
+ kernel command line is stored. The address
+ of the buffer is NULL in case of an error
+ or if the Linux command line is not
+ defined. Otherwise, the returned address
+ is the address of a buffer allocated with
+ a call to AllocatePool() that has to be
+ freed by the caller.
+ @param[out] AtagMachineType Value of the ARM Machine Type
+
+ @retval EFI_SUCCESS The processing was successfull.
+ @retval EFI_ABORTED The initialisation of the Shell Library failed.
+ @retval EFI_NOT_FOUND Path to the Linux kernel not found.
+ @retval EFI_INVALID_PARAMETER At least one parameter is not valid or there is a
+ conflict between two parameters.
+ @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
+
+**/
+EFI_STATUS
+ProcessShellParameters (
+ OUT CHAR16 **KernelPath,
+ OUT CHAR16 **FdtPath,
+ OUT CHAR16 **InitrdPath,
+ OUT CHAR16 **LinuxCommandLine,
+ OUT UINTN *AtagMachineType
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *CheckPackage;
+ CHAR16 *ProblemParam;
+ CONST CHAR16 *FlagValue;
+ CONST CHAR16 *ParameterValue;
+ UINTN LinuxCommandLineLen;
+
+
+ *KernelPath = NULL;
+ *FdtPath = NULL;
+ *InitrdPath = NULL;
+ *LinuxCommandLine = NULL;
+ *AtagMachineType = ARM_FDT_MACHINE_TYPE;
+
+ //
+ // Initialise the Shell Library as we are going to use it.
+ // Assert that the return code is EFI_SUCCESS as it should.
+ // To anticipate any change is the codes returned by
+ // ShellInitialize(), leave in case of error.
+ //
+ Status = ShellInitialize ();
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return EFI_ABORTED;
+ }
+
+ Status = ShellCommandLineParse (ParamList, &CheckPackage, &ProblemParam, TRUE);
+ if (EFI_ERROR (Status)) {
+ if ((Status == EFI_VOLUME_CORRUPTED) &&
+ (ProblemParam != NULL) ) {
+ PrintHii (
+ NULL, STRING_TOKEN (STR_SHELL_INVALID_PARAMETER), ProblemParam
+ );
+ FreePool (ProblemParam);
+ } else {
+ ASSERT (FALSE);
+ }
+ goto Error;
+ }
+
+ Status = EFI_INVALID_PARAMETER;
+ if (ShellCommandLineGetCount (CheckPackage) != 2) {
+ PrintHelp (NULL);
+ goto Error;
+ }
+
+ Status = EFI_OUT_OF_RESOURCES;
+
+ FlagValue = ShellCommandLineGetValue (CheckPackage, L"-a");
+ if (FlagValue != NULL) {
+ if (ShellCommandLineGetFlag (CheckPackage, L"-d")) {
+ PrintHii (NULL, STRING_TOKEN (STR_ATAG_FDT_CONFLICT));
+ goto Error;
+ }
+ *AtagMachineType = StrDecimalToUintn (FlagValue);
+ }
+
+ ParameterValue = ShellCommandLineGetRawValue (CheckPackage, 1);
+ *KernelPath = AllocateCopyPool (StrSize (ParameterValue), ParameterValue);
+ if (*KernelPath == NULL) {
+ goto Error;
+ }
+
+ FlagValue = ShellCommandLineGetValue (CheckPackage, L"-d");
+ if (FlagValue != NULL) {
+ *FdtPath = AllocateCopyPool (StrSize (FlagValue), FlagValue);
+ if (*FdtPath == NULL) {
+ goto Error;
+ }
+ }
+
+ FlagValue = ShellCommandLineGetValue (CheckPackage, L"-f");
+ if (FlagValue != NULL) {
+ *InitrdPath = AllocateCopyPool (StrSize (FlagValue), FlagValue);
+ if (*InitrdPath == NULL) {
+ goto Error;
+ }
+ }
+
+ FlagValue = ShellCommandLineGetValue (CheckPackage, L"-c");
+ if (FlagValue != NULL) {
+ LinuxCommandLineLen = StrLen (FlagValue);
+ if ((LinuxCommandLineLen != 0) &&
+ (FlagValue[0] == L'"' ) &&
+ (FlagValue[LinuxCommandLineLen - 1] == L'"')) {
+ FlagValue++;
+ LinuxCommandLineLen -= 2;
+ }
+
+ *LinuxCommandLine = AllocateCopyPool (
+ (LinuxCommandLineLen + 1) * sizeof (CHAR16),
+ FlagValue
+ );
+ if (*LinuxCommandLine == NULL) {
+ goto Error;
+ }
+ (*LinuxCommandLine)[LinuxCommandLineLen] = L'\0';
+ }
+
+ Status = EFI_SUCCESS;
+
+Error:
+ ShellCommandLineFreeVarList (CheckPackage);
+
+ if (EFI_ERROR (Status)) {
+ if (*KernelPath != NULL) {
+ FreePool (*KernelPath);
+ *KernelPath = NULL;
+ }
+ if (*FdtPath != NULL) {
+ FreePool (*FdtPath);
+ *FdtPath = NULL;
+ }
+ if (*InitrdPath != NULL) {
+ FreePool (*InitrdPath);
+ *InitrdPath = NULL;
+ }
+ if (*LinuxCommandLine != NULL) {
+ FreePool (*LinuxCommandLine);
+ *LinuxCommandLine = NULL;
+ }
+ }
+
+ return Status;
+}
diff --git a/ArmPkg/ArmPkg.dsc b/ArmPkg/ArmPkg.dsc
index 6959fde22c..1f69799dc2 100644
--- a/ArmPkg/ArmPkg.dsc
+++ b/ArmPkg/ArmPkg.dsc
@@ -78,6 +78,10 @@
BdsLib|ArmPkg/Library/BdsLib/BdsLib.inf
FdtLib|EmbeddedPkg/Library/FdtLib/FdtLib.inf
+ ShellLib|ShellPkg/Library/UefiShellLib/UefiShellLib.inf
+ FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf
+ SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf
+
IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
[LibraryClasses.ARM]
@@ -138,7 +142,7 @@
ArmPkg/Filesystem/SemihostFs/SemihostFs.inf
- ArmPkg/Application/LinuxLoader/LinuxFdtLoader.inf
+ ArmPkg/Application/LinuxLoader/LinuxLoader.inf
[Components.ARM]
ArmPkg/Library/BaseMemoryLibVstm/BaseMemoryLibVstm.inf
@@ -154,8 +158,6 @@
ArmPkg/Library/ArmLib/ArmV7/ArmV7LibSec.inf
ArmPkg/Library/ArmLib/ArmV7/ArmV7LibPrePi.inf
- ArmPkg/Application/LinuxLoader/LinuxAtagLoader.inf
-
[Components.AARCH64]
ArmPkg/Drivers/ArmCpuLib/ArmCortexAEMv8Lib/ArmCortexAEMv8Lib.inf
ArmPkg/Drivers/ArmCpuLib/ArmCortexA5xLib/ArmCortexA5xLib.inf