]> git.proxmox.com Git - mirror_edk2.git/commitdiff
ArmPkg/Application: Add new EFI application to boot Linux
authorRonald Cron <Ronald.Cron@arm.com>
Mon, 6 Jul 2015 16:49:40 +0000 (16:49 +0000)
committeroliviermartin <oliviermartin@Edk2>
Mon, 6 Jul 2015 16:49:40 +0000 (16:49 +0000)
This new application support ATAG and FDT Linux kernel.
It uses the Device Tree from the EFI Configuration Table
to boot FDT aware Linux kernel.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ronald Cron <Ronald.Cron@arm.com>
Reviewed-by: Olivier Martin <Olivier.Martin@arm.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17828 6f19259b-4bc3-4df7-8a09-765794883524

20 files changed:
ArmPkg/Application/LinuxLoader/AArch64/LinuxStarter.c [new file with mode: 0644]
ArmPkg/Application/LinuxLoader/AArch64/LinuxStarterHelper.S [new file with mode: 0644]
ArmPkg/Application/LinuxLoader/Arm/LinuxAtag.c [new file with mode: 0644]
ArmPkg/Application/LinuxLoader/Arm/LinuxAtag.h [new file with mode: 0644]
ArmPkg/Application/LinuxLoader/Arm/LinuxStarter.c [new file with mode: 0644]
ArmPkg/Application/LinuxLoader/LinuxAtagLoader.c [deleted file]
ArmPkg/Application/LinuxLoader/LinuxAtagLoader.inf [deleted file]
ArmPkg/Application/LinuxLoader/LinuxConfig.c [deleted file]
ArmPkg/Application/LinuxLoader/LinuxFdtLoader.c [deleted file]
ArmPkg/Application/LinuxLoader/LinuxFdtLoader.inf [deleted file]
ArmPkg/Application/LinuxLoader/LinuxInternal.h [deleted file]
ArmPkg/Application/LinuxLoader/LinuxLoader.c [new file with mode: 0644]
ArmPkg/Application/LinuxLoader/LinuxLoader.h [new file with mode: 0644]
ArmPkg/Application/LinuxLoader/LinuxLoader.inf [new file with mode: 0644]
ArmPkg/Application/LinuxLoader/LinuxLoader.uni [new file with mode: 0644]
ArmPkg/Application/LinuxLoader/LinuxLoaderEfiApp.c [new file with mode: 0644]
ArmPkg/Application/LinuxLoader/LinuxLoaderFdt.c [new file with mode: 0644]
ArmPkg/Application/LinuxLoader/LinuxLoaderHelper.c [new file with mode: 0644]
ArmPkg/Application/LinuxLoader/LinuxLoaderShellApp.c [new file with mode: 0644]
ArmPkg/ArmPkg.dsc

diff --git a/ArmPkg/Application/LinuxLoader/AArch64/LinuxStarter.c b/ArmPkg/Application/LinuxLoader/AArch64/LinuxStarter.c
new file mode 100644 (file)
index 0000000..0d540c9
--- /dev/null
@@ -0,0 +1,370 @@
+/** @file\r
+*\r
+*  Copyright (c) 2011-2015, ARM Limited. All rights reserved.\r
+*\r
+*  This program and the accompanying materials\r
+*  are licensed and made available under the terms and conditions of the BSD License\r
+*  which accompanies this distribution.  The full text of the license may be found at\r
+*  http://opensource.org/licenses/bsd-license.php\r
+*\r
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+*\r
+**/\r
+\r
+#include <Library/ArmLib.h>\r
+#include <Library/ArmGicLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/PcdLib.h>\r
+\r
+#include <Ppi/ArmMpCoreInfo.h>\r
+\r
+#include <Guid/Fdt.h>\r
+\r
+#include "LinuxLoader.h"\r
+\r
+/*\r
+  Linux kernel booting: Look at the doc in the Kernel source :\r
+    Documentation/arm64/booting.txt\r
+  The kernel image must be placed at the start of the memory to be used by the\r
+  kernel (2MB aligned) + 0x80000.\r
+\r
+  The Device tree blob is expected to be under 2MB and be within the first 512MB\r
+  of kernel memory and be 2MB aligned.\r
+\r
+  A Flattened Device Tree (FDT) used to boot linux needs to be updated before\r
+  the kernel is started. It needs to indicate how secondary cores are brought up\r
+  and where they are waiting before loading Linux. The FDT also needs to hold\r
+  the correct kernel command line and filesystem RAM-disk information.\r
+  At the moment we do not fully support generating this FDT information at\r
+  runtime. A prepared FDT should be provided at boot. FDT is the only supported\r
+  method for booting the AArch64 Linux kernel.\r
+\r
+  Linux does not use any runtime services at this time, so we can let it\r
+  overwrite UEFI.\r
+*/\r
+\r
+\r
+#define LINUX_ALIGN_VAL       (0x080000) // 2MB + 0x80000 mask\r
+#define LINUX_ALIGN_MASK      (0x1FFFFF) // Bottom 21bits\r
+#define ALIGN_2MB(addr)       ALIGN_POINTER(addr , (2*1024*1024))\r
+\r
+/* ARM32 and AArch64 kernel handover differ.\r
+ * x0 is set to FDT base.\r
+ * x1-x3 are reserved for future use and should be set to zero.\r
+ */\r
+typedef VOID (*LINUX_KERNEL64)(UINTN ParametersBase, UINTN Reserved0,\r
+                               UINTN Reserved1, UINTN Reserved2);\r
+\r
+/* These externs are used to relocate some ASM code into Linux memory. */\r
+extern VOID  *SecondariesPenStart;\r
+extern VOID  *SecondariesPenEnd;\r
+extern UINTN *AsmMailboxbase;\r
+\r
+\r
+STATIC\r
+VOID\r
+PreparePlatformHardware (\r
+  VOID\r
+  )\r
+{\r
+  //Note: Interrupts will be disabled by the GIC driver when ExitBootServices() will be called.\r
+\r
+  // Clean before Disable else the Stack gets corrupted with old data.\r
+  ArmCleanDataCache ();\r
+  ArmDisableDataCache ();\r
+  // Invalidate all the entries that might have snuck in.\r
+  ArmInvalidateDataCache ();\r
+\r
+  // Disable and invalidate the instruction cache\r
+  ArmDisableInstructionCache ();\r
+  ArmInvalidateInstructionCache ();\r
+\r
+  // Turn off MMU\r
+  ArmDisableMmu ();\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+StartLinux (\r
+  IN  EFI_PHYSICAL_ADDRESS  LinuxImage,\r
+  IN  UINTN                 LinuxImageSize,\r
+  IN  EFI_PHYSICAL_ADDRESS  FdtBlobBase,\r
+  IN  UINTN                 FdtBlobSize\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  LINUX_KERNEL64        LinuxKernel = (LINUX_KERNEL64)LinuxImage;\r
+\r
+  // Send msg to secondary cores to go to the kernel pen.\r
+  ArmGicSendSgiTo (PcdGet32 (PcdGicDistributorBase), ARM_GIC_ICDSGIR_FILTER_EVERYONEELSE, 0x0E, PcdGet32 (PcdGicSgiIntId));\r
+\r
+  // Shut down UEFI boot services. ExitBootServices() will notify every driver that created an event on\r
+  // ExitBootServices event. Example the Interrupt DXE driver will disable the interrupts on this event.\r
+  Status = ShutdownUefiBootServices ();\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "ERROR: Can not shutdown UEFI boot services. Status=0x%X\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  // Check if the Linux Image is a uImage\r
+  if (*(UINTN*)LinuxKernel == LINUX_UIMAGE_SIGNATURE) {\r
+    // Assume the Image Entry Point is just after the uImage header (64-byte size)\r
+    LinuxKernel = (LINUX_KERNEL64)((UINTN)LinuxKernel + 64);\r
+    LinuxImageSize -= 64;\r
+  }\r
+\r
+  //\r
+  // Switch off interrupts, caches, mmu, etc\r
+  //\r
+  PreparePlatformHardware ();\r
+\r
+  // Register and print out performance information\r
+  PERF_END (NULL, "BDS", NULL, 0);\r
+  if (PerformanceMeasurementEnabled ()) {\r
+    PrintPerformance ();\r
+  }\r
+\r
+  //\r
+  // Start the Linux Kernel\r
+  //\r
+\r
+  // x1-x3 are reserved (set to zero) for future use.\r
+  LinuxKernel ((UINTN)FdtBlobBase, 0, 0, 0);\r
+\r
+  // Kernel should never exit\r
+  // After Life services are not provided\r
+  ASSERT (FALSE);\r
+\r
+  // We cannot recover the execution at this stage\r
+  while (1);\r
+}\r
+\r
+/**\r
+  Start a Linux kernel from a Device Path\r
+\r
+  @param  SystemMemoryBase      Base of the system memory\r
+  @param  LinuxKernel           Device Path to the Linux Kernel\r
+  @param  Parameters            Linux kernel arguments\r
+  @param  Fdt                   Device Path to the Flat Device Tree\r
+  @param  MachineType           ARM machine type value\r
+\r
+  @retval EFI_SUCCESS           All drivers have been connected\r
+  @retval EFI_NOT_FOUND         The Linux kernel Device Path has not been found\r
+  @retval EFI_OUT_OF_RESOURCES  There is not enough resource memory to store the matching results.\r
+  @retval RETURN_UNSUPPORTED    ATAG is not support by this architecture\r
+\r
+**/\r
+EFI_STATUS\r
+BootLinuxAtag (\r
+  IN  EFI_PHYSICAL_ADDRESS      SystemMemoryBase,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath,\r
+  IN  CONST CHAR8*              CommandLineArguments,\r
+  IN  UINTN                     MachineType\r
+  )\r
+{\r
+  // NOTE : AArch64 Linux kernel does not support ATAG, FDT only.\r
+  ASSERT (0);\r
+\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+  Start a Linux kernel from a Device Path\r
+\r
+  @param[in]  LinuxKernelDevicePath  Device Path to the Linux Kernel\r
+  @param[in]  InitrdDevicePath       Device Path to the Initrd\r
+  @param[in]  Arguments              Linux kernel arguments\r
+\r
+  @retval EFI_SUCCESS           All drivers have been connected\r
+  @retval EFI_NOT_FOUND         The Linux kernel Device Path has not been found\r
+  @retval EFI_OUT_OF_RESOURCES  There is not enough resource memory to store the matching results.\r
+\r
+**/\r
+EFI_STATUS\r
+BootLinuxFdt (\r
+  IN  EFI_PHYSICAL_ADDRESS      SystemMemoryBase,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL* FdtDevicePath,\r
+  IN  CONST CHAR8*              Arguments\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  EFI_STATUS               PenBaseStatus;\r
+  UINTN                    LinuxImageSize;\r
+  UINTN                    InitrdImageSize;\r
+  UINTN                    InitrdImageBaseSize;\r
+  VOID                     *InstalledFdtBase;\r
+  UINTN                    FdtBlobSize;\r
+  EFI_PHYSICAL_ADDRESS     FdtBlobBase;\r
+  EFI_PHYSICAL_ADDRESS     LinuxImage;\r
+  EFI_PHYSICAL_ADDRESS     InitrdImage;\r
+  EFI_PHYSICAL_ADDRESS     InitrdImageBase;\r
+  ARM_PROCESSOR_TABLE      *ArmProcessorTable;\r
+  ARM_CORE_INFO            *ArmCoreInfoTable;\r
+  UINTN                    Index;\r
+  EFI_PHYSICAL_ADDRESS     PenBase;\r
+  UINTN                    PenSize;\r
+  UINTN                    MailBoxBase;\r
+\r
+  PenBaseStatus = EFI_UNSUPPORTED;\r
+  PenSize = 0;\r
+  InitrdImage = 0;\r
+  InitrdImageSize = 0;\r
+  InitrdImageBase = 0;\r
+  InitrdImageBaseSize = 0;\r
+\r
+  PERF_START (NULL, "BDS", NULL, 0);\r
+\r
+  //\r
+  // Load the Linux kernel from a device path\r
+  //\r
+\r
+  // Try to put the kernel at the start of RAM so as to give it access to all memory.\r
+  // If that fails fall back to try loading it within LINUX_KERNEL_MAX_OFFSET of memory start.\r
+  LinuxImage = SystemMemoryBase + 0x80000;\r
+  Status = BdsLoadImage (LinuxKernelDevicePath, AllocateAddress, &LinuxImage, &LinuxImageSize);\r
+  if (EFI_ERROR (Status)) {\r
+    // Try again but give the loader more freedom of where to put the image.\r
+    LinuxImage = LINUX_KERNEL_MAX_OFFSET;\r
+    Status = BdsLoadImage (LinuxKernelDevicePath, AllocateMaxAddress, &LinuxImage, &LinuxImageSize);\r
+    if (EFI_ERROR (Status)) {\r
+      Print (L"ERROR: Did not find Linux kernel (%r).\n", Status);\r
+      return Status;\r
+    }\r
+  }\r
+  // Adjust the kernel location slightly if required. The kernel needs to be placed at start\r
+  //  of memory (2MB aligned) + 0x80000.\r
+  if ((LinuxImage & LINUX_ALIGN_MASK) != LINUX_ALIGN_VAL) {\r
+    LinuxImage = (EFI_PHYSICAL_ADDRESS)CopyMem (ALIGN_2MB (LinuxImage) + 0x80000, (VOID*)(UINTN)LinuxImage, LinuxImageSize);\r
+  }\r
+\r
+  if (InitrdDevicePath) {\r
+    InitrdImageBase = LINUX_KERNEL_MAX_OFFSET;\r
+    Status = BdsLoadImage (InitrdDevicePath, AllocateMaxAddress, &InitrdImageBase, &InitrdImageBaseSize);\r
+    if (Status == EFI_OUT_OF_RESOURCES) {\r
+      Status = BdsLoadImage (InitrdDevicePath, AllocateAnyPages, &InitrdImageBase, &InitrdImageBaseSize);\r
+    }\r
+    if (EFI_ERROR (Status)) {\r
+      Print (L"ERROR: Did not find initrd image (%r).\n", Status);\r
+      goto EXIT_FREE_LINUX;\r
+    }\r
+\r
+    // Check if the initrd is a uInitrd\r
+    if (*(UINTN*)((UINTN)InitrdImageBase) == LINUX_UIMAGE_SIGNATURE) {\r
+      // Skip the 64-byte image header\r
+      InitrdImage = (EFI_PHYSICAL_ADDRESS)((UINTN)InitrdImageBase + 64);\r
+      InitrdImageSize = InitrdImageBaseSize - 64;\r
+    } else {\r
+      InitrdImage = InitrdImageBase;\r
+      InitrdImageSize = InitrdImageBaseSize;\r
+    }\r
+  }\r
+\r
+  if (FdtDevicePath == NULL) {\r
+    //\r
+    // Get the FDT from the Configuration Table.\r
+    // The FDT will be reloaded in PrepareFdt() to a more appropriate\r
+    // location for the Linux Kernel.\r
+    //\r
+    Status = EfiGetSystemConfigurationTable (&gFdtTableGuid, &InstalledFdtBase);\r
+    if (EFI_ERROR (Status)) {\r
+      Print (L"ERROR: Did not get the Device Tree blob (%r).\n", Status);\r
+      goto EXIT_FREE_INITRD;\r
+    }\r
+    FdtBlobBase = (EFI_PHYSICAL_ADDRESS)InstalledFdtBase;\r
+    FdtBlobSize = fdt_totalsize (InstalledFdtBase);\r
+  } else {\r
+    //\r
+    // FDT device path explicitly defined. The FDT is relocated later to a\r
+    // more appropriate location for the Linux kernel.\r
+    //\r
+    FdtBlobBase = LINUX_KERNEL_MAX_OFFSET;\r
+    Status = BdsLoadImage (FdtDevicePath, AllocateMaxAddress, &FdtBlobBase, &FdtBlobSize);\r
+    if (EFI_ERROR (Status)) {\r
+      Print (L"ERROR: Did not find Device Tree blob (%r).\n", Status);\r
+      goto EXIT_FREE_INITRD;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Install secondary core pens if the Power State Coordination Interface is not supported\r
+  //\r
+  if (FeaturePcdGet (PcdArmLinuxSpinTable)) {\r
+    // Place Pen at the start of Linux memory. We can then tell Linux to not use this bit of memory\r
+    PenBase  = LinuxImage - 0x80000;\r
+    PenSize  = (UINTN)&SecondariesPenEnd - (UINTN)&SecondariesPenStart;\r
+\r
+    // Reserve the memory as RuntimeServices\r
+    PenBaseStatus = gBS->AllocatePages (AllocateAddress, EfiRuntimeServicesCode, EFI_SIZE_TO_PAGES (PenSize), &PenBase);\r
+    if (EFI_ERROR (PenBaseStatus)) {\r
+      Print (L"Warning: Failed to reserve the memory required for the secondary cores at 0x%lX, Status = %r\n", PenBase, PenBaseStatus);\r
+      // Even if there is a risk of memory corruption we carry on\r
+    }\r
+\r
+    // Put mailboxes below the pen code so we know where they are relative to code.\r
+    MailBoxBase = (UINTN)PenBase + ((UINTN)&SecondariesPenEnd - (UINTN)&SecondariesPenStart);\r
+    // Make sure this is 8 byte aligned.\r
+    if (MailBoxBase % sizeof (MailBoxBase) != 0) {\r
+      MailBoxBase += sizeof (MailBoxBase) - MailBoxBase % sizeof (MailBoxBase);\r
+    }\r
+\r
+    CopyMem ( (VOID*)(PenBase), (VOID*)&SecondariesPenStart, PenSize);\r
+\r
+    // Update the MailboxBase variable used in the pen code\r
+    *(UINTN*)(PenBase + ((UINTN)&AsmMailboxbase - (UINTN)&SecondariesPenStart)) = MailBoxBase;\r
+\r
+    for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {\r
+      // Check for correct GUID type\r
+      if (CompareGuid (&gArmMpCoreInfoGuid, &(gST->ConfigurationTable[Index].VendorGuid))) {\r
+        UINTN i;\r
+\r
+        // Get them under our control. Move from depending on 32bit reg(sys_flags) and SWI\r
+        // to 64 bit addr and WFE\r
+        ArmProcessorTable = (ARM_PROCESSOR_TABLE *)gST->ConfigurationTable[Index].VendorTable;\r
+        ArmCoreInfoTable = ArmProcessorTable->ArmCpus;\r
+\r
+        for (i = 0; i < ArmProcessorTable->NumberOfEntries; i++ ) {\r
+          // This goes into the SYSFLAGS register for the VE platform. We only have one 32bit reg to use\r
+          MmioWrite32 (ArmCoreInfoTable[i].MailboxSetAddress, (UINTN)PenBase);\r
+\r
+          // So FDT can set the mailboxes correctly with the parser. These are 64bit Memory locations.\r
+          ArmCoreInfoTable[i].MailboxSetAddress = (UINTN)MailBoxBase + i*sizeof (MailBoxBase);\r
+\r
+          // Clear the mailboxes for the respective cores\r
+          *((UINTN*)(ArmCoreInfoTable[i].MailboxSetAddress)) = 0x0;\r
+        }\r
+      }\r
+    }\r
+    // Flush caches to make sure our pen gets to mem before we free the cores.\r
+    ArmCleanDataCache ();\r
+  }\r
+\r
+  // By setting address=0 we leave the memory allocation to the function\r
+  Status = PrepareFdt (SystemMemoryBase, Arguments, InitrdImage, InitrdImageSize, &FdtBlobBase, &FdtBlobSize);\r
+  if (EFI_ERROR (Status)) {\r
+    Print (L"ERROR: Can not load Linux kernel with Device Tree. Status=0x%X\n", Status);\r
+    goto EXIT_FREE_FDT;\r
+  }\r
+\r
+  return StartLinux (LinuxImage, LinuxImageSize, FdtBlobBase, FdtBlobSize);\r
+\r
+EXIT_FREE_FDT:\r
+  if (!EFI_ERROR (PenBaseStatus)) {\r
+    gBS->FreePages (PenBase, EFI_SIZE_TO_PAGES (PenSize));\r
+  }\r
+\r
+  gBS->FreePages (FdtBlobBase, EFI_SIZE_TO_PAGES (FdtBlobSize));\r
+\r
+EXIT_FREE_INITRD:\r
+  if (InitrdDevicePath) {\r
+    gBS->FreePages (InitrdImageBase, EFI_SIZE_TO_PAGES (InitrdImageBaseSize));\r
+  }\r
+\r
+EXIT_FREE_LINUX:\r
+  gBS->FreePages (LinuxImage, EFI_SIZE_TO_PAGES (LinuxImageSize));\r
+\r
+  return Status;\r
+}\r
diff --git a/ArmPkg/Application/LinuxLoader/AArch64/LinuxStarterHelper.S b/ArmPkg/Application/LinuxLoader/AArch64/LinuxStarterHelper.S
new file mode 100644 (file)
index 0000000..525c128
--- /dev/null
@@ -0,0 +1,58 @@
+//\r
+//  Copyright (c) 2011-2013, ARM Limited. All rights reserved.\r
+//\r
+//  This program and the accompanying materials\r
+//  are licensed and made available under the terms and conditions of the BSD License\r
+//  which accompanies this distribution.  The full text of the license may be found at\r
+//  http://opensource.org/licenses/bsd-license.php\r
+//\r
+//  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+//  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+//\r
+\r
+\r
+/* Secondary core pens for AArch64 Linux booting.\r
+\r
+   This code it placed in Linux kernel memory and marked reserved. UEFI ensures\r
+   that the secondary cores get to this pen and the kernel can then start the\r
+   cores from here.\r
+   NOTE: This code must be self-contained.\r
+*/\r
+\r
+#include <Library/ArmLib.h>\r
+\r
+.text\r
+.align 3\r
+\r
+GCC_ASM_EXPORT(SecondariesPenStart)\r
+ASM_GLOBAL SecondariesPenEnd\r
+\r
+ASM_PFX(SecondariesPenStart):\r
+   // Registers x0-x3 are reserved for future use and should be set to zero.\r
+   mov x0, xzr\r
+   mov x1, xzr\r
+   mov x2, xzr\r
+   mov x3, xzr\r
+\r
+   // Get core position. Taken from ArmPlatformGetCorePosition().\r
+   // Assumes max 4 cores per cluster.\r
+   mrs x4, mpidr_el1             // Get MPCore register.\r
+   and x5, x4, #ARM_CORE_MASK    // Get core number.\r
+   and x4, x4, #ARM_CLUSTER_MASK // Get cluster number.\r
+   add x4, x5, x4, LSR #6        // Add scaled cluster number to core number.\r
+   lsl x4, x4, 3            // Get mailbox offset for this core.\r
+   ldr x5, AsmMailboxbase   // Get mailbox addr relative to pc (36 bytes ahead).\r
+   add x4, x4, x5           // Add core mailbox offset to base of mailbox.\r
+1: ldr x5, [x4]             // Load value from mailbox.\r
+   cmp xzr, x5              // Has the mailbox been set?\r
+   b.ne 2f                  // If so break out of loop.\r
+   wfe                      // If not, wait a bit.\r
+   b 1b                     // Wait over, check if mailbox set again.\r
+2: br x5                    // Jump to mailbox value.\r
+\r
+.align 3 // Make sure the variable below is 8 byte aligned.\r
+                .global     AsmMailboxbase\r
+AsmMailboxbase: .xword      0xdeaddeadbeefbeef\r
+\r
+SecondariesPenEnd:\r
diff --git a/ArmPkg/Application/LinuxLoader/Arm/LinuxAtag.c b/ArmPkg/Application/LinuxLoader/Arm/LinuxAtag.c
new file mode 100644 (file)
index 0000000..fd7ee9c
--- /dev/null
@@ -0,0 +1,177 @@
+/** @file\r
+*\r
+*  Copyright (c) 2011-2015, ARM Limited. All rights reserved.\r
+*\r
+*  This program and the accompanying materials\r
+*  are licensed and made available under the terms and conditions of the BSD License\r
+*  which accompanies this distribution.  The full text of the license may be found at\r
+*  http://opensource.org/licenses/bsd-license.php\r
+*\r
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+*\r
+**/\r
+\r
+#include "LinuxAtag.h"\r
+#include "LinuxLoader.h"\r
+\r
+// Point to the current ATAG\r
+STATIC LINUX_ATAG *mLinuxKernelCurrentAtag;\r
+\r
+STATIC\r
+VOID\r
+SetupCoreTag (\r
+  IN UINT32 PageSize\r
+  )\r
+{\r
+  mLinuxKernelCurrentAtag->header.size = tag_size (LINUX_ATAG_CORE);\r
+  mLinuxKernelCurrentAtag->header.type = ATAG_CORE;\r
+\r
+  mLinuxKernelCurrentAtag->body.core_tag.flags    = 1;            /* ensure read-only */\r
+  mLinuxKernelCurrentAtag->body.core_tag.pagesize = PageSize;     /* systems PageSize (4k) */\r
+  mLinuxKernelCurrentAtag->body.core_tag.rootdev  = 0;            /* zero root device (typically overridden from kernel command line )*/\r
+\r
+  // move pointer to next tag\r
+  mLinuxKernelCurrentAtag = next_tag_address (mLinuxKernelCurrentAtag);\r
+}\r
+\r
+STATIC\r
+VOID\r
+SetupMemTag (\r
+  IN UINTN StartAddress,\r
+  IN UINT32 Size\r
+  )\r
+{\r
+  mLinuxKernelCurrentAtag->header.size = tag_size (LINUX_ATAG_MEM);\r
+  mLinuxKernelCurrentAtag->header.type = ATAG_MEM;\r
+\r
+  mLinuxKernelCurrentAtag->body.mem_tag.start = StartAddress;    /* Start of memory chunk for AtagMem */\r
+  mLinuxKernelCurrentAtag->body.mem_tag.size  = Size;             /* Size of memory chunk for AtagMem */\r
+\r
+  // move pointer to next tag\r
+  mLinuxKernelCurrentAtag = next_tag_address (mLinuxKernelCurrentAtag);\r
+}\r
+\r
+STATIC\r
+VOID\r
+SetupCmdlineTag (\r
+  IN CONST CHAR8 *CmdLine\r
+  )\r
+{\r
+  UINT32 LineLength;\r
+\r
+  // Increment the line length by 1 to account for the null string terminator character\r
+  LineLength = AsciiStrLen (CmdLine) + 1;\r
+\r
+  /* Check for NULL strings.\r
+   * Do not insert a tag for an empty CommandLine, don't even modify the tag address pointer.\r
+   * Remember, you have at least one null string terminator character.\r
+   */\r
+  if (LineLength > 1) {\r
+    mLinuxKernelCurrentAtag->header.size = ((UINT32)sizeof (LINUX_ATAG_HEADER) + LineLength + (UINT32)3) >> 2;\r
+    mLinuxKernelCurrentAtag->header.type = ATAG_CMDLINE;\r
+\r
+    /* place CommandLine into tag */\r
+    AsciiStrCpy (mLinuxKernelCurrentAtag->body.cmdline_tag.cmdline, CmdLine);\r
+\r
+    // move pointer to next tag\r
+    mLinuxKernelCurrentAtag = next_tag_address (mLinuxKernelCurrentAtag);\r
+  }\r
+}\r
+\r
+STATIC\r
+VOID\r
+SetupInitrdTag (\r
+  IN UINT32 InitrdImage,\r
+  IN UINT32 InitrdImageSize\r
+  )\r
+{\r
+  mLinuxKernelCurrentAtag->header.size = tag_size (LINUX_ATAG_INITRD2);\r
+  mLinuxKernelCurrentAtag->header.type = ATAG_INITRD2;\r
+\r
+  mLinuxKernelCurrentAtag->body.initrd2_tag.start = InitrdImage;\r
+  mLinuxKernelCurrentAtag->body.initrd2_tag.size = InitrdImageSize;\r
+\r
+  // Move pointer to next tag\r
+  mLinuxKernelCurrentAtag = next_tag_address (mLinuxKernelCurrentAtag);\r
+}\r
+STATIC\r
+VOID\r
+SetupEndTag (\r
+  VOID\r
+  )\r
+{\r
+  // Empty tag ends list; this has zero length and no body\r
+  mLinuxKernelCurrentAtag->header.type = ATAG_NONE;\r
+  mLinuxKernelCurrentAtag->header.size = 0;\r
+\r
+  /* We can not calculate the next address by using the standard macro:\r
+   * Params = next_tag_address (Params);\r
+   * because it relies on the header.size, which here it is 0 (zero).\r
+   * The easiest way is to add the sizeof (mLinuxKernelCurrentAtag->header).\r
+   */\r
+  mLinuxKernelCurrentAtag = (LINUX_ATAG*)((UINT32)mLinuxKernelCurrentAtag + sizeof (mLinuxKernelCurrentAtag->header));\r
+}\r
+\r
+EFI_STATUS\r
+PrepareAtagList (\r
+  IN  EFI_PHYSICAL_ADDRESS  SystemMemoryBase,\r
+  IN  CONST CHAR8*          CommandLineString,\r
+  IN  EFI_PHYSICAL_ADDRESS  InitrdImage,\r
+  IN  UINTN                 InitrdImageSize,\r
+  OUT EFI_PHYSICAL_ADDRESS  *AtagBase,\r
+  OUT UINT32                *AtagSize\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  LIST_ENTRY                  *ResourceLink;\r
+  LIST_ENTRY                  ResourceList;\r
+  EFI_PHYSICAL_ADDRESS        AtagStartAddress;\r
+  SYSTEM_MEMORY_RESOURCE      *Resource;\r
+\r
+  AtagStartAddress = LINUX_ATAG_MAX_OFFSET;\r
+  Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData, EFI_SIZE_TO_PAGES (ATAG_MAX_SIZE), &AtagStartAddress);\r
+  if (EFI_ERROR (Status)) {\r
+    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));\r
+    Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, EFI_SIZE_TO_PAGES (ATAG_MAX_SIZE), &AtagStartAddress);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  // Ready to setup the atag list\r
+  mLinuxKernelCurrentAtag = (LINUX_ATAG*)(UINTN)AtagStartAddress;\r
+\r
+  // Standard core tag 4k PageSize\r
+  SetupCoreTag ( (UINT32)SIZE_4KB );\r
+\r
+  // Physical memory setup\r
+  GetSystemMemoryResources (&ResourceList);\r
+  ResourceLink = ResourceList.ForwardLink;\r
+  while (ResourceLink != NULL && ResourceLink != &ResourceList) {\r
+    Resource = (SYSTEM_MEMORY_RESOURCE*)ResourceLink;\r
+    DEBUG ((EFI_D_INFO, "- [0x%08X,0x%08X]\n",\r
+        (UINT32)Resource->PhysicalStart,\r
+        (UINT32)Resource->PhysicalStart + (UINT32)Resource->ResourceLength));\r
+    SetupMemTag ((UINT32)Resource->PhysicalStart, (UINT32)Resource->ResourceLength );\r
+    ResourceLink = ResourceLink->ForwardLink;\r
+  }\r
+\r
+  // CommandLine setting root device\r
+  if (CommandLineString) {\r
+    SetupCmdlineTag (CommandLineString);\r
+  }\r
+\r
+  if (InitrdImageSize > 0 && InitrdImage != 0) {\r
+    SetupInitrdTag ((UINT32)InitrdImage, (UINT32)InitrdImageSize);\r
+  }\r
+\r
+  // End of tags\r
+  SetupEndTag ();\r
+\r
+  // Calculate atag list size\r
+  *AtagBase = AtagStartAddress;\r
+  *AtagSize = (UINT32)mLinuxKernelCurrentAtag - (UINT32)AtagStartAddress + 1;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/ArmPkg/Application/LinuxLoader/Arm/LinuxAtag.h b/ArmPkg/Application/LinuxLoader/Arm/LinuxAtag.h
new file mode 100644 (file)
index 0000000..b4c7e59
--- /dev/null
@@ -0,0 +1,124 @@
+/** @file\r
+*\r
+*  Copyright (c) 2011-2015, ARM Limited. All rights reserved.\r
+*\r
+*  This program and the accompanying materials\r
+*  are licensed and made available under the terms and conditions of the BSD License\r
+*  which accompanies this distribution.  The full text of the license may be found at\r
+*  http://opensource.org/licenses/bsd-license.php\r
+*\r
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+*\r
+**/\r
+\r
+#ifndef __LINUX_ATAG_H__\r
+#define __LINUX_ATAG_H__\r
+\r
+//\r
+// ATAG Definitions\r
+//\r
+\r
+#define ATAG_MAX_SIZE        0x3000\r
+\r
+/* ATAG : list of possible tags */\r
+#define ATAG_NONE            0x00000000\r
+#define ATAG_CORE            0x54410001\r
+#define ATAG_MEM             0x54410002\r
+#define ATAG_VIDEOTEXT       0x54410003\r
+#define ATAG_RAMDISK         0x54410004\r
+#define ATAG_INITRD2         0x54420005\r
+#define ATAG_SERIAL          0x54410006\r
+#define ATAG_REVISION        0x54410007\r
+#define ATAG_VIDEOLFB        0x54410008\r
+#define ATAG_CMDLINE         0x54410009\r
+#define ATAG_ARM_MP_CORE     0x5441000A\r
+\r
+#define next_tag_address(t)  ((LINUX_ATAG*)((UINT32)(t) + (((t)->header.size) << 2) ))\r
+#define tag_size(type)       ((UINT32)((sizeof(LINUX_ATAG_HEADER) + sizeof(type)) >> 2))\r
+\r
+typedef struct {\r
+  UINT32  size; /* length of tag in words including this header */\r
+  UINT32  type;  /* tag type */\r
+} LINUX_ATAG_HEADER;\r
+\r
+typedef struct {\r
+  UINT32  flags;\r
+  UINT32  pagesize;\r
+  UINT32  rootdev;\r
+} LINUX_ATAG_CORE;\r
+\r
+typedef struct {\r
+  UINT32  size;\r
+  UINTN  start;\r
+} LINUX_ATAG_MEM;\r
+\r
+typedef struct {\r
+  UINT8   x;\r
+  UINT8   y;\r
+  UINT16  video_page;\r
+  UINT8   video_mode;\r
+  UINT8   video_cols;\r
+  UINT16  video_ega_bx;\r
+  UINT8   video_lines;\r
+  UINT8   video_isvga;\r
+  UINT16  video_points;\r
+} LINUX_ATAG_VIDEOTEXT;\r
+\r
+typedef struct {\r
+  UINT32  flags;\r
+  UINT32  size;\r
+  UINTN  start;\r
+} LINUX_ATAG_RAMDISK;\r
+\r
+typedef struct {\r
+  UINT32  start;\r
+  UINT32  size;\r
+} LINUX_ATAG_INITRD2;\r
+\r
+typedef struct {\r
+  UINT32  low;\r
+  UINT32  high;\r
+} LINUX_ATAG_SERIALNR;\r
+\r
+typedef struct {\r
+  UINT32  rev;\r
+} LINUX_ATAG_REVISION;\r
+\r
+typedef struct {\r
+  UINT16  lfb_width;\r
+  UINT16  lfb_height;\r
+  UINT16  lfb_depth;\r
+  UINT16  lfb_linelength;\r
+  UINT32  lfb_base;\r
+  UINT32  lfb_size;\r
+  UINT8   red_size;\r
+  UINT8   red_pos;\r
+  UINT8   green_size;\r
+  UINT8   green_pos;\r
+  UINT8   blue_size;\r
+  UINT8   blue_pos;\r
+  UINT8   rsvd_size;\r
+  UINT8   rsvd_pos;\r
+} LINUX_ATAG_VIDEOLFB;\r
+\r
+typedef struct {\r
+  CHAR8   cmdline[1];\r
+} LINUX_ATAG_CMDLINE;\r
+\r
+typedef struct {\r
+  LINUX_ATAG_HEADER header;\r
+  union {\r
+    LINUX_ATAG_CORE         core_tag;\r
+    LINUX_ATAG_MEM          mem_tag;\r
+    LINUX_ATAG_VIDEOTEXT    videotext_tag;\r
+    LINUX_ATAG_RAMDISK      ramdisk_tag;\r
+    LINUX_ATAG_INITRD2      initrd2_tag;\r
+    LINUX_ATAG_SERIALNR     serialnr_tag;\r
+    LINUX_ATAG_REVISION     revision_tag;\r
+    LINUX_ATAG_VIDEOLFB     videolfb_tag;\r
+    LINUX_ATAG_CMDLINE      cmdline_tag;\r
+  } body;\r
+} LINUX_ATAG;\r
+\r
+#endif /* __LINUX_ATAG_H__ */\r
diff --git a/ArmPkg/Application/LinuxLoader/Arm/LinuxStarter.c b/ArmPkg/Application/LinuxLoader/Arm/LinuxStarter.c
new file mode 100644 (file)
index 0000000..960fdd6
--- /dev/null
@@ -0,0 +1,346 @@
+/** @file\r
+*\r
+*  Copyright (c) 2011-2015, ARM Limited. All rights reserved.\r
+*\r
+*  This program and the accompanying materials\r
+*  are licensed and made available under the terms and conditions of the BSD License\r
+*  which accompanies this distribution.  The full text of the license may be found at\r
+*  http://opensource.org/licenses/bsd-license.php\r
+*\r
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+*\r
+**/\r
+\r
+#include <Library/ArmLib.h>\r
+#include <Library/PcdLib.h>\r
+\r
+#include <Guid/Fdt.h>\r
+\r
+#include "LinuxLoader.h"\r
+\r
+#define ALIGN32_BELOW(addr)   ALIGN_POINTER(addr - 32,32)\r
+\r
+#define IS_ADDRESS_IN_REGION(RegionStart, RegionSize, Address) \\r
+    (((UINTN)(RegionStart) <= (UINTN)(Address)) && ((UINTN)(Address) <= ((UINTN)(RegionStart) + (UINTN)(RegionSize))))\r
+\r
+EFI_STATUS\r
+PrepareAtagList (\r
+  IN  EFI_PHYSICAL_ADDRESS  SystemMemoryBase,\r
+  IN  CONST CHAR8*          CommandLineString,\r
+  IN  EFI_PHYSICAL_ADDRESS  InitrdImage,\r
+  IN  UINTN                 InitrdImageSize,\r
+  OUT EFI_PHYSICAL_ADDRESS  *AtagBase,\r
+  OUT UINT32                *AtagSize\r
+  );\r
+\r
+STATIC\r
+VOID\r
+PreparePlatformHardware (\r
+  VOID\r
+  )\r
+{\r
+  //Note: Interrupts will be disabled by the GIC driver when ExitBootServices() will be called.\r
+\r
+  // Clean before Disable else the Stack gets corrupted with old data.\r
+  ArmCleanDataCache ();\r
+  ArmDisableDataCache ();\r
+  // Invalidate all the entries that might have snuck in.\r
+  ArmInvalidateDataCache ();\r
+\r
+  // Invalidate and disable the Instruction cache\r
+  ArmDisableInstructionCache ();\r
+  ArmInvalidateInstructionCache ();\r
+\r
+  // Turn off MMU\r
+  ArmDisableMmu ();\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+StartLinux (\r
+  IN  EFI_PHYSICAL_ADDRESS  SystemMemoryBase,\r
+  IN  EFI_PHYSICAL_ADDRESS  LinuxImage,\r
+  IN  UINTN                 LinuxImageSize,\r
+  IN  EFI_PHYSICAL_ADDRESS  KernelParamsAddress,\r
+  IN  UINTN                 KernelParamsSize,\r
+  IN  UINT32                MachineType\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  LINUX_KERNEL          LinuxKernel;\r
+\r
+  // Shut down UEFI boot services. ExitBootServices() will notify every driver that created an event on\r
+  // ExitBootServices event. Example the Interrupt DXE driver will disable the interrupts on this event.\r
+  Status = ShutdownUefiBootServices ();\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "ERROR: Can not shutdown UEFI boot services. Status=0x%X\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  // Move the kernel parameters to any address inside the first 1MB.\r
+  // This is necessary because the ARM Linux kernel requires\r
+  // the FTD / ATAG List to reside entirely inside the first 1MB of\r
+  // physical memory.\r
+  //Note: There is no requirement on the alignment\r
+  if (MachineType != ARM_FDT_MACHINE_TYPE) {\r
+    if (((UINTN)KernelParamsAddress > LINUX_ATAG_MAX_OFFSET) && (KernelParamsSize < PcdGet32 (PcdArmLinuxAtagMaxOffset))) {\r
+      KernelParamsAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)CopyMem (ALIGN32_BELOW (LINUX_ATAG_MAX_OFFSET - KernelParamsSize), (VOID*)(UINTN)KernelParamsAddress, KernelParamsSize);\r
+    }\r
+  } else {\r
+    if (((UINTN)KernelParamsAddress > LINUX_FDT_MAX_OFFSET) && (KernelParamsSize < PcdGet32 (PcdArmLinuxFdtMaxOffset))) {\r
+      KernelParamsAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)CopyMem (ALIGN32_BELOW (LINUX_FDT_MAX_OFFSET - KernelParamsSize), (VOID*)(UINTN)KernelParamsAddress, KernelParamsSize);\r
+    }\r
+  }\r
+\r
+  if ((UINTN)LinuxImage > LINUX_KERNEL_MAX_OFFSET) {\r
+    //Note: There is no requirement on the alignment\r
+    LinuxKernel = (LINUX_KERNEL)CopyMem (ALIGN32_BELOW (LINUX_KERNEL_MAX_OFFSET - LinuxImageSize), (VOID*)(UINTN)LinuxImage, LinuxImageSize);\r
+  } else {\r
+    LinuxKernel = (LINUX_KERNEL)(UINTN)LinuxImage;\r
+  }\r
+\r
+  // Check if the Linux Image is a uImage\r
+  if (*(UINT32*)LinuxKernel == LINUX_UIMAGE_SIGNATURE) {\r
+    // Assume the Image Entry Point is just after the uImage header (64-byte size)\r
+    LinuxKernel = (LINUX_KERNEL)((UINTN)LinuxKernel + 64);\r
+    LinuxImageSize -= 64;\r
+  }\r
+\r
+  // Check there is no overlapping between kernel and its parameters\r
+  // We can only assert because it is too late to fallback to UEFI (ExitBootServices has been called).\r
+  ASSERT (!IS_ADDRESS_IN_REGION (LinuxKernel, LinuxImageSize, KernelParamsAddress) &&\r
+          !IS_ADDRESS_IN_REGION (LinuxKernel, LinuxImageSize, KernelParamsAddress + KernelParamsSize));\r
+\r
+  //\r
+  // Switch off interrupts, caches, mmu, etc\r
+  //\r
+  PreparePlatformHardware ();\r
+\r
+  // Register and print out performance information\r
+  PERF_END (NULL, "BDS", NULL, 0);\r
+  if (PerformanceMeasurementEnabled ()) {\r
+    PrintPerformance ();\r
+  }\r
+\r
+  //\r
+  // Start the Linux Kernel\r
+  //\r
+\r
+  // Outside BootServices, so can't use Print();\r
+  DEBUG ((EFI_D_ERROR, "\nStarting the kernel:\n\n"));\r
+\r
+  // Jump to kernel with register set\r
+  LinuxKernel ((UINTN)0, MachineType, (UINTN)KernelParamsAddress);\r
+\r
+  // Kernel should never exit\r
+  // After Life services are not provided\r
+  ASSERT (FALSE);\r
+  // We cannot recover the execution at this stage\r
+  while (1);\r
+}\r
+\r
+/**\r
+  Start a Linux kernel from a Device Path\r
+\r
+  @param  SystemMemoryBase      Base of the system memory\r
+  @param  LinuxKernel           Device Path to the Linux Kernel\r
+  @param  Parameters            Linux kernel arguments\r
+  @param  Fdt                   Device Path to the Flat Device Tree\r
+  @param  MachineType           ARM machine type value\r
+\r
+  @retval EFI_SUCCESS           All drivers have been connected\r
+  @retval EFI_NOT_FOUND         The Linux kernel Device Path has not been found\r
+  @retval EFI_OUT_OF_RESOURCES  There is not enough resource memory to store the matching results.\r
+  @retval RETURN_UNSUPPORTED    ATAG is not support by this architecture\r
+\r
+**/\r
+EFI_STATUS\r
+BootLinuxAtag (\r
+  IN  EFI_PHYSICAL_ADDRESS      SystemMemoryBase,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath,\r
+  IN  CONST CHAR8*              CommandLineArguments,\r
+  IN  UINTN                     MachineType\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  UINT32                LinuxImageSize;\r
+  UINT32                InitrdImageBaseSize = 0;\r
+  UINT32                InitrdImageSize = 0;\r
+  UINT32                AtagSize;\r
+  EFI_PHYSICAL_ADDRESS  AtagBase;\r
+  EFI_PHYSICAL_ADDRESS  LinuxImage;\r
+  EFI_PHYSICAL_ADDRESS  InitrdImageBase = 0;\r
+  EFI_PHYSICAL_ADDRESS  InitrdImage = 0;\r
+\r
+  PERF_START (NULL, "BDS", NULL, 0);\r
+\r
+  // Load the Linux kernel from a device path\r
+  LinuxImage = LINUX_KERNEL_MAX_OFFSET;\r
+  Status = BdsLoadImage (LinuxKernelDevicePath, AllocateMaxAddress, &LinuxImage, &LinuxImageSize);\r
+  if (EFI_ERROR (Status)) {\r
+    Print (L"ERROR: Did not find Linux kernel.\n");\r
+    return Status;\r
+  }\r
+\r
+  if (InitrdDevicePath) {\r
+    // Load the initrd near to the Linux kernel\r
+    InitrdImageBase = LINUX_KERNEL_MAX_OFFSET;\r
+    Status = BdsLoadImage (InitrdDevicePath, AllocateMaxAddress, &InitrdImageBase, &InitrdImageBaseSize);\r
+    if (Status == EFI_OUT_OF_RESOURCES) {\r
+      Status = BdsLoadImage (InitrdDevicePath, AllocateAnyPages, &InitrdImageBase, &InitrdImageBaseSize);\r
+    }\r
+    if (EFI_ERROR (Status)) {\r
+      Print (L"ERROR: Did not find initrd image.\n");\r
+      goto EXIT_FREE_LINUX;\r
+    }\r
+\r
+    // Check if the initrd is a uInitrd\r
+    if (*(UINT32*)((UINTN)InitrdImageBase) == LINUX_UIMAGE_SIGNATURE) {\r
+      // Skip the 64-byte image header\r
+      InitrdImage = (EFI_PHYSICAL_ADDRESS)((UINTN)InitrdImageBase + 64);\r
+      InitrdImageSize = InitrdImageBaseSize - 64;\r
+    } else {\r
+      InitrdImage = InitrdImageBase;\r
+      InitrdImageSize = InitrdImageBaseSize;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Setup the Linux Kernel Parameters\r
+  //\r
+\r
+  // By setting address=0 we leave the memory allocation to the function\r
+  Status = PrepareAtagList (SystemMemoryBase, CommandLineArguments, InitrdImage, InitrdImageSize, &AtagBase, &AtagSize);\r
+  if (EFI_ERROR (Status)) {\r
+    Print (L"ERROR: Can not prepare ATAG list. Status=0x%X\n", Status);\r
+    goto EXIT_FREE_INITRD;\r
+  }\r
+\r
+  return StartLinux (SystemMemoryBase, LinuxImage, LinuxImageSize, AtagBase, AtagSize, MachineType);\r
+\r
+EXIT_FREE_INITRD:\r
+  if (InitrdDevicePath) {\r
+    gBS->FreePages (InitrdImageBase, EFI_SIZE_TO_PAGES (InitrdImageBaseSize));\r
+  }\r
+\r
+EXIT_FREE_LINUX:\r
+  gBS->FreePages (LinuxImage, EFI_SIZE_TO_PAGES (LinuxImageSize));\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Start a Linux kernel from a Device Path\r
+\r
+  @param  LinuxKernelDevicePath  Device Path to the Linux Kernel\r
+  @param  InitrdDevicePath       Device Path to the Initrd\r
+  @param  CommandLineArguments   Linux command line\r
+\r
+  @retval EFI_SUCCESS           All drivers have been connected\r
+  @retval EFI_NOT_FOUND         The Linux kernel Device Path has not been found\r
+  @retval EFI_OUT_OF_RESOURCES  There is not enough resource memory to store the matching results.\r
+\r
+**/\r
+EFI_STATUS\r
+BootLinuxFdt (\r
+  IN  EFI_PHYSICAL_ADDRESS      SystemMemoryBase,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL* FdtDevicePath,\r
+  IN  CONST CHAR8*              CommandLineArguments\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  UINT32                   LinuxImageSize;\r
+  UINT32                   InitrdImageBaseSize = 0;\r
+  UINT32                   InitrdImageSize = 0;\r
+  VOID                     *InstalledFdtBase;\r
+  UINT32                   FdtBlobSize;\r
+  EFI_PHYSICAL_ADDRESS     FdtBlobBase;\r
+  EFI_PHYSICAL_ADDRESS     LinuxImage;\r
+  EFI_PHYSICAL_ADDRESS     InitrdImageBase = 0;\r
+  EFI_PHYSICAL_ADDRESS     InitrdImage = 0;\r
+\r
+  PERF_START (NULL, "BDS", NULL, 0);\r
+\r
+  // Load the Linux kernel from a device path\r
+  LinuxImage = LINUX_KERNEL_MAX_OFFSET;\r
+  Status = BdsLoadImage (LinuxKernelDevicePath, AllocateMaxAddress, &LinuxImage, &LinuxImageSize);\r
+  if (EFI_ERROR (Status)) {\r
+    Print (L"ERROR: Did not find Linux kernel.\n");\r
+    return Status;\r
+  }\r
+\r
+  if (InitrdDevicePath) {\r
+    InitrdImageBase = LINUX_KERNEL_MAX_OFFSET;\r
+    Status = BdsLoadImage (InitrdDevicePath, AllocateMaxAddress, &InitrdImageBase, &InitrdImageBaseSize);\r
+    if (Status == EFI_OUT_OF_RESOURCES) {\r
+      Status = BdsLoadImage (InitrdDevicePath, AllocateAnyPages, &InitrdImageBase, &InitrdImageBaseSize);\r
+    }\r
+    if (EFI_ERROR (Status)) {\r
+      Print (L"ERROR: Did not find initrd image.\n");\r
+      goto EXIT_FREE_LINUX;\r
+    }\r
+\r
+    // Check if the initrd is a uInitrd\r
+    if (*(UINT32*)((UINTN)InitrdImageBase) == LINUX_UIMAGE_SIGNATURE) {\r
+      // Skip the 64-byte image header\r
+      InitrdImage = (EFI_PHYSICAL_ADDRESS)((UINTN)InitrdImageBase + 64);\r
+      InitrdImageSize = InitrdImageBaseSize - 64;\r
+    } else {\r
+      InitrdImage = InitrdImageBase;\r
+      InitrdImageSize = InitrdImageBaseSize;\r
+    }\r
+  }\r
+\r
+  if (FdtDevicePath == NULL) {\r
+    //\r
+    // Get the FDT from the Configuration Table.\r
+    // The FDT will be reloaded in PrepareFdt() to a more appropriate\r
+    // location for the Linux Kernel.\r
+    //\r
+    Status = EfiGetSystemConfigurationTable (&gFdtTableGuid, &InstalledFdtBase);\r
+    if (EFI_ERROR (Status)) {\r
+      Print (L"ERROR: Did not get the Device Tree blob (%r).\n", Status);\r
+      goto EXIT_FREE_INITRD;\r
+    }\r
+    FdtBlobBase = (EFI_PHYSICAL_ADDRESS)(UINTN)InstalledFdtBase;\r
+    FdtBlobSize = fdt_totalsize (InstalledFdtBase);\r
+  } else {\r
+    //\r
+    // FDT device path explicitly defined. The FDT is relocated later to a\r
+    // more appropriate location for the Linux kernel.\r
+    //\r
+    FdtBlobBase = LINUX_KERNEL_MAX_OFFSET;\r
+    Status = BdsLoadImage (FdtDevicePath, AllocateMaxAddress, &FdtBlobBase, &FdtBlobSize);\r
+    if (EFI_ERROR (Status)) {\r
+      Print (L"ERROR: Did not find Device Tree blob (%r).\n", Status);\r
+      goto EXIT_FREE_INITRD;\r
+    }\r
+  }\r
+\r
+  // Update the Fdt with the Initrd information. The FDT will increase in size.\r
+  // By setting address=0 we leave the memory allocation to the function\r
+  Status = PrepareFdt (SystemMemoryBase, CommandLineArguments, InitrdImage, InitrdImageSize, &FdtBlobBase, &FdtBlobSize);\r
+  if (EFI_ERROR (Status)) {\r
+    Print (L"ERROR: Can not load kernel with FDT. Status=%r\n", Status);\r
+    goto EXIT_FREE_FDT;\r
+  }\r
+\r
+  return StartLinux (SystemMemoryBase, LinuxImage, LinuxImageSize, FdtBlobBase, FdtBlobSize, ARM_FDT_MACHINE_TYPE);\r
+\r
+EXIT_FREE_FDT:\r
+  gBS->FreePages (FdtBlobBase, EFI_SIZE_TO_PAGES (FdtBlobSize));\r
+\r
+EXIT_FREE_INITRD:\r
+  if (InitrdDevicePath) {\r
+    gBS->FreePages (InitrdImageBase, EFI_SIZE_TO_PAGES (InitrdImageBaseSize));\r
+  }\r
+\r
+EXIT_FREE_LINUX:\r
+  gBS->FreePages (LinuxImage, EFI_SIZE_TO_PAGES (LinuxImageSize));\r
+\r
+  return Status;\r
+}\r
diff --git a/ArmPkg/Application/LinuxLoader/LinuxAtagLoader.c b/ArmPkg/Application/LinuxLoader/LinuxAtagLoader.c
deleted file mode 100644 (file)
index 50a4b47..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/** @file\r
-*\r
-*  Copyright (c) 2011, ARM Limited. All rights reserved.\r
-*\r
-*  This program and the accompanying materials\r
-*  are licensed and made available under the terms and conditions of the BSD License\r
-*  which accompanies this distribution.  The full text of the license may be found at\r
-*  http://opensource.org/licenses/bsd-license.php\r
-*\r
-*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-*\r
-**/\r
-\r
-#include "LinuxInternal.h"\r
-\r
-#include <Library/PrintLib.h>\r
-#include <Library/UefiApplicationEntryPoint.h>\r
-\r
-/**\r
-  The user Entry Point for Application. The user code starts with this function\r
-  as the real entry point for the application.\r
-\r
-  @param[in] ImageHandle    The firmware allocated handle for the EFI image.\r
-  @param[in] SystemTable    A pointer to the EFI System Table.\r
-\r
-  @retval EFI_SUCCESS       The entry point is executed successfully.\r
-  @retval other             Some error occurs when executing this entry point.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-UefiMain (\r
-  IN EFI_HANDLE        ImageHandle,\r
-  IN EFI_SYSTEM_TABLE  *SystemTable\r
-  )\r
-{\r
-  EFI_STATUS                   Status;\r
-  EFI_LOADED_IMAGE_PROTOCOL   *LoadedImage;\r
-  LINUX_LOADER_OPTIONAL_DATA*  LinuxOptionalData;\r
-  EFI_DEVICE_PATH*             DevicePathKernel;\r
-  EFI_DEVICE_PATH*             InitrdDevicePath;\r
-  CHAR16*                      OptionalDataInitrd;\r
-  CHAR8*                       OptionalDataArguments;\r
-  CHAR16*                      Initrd;\r
-\r
-  Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&LoadedImage);\r
-  ASSERT_EFI_ERROR (Status);\r
-\r
-  if (LoadedImage->LoadOptionsSize == 0) {\r
-    Status = LinuxLoaderConfig (LoadedImage);\r
-  } else {\r
-    // Ensure the signature is correct\r
-    LinuxOptionalData = (LINUX_LOADER_OPTIONAL_DATA*)LoadedImage->LoadOptions;\r
-    if (LinuxOptionalData->Signature != LINUX_LOADER_SIGNATURE) {\r
-      return EFI_UNSUPPORTED;\r
-    }\r
-\r
-    // Generate the File Path Node for the Linux Kernel\r
-    DevicePathKernel = FileDevicePath (LoadedImage->DeviceHandle, LINUX_KERNEL_NAME);\r
-\r
-    if (LinuxOptionalData->CmdLineLength > 0) {\r
-      OptionalDataArguments = (CHAR8*)LinuxOptionalData + sizeof(LINUX_LOADER_OPTIONAL_DATA);\r
-    } else {\r
-      OptionalDataArguments = NULL;\r
-    }\r
-\r
-    if (LinuxOptionalData->InitrdPathListLength > 0) {\r
-      if (OptionalDataArguments != NULL) {\r
-        OptionalDataInitrd = (CHAR16*)(OptionalDataArguments + LinuxOptionalData->CmdLineLength);\r
-      } else {\r
-        OptionalDataInitrd = (CHAR16*)LinuxOptionalData + sizeof(LINUX_LOADER_OPTIONAL_DATA);\r
-      }\r
-\r
-      // If pointer not aligned\r
-      if ((UINTN)OptionalDataInitrd & 0x1) {\r
-        Initrd = (CHAR16*)AllocateCopyPool (LinuxOptionalData->InitrdPathListLength, OptionalDataInitrd);\r
-      } else {\r
-        Initrd = OptionalDataInitrd;\r
-      }\r
-\r
-      InitrdDevicePath = FileDevicePath (LoadedImage->DeviceHandle, Initrd);\r
-    } else {\r
-      OptionalDataInitrd = NULL;\r
-      InitrdDevicePath   = NULL;\r
-      Initrd             = NULL;\r
-    }\r
-\r
-    // Load and Start the Linux Kernel (we should never return)\r
-    Status = BdsBootLinuxAtag (DevicePathKernel, InitrdDevicePath, OptionalDataArguments);\r
-\r
-    if ((UINTN)OptionalDataInitrd & 0x1) {\r
-      FreePool (Initrd);\r
-    }\r
-\r
-    FreePool (DevicePathKernel);\r
-    if (InitrdDevicePath) {\r
-      FreePool (InitrdDevicePath);\r
-    }\r
-  }\r
-\r
-  return Status;\r
-}\r
diff --git a/ArmPkg/Application/LinuxLoader/LinuxAtagLoader.inf b/ArmPkg/Application/LinuxLoader/LinuxAtagLoader.inf
deleted file mode 100644 (file)
index dcc2597..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-#/* @file\r
-#  Copyright (c) 2011-2013, ARM Limited. All rights reserved.\r
-#\r
-#  This program and the accompanying materials\r
-#  are licensed and made available under the terms and conditions of the BSD License\r
-#  which accompanies this distribution.  The full text of the license may be found at\r
-#  http://opensource.org/licenses/bsd-license.php\r
-#\r
-#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-#\r
-#*/\r
-\r
-[Defines]\r
-  INF_VERSION                    = 0x00010006\r
-  BASE_NAME                      = LinuxAtagLoader\r
-  FILE_GUID                      = a912f198-7f0e-4803-b908-b757b806ec83\r
-  MODULE_TYPE                    = UEFI_APPLICATION\r
-  VERSION_STRING                 = 0.1\r
-  ENTRY_POINT                    = UefiMain\r
-\r
-[Sources]\r
-  LinuxAtagLoader.c\r
-  LinuxConfig.c\r
-\r
-[Packages]\r
-  ArmPkg/ArmPkg.dec\r
-  MdePkg/MdePkg.dec\r
-\r
-[LibraryClasses]\r
-  BdsLib\r
-  DxeServicesTableLib\r
-  UefiLib\r
-  UefiApplicationEntryPoint\r
-\r
-[Protocols]\r
-  gEfiLoadedImageProtocolGuid\r
-  gEfiDevicePathToTextProtocolGuid\r
-\r
diff --git a/ArmPkg/Application/LinuxLoader/LinuxConfig.c b/ArmPkg/Application/LinuxLoader/LinuxConfig.c
deleted file mode 100644 (file)
index c88dc65..0000000
+++ /dev/null
@@ -1,354 +0,0 @@
-/** @file\r
-*\r
-*  Copyright (c) 2011-2013, ARM Limited. All rights reserved.\r
-*\r
-*  This program and the accompanying materials\r
-*  are licensed and made available under the terms and conditions of the BSD License\r
-*  which accompanies this distribution.  The full text of the license may be found at\r
-*  http://opensource.org/licenses/bsd-license.php\r
-*\r
-*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-*\r
-**/\r
-\r
-#include "LinuxInternal.h"\r
-\r
-#define DEFAULT_BOOT_ENTRY_DESCRIPTION  L"Linux"\r
-#define MAX_STR_INPUT                   300\r
-#define MAX_ASCII_INPUT                 300\r
-\r
-typedef enum {\r
-  LINUX_LOADER_NEW = 1,\r
-  LINUX_LOADER_UPDATE\r
-} LINUX_LOADER_ACTION;\r
-\r
-STATIC\r
-EFI_STATUS\r
-EditHIInputStr (\r
-  IN OUT CHAR16  *CmdLine,\r
-  IN     UINTN   MaxCmdLine\r
-  )\r
-{\r
-  UINTN           CmdLineIndex;\r
-  UINTN           WaitIndex;\r
-  CHAR8           Char;\r
-  EFI_INPUT_KEY   Key;\r
-  EFI_STATUS      Status;\r
-\r
-  Print (CmdLine);\r
-\r
-  for (CmdLineIndex = StrLen (CmdLine); CmdLineIndex < MaxCmdLine; ) {\r
-    Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &WaitIndex);\r
-    ASSERT_EFI_ERROR (Status);\r
-\r
-    Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
-    ASSERT_EFI_ERROR (Status);\r
-\r
-    // Unicode character is valid when Scancode is NUll\r
-    if (Key.ScanCode == SCAN_NULL) {\r
-      // Scan code is NUll, hence read Unicode character\r
-      Char = (CHAR8)Key.UnicodeChar;\r
-    } else {\r
-      Char = CHAR_NULL;\r
-    }\r
-\r
-    if ((Char == CHAR_LINEFEED) || (Char == CHAR_CARRIAGE_RETURN) || (Char == 0x7f)) {\r
-      CmdLine[CmdLineIndex] = '\0';\r
-      Print (L"\n\r");\r
-\r
-      return EFI_SUCCESS;\r
-    } else if ((Key.UnicodeChar == L'\b') || (Key.ScanCode == SCAN_LEFT) || (Key.ScanCode == SCAN_DELETE)){\r
-      if (CmdLineIndex != 0) {\r
-        CmdLineIndex--;\r
-        Print (L"\b \b");\r
-      }\r
-    } else if ((Key.ScanCode == SCAN_ESC) || (Char == 0x1B) || (Char == 0x0)) {\r
-      return EFI_INVALID_PARAMETER;\r
-    } else {\r
-      CmdLine[CmdLineIndex++] = Key.UnicodeChar;\r
-      Print (L"%c", Key.UnicodeChar);\r
-    }\r
-  }\r
-\r
-  return EFI_SUCCESS;\r
-}\r
-\r
-STATIC\r
-EFI_STATUS\r
-EditHIInputAscii (\r
-  IN OUT CHAR8   *CmdLine,\r
-  IN     UINTN   MaxCmdLine\r
-  )\r
-{\r
-  CHAR16*     Str;\r
-  EFI_STATUS  Status;\r
-\r
-  Str = (CHAR16*)AllocatePool (MaxCmdLine * sizeof(CHAR16));\r
-  AsciiStrToUnicodeStr (CmdLine, Str);\r
-\r
-  Status = EditHIInputStr (Str, MaxCmdLine);\r
-\r
-  UnicodeStrToAsciiStr (Str, CmdLine);\r
-  FreePool (Str);\r
-\r
-  return Status;\r
-}\r
-\r
-STATIC\r
-EFI_STATUS\r
-GetHIInputInteger (\r
-  OUT UINTN   *Integer\r
-  )\r
-{\r
-  CHAR16      CmdLine[255];\r
-  EFI_STATUS  Status;\r
-\r
-  CmdLine[0] = '\0';\r
-  Status = EditHIInputStr (CmdLine, 255);\r
-  if (!EFI_ERROR(Status)) {\r
-    *Integer = StrDecimalToUintn (CmdLine);\r
-  }\r
-\r
-  return Status;\r
-}\r
-\r
-#if 0\r
-EFI_STATUS\r
-GenerateDeviceDescriptionName (\r
-  IN  EFI_HANDLE  Handle,\r
-  IN OUT CHAR16*  Description\r
-  )\r
-{\r
-  EFI_STATUS                        Status;\r
-  EFI_COMPONENT_NAME_PROTOCOL*      ComponentName2Protocol;\r
-  EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r
-  EFI_DEVICE_PATH_PROTOCOL*         DevicePathProtocol;\r
-  CHAR16*                           DriverName;\r
-  CHAR16*                           DevicePathTxt;\r
-  EFI_DEVICE_PATH*                  DevicePathNode;\r
-\r
-  ComponentName2Protocol = NULL;\r
-  Status = gBS->HandleProtocol (Handle, &gEfiComponentName2ProtocolGuid, (VOID **)&ComponentName2Protocol);\r
-  if (!EFI_ERROR(Status)) {\r
-    //TODO: Fixme. we must find the best langague\r
-    Status = ComponentName2Protocol->GetDriverName (ComponentName2Protocol,"en",&DriverName);\r
-    if (!EFI_ERROR(Status)) {\r
-      StrnCpy (Description,DriverName,BOOT_DEVICE_DESCRIPTION_MAX);\r
-    }\r
-  }\r
-\r
-  if (EFI_ERROR(Status)) {\r
-    // Use the lastest non null entry of the Device path as a description\r
-    Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);\r
-    if (EFI_ERROR(Status)) {\r
-      return Status;\r
-    }\r
-\r
-    // Convert the last non end-type Device Path Node in text for the description\r
-    DevicePathNode = GetLastDevicePathNode (DevicePathProtocol);\r
-    Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r
-    ASSERT_EFI_ERROR(Status);\r
-    DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText(DevicePathNode,TRUE,TRUE);\r
-    StrnCpy (Description, DevicePathTxt, BOOT_DEVICE_DESCRIPTION_MAX);\r
-    FreePool (DevicePathTxt);\r
-  }\r
-\r
-  return EFI_SUCCESS;\r
-}\r
-#endif\r
-\r
-EFI_STATUS\r
-LinuxLoaderConfig (\r
-  IN EFI_LOADED_IMAGE_PROTOCOL   *LoadedImage\r
-  )\r
-{\r
-  EFI_STATUS                   Status;\r
-  LINUX_LOADER_ACTION          Choice;\r
-  UINTN                        BootOrderSize;\r
-  UINT16*                      BootOrder;\r
-  UINTN                        BootOrderCount;\r
-  UINTN                        Index;\r
-  CHAR16                       Description[MAX_ASCII_INPUT];\r
-  CHAR8                        CmdLine[MAX_ASCII_INPUT];\r
-  CHAR16                       Initrd[MAX_STR_INPUT];\r
-  UINT16                       InitrdPathListLength;\r
-  UINT16                       CmdLineLength;\r
-  BDS_LOAD_OPTION*             BdsLoadOption;\r
-  BDS_LOAD_OPTION**            SupportedBdsLoadOptions;\r
-  UINTN                        SupportedBdsLoadOptionCount;\r
-  LINUX_LOADER_OPTIONAL_DATA*  LinuxOptionalData;\r
-  EFI_DEVICE_PATH*             DevicePathRoot;\r
-\r
-  Choice = (LINUX_LOADER_ACTION)0;\r
-  SupportedBdsLoadOptions = NULL;\r
-  SupportedBdsLoadOptionCount = 0;\r
-\r
-  do {\r
-    Print (L"[%d] Create new Linux Boot Entry\n",LINUX_LOADER_NEW);\r
-    Print (L"[%d] Update Linux Boot Entry\n",LINUX_LOADER_UPDATE);\r
-\r
-    Print (L"Option: ");\r
-    Status = GetHIInputInteger ((UINTN*)&Choice);\r
-    if (Status == EFI_INVALID_PARAMETER) {\r
-      Print (L"\n");\r
-      return Status;\r
-    } else if ((Choice != LINUX_LOADER_NEW) && (Choice != LINUX_LOADER_UPDATE)) {\r
-      Print (L"Error: the option should be either '%d' or '%d'\n",LINUX_LOADER_NEW,LINUX_LOADER_UPDATE);\r
-      Status = EFI_INVALID_PARAMETER;\r
-    }\r
-  } while (EFI_ERROR(Status));\r
-\r
-  if (Choice == LINUX_LOADER_UPDATE) {\r
-    // If no compatible entry then we just create a new entry\r
-    Choice = LINUX_LOADER_NEW;\r
-\r
-    // Scan the OptionalData of every entry for the correct signature\r
-    Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);\r
-    if (!EFI_ERROR(Status)) {\r
-      BootOrderCount = BootOrderSize / sizeof(UINT16);\r
-\r
-      // Allocate an array to handle maximum number of supported Boot Entry\r
-      SupportedBdsLoadOptions = (BDS_LOAD_OPTION**)AllocatePool(sizeof(BDS_LOAD_OPTION*) * BootOrderCount);\r
-\r
-      SupportedBdsLoadOptionCount = 0;\r
-\r
-      // Check if the signature is present in the list of the current Boot entries\r
-      for (Index = 0; Index < BootOrderCount; Index++) {\r
-        Status = BootOptionFromLoadOptionIndex (BootOrder[Index], &BdsLoadOption);\r
-        if (!EFI_ERROR(Status)) {\r
-          if ((BdsLoadOption->OptionalDataSize >= sizeof(UINT32)) &&\r
-              (*(UINT32*)BdsLoadOption->OptionalData == LINUX_LOADER_SIGNATURE)) {\r
-            SupportedBdsLoadOptions[SupportedBdsLoadOptionCount++] = BdsLoadOption;\r
-            Choice = LINUX_LOADER_UPDATE;\r
-          }\r
-        }\r
-      }\r
-    }\r
-    FreePool (BootOrder);\r
-  }\r
-\r
-  if (Choice == LINUX_LOADER_NEW) {\r
-    Description[0] = '\0';\r
-    CmdLine[0]     = '\0';\r
-    Initrd[0]      = '\0';\r
-\r
-    BdsLoadOption = (BDS_LOAD_OPTION*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION));\r
-\r
-    DEBUG_CODE_BEGIN();\r
-      CHAR16*                           DevicePathTxt;\r
-      EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r
-\r
-      Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r
-      ASSERT_EFI_ERROR(Status);\r
-      DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (LoadedImage->FilePath, TRUE, TRUE);\r
-\r
-      Print(L"EFI OS Loader: %s\n",DevicePathTxt);\r
-\r
-      FreePool(DevicePathTxt);\r
-    DEBUG_CODE_END();\r
-\r
-    //\r
-    // Fill the known fields of BdsLoadOption\r
-    //\r
-\r
-    BdsLoadOption->Attributes = LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_BOOT;\r
-\r
-    // Get the full Device Path for this file\r
-    Status = gBS->HandleProtocol (LoadedImage->DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathRoot);\r
-    ASSERT_EFI_ERROR(Status);\r
-\r
-    BdsLoadOption->FilePathList = AppendDevicePath (DevicePathRoot, LoadedImage->FilePath);\r
-    BdsLoadOption->FilePathListLength = GetDevicePathSize (BdsLoadOption->FilePathList);\r
-  } else {\r
-    if (SupportedBdsLoadOptionCount > 1) {\r
-      for (Index = 0; Index < SupportedBdsLoadOptionCount; Index++) {\r
-        Print (L"[%d] %s\n",Index + 1,SupportedBdsLoadOptions[Index]->Description);\r
-      }\r
-\r
-      do {\r
-        Print (L"Update Boot Entry: ");\r
-        Status = GetHIInputInteger ((UINTN*)&Choice);\r
-        if (Status == EFI_INVALID_PARAMETER) {\r
-          Print (L"\n");\r
-          return Status;\r
-        } else if ((Choice < 1) && (Choice > SupportedBdsLoadOptionCount)) {\r
-          Print (L"Choose entry from 1 to %d\n",SupportedBdsLoadOptionCount);\r
-          Status = EFI_INVALID_PARAMETER;\r
-        }\r
-      } while (EFI_ERROR(Status));\r
-      BdsLoadOption = SupportedBdsLoadOptions[Choice-1];\r
-    }\r
-    StrnCpy (Description, BdsLoadOption->Description, MAX_STR_INPUT);\r
-\r
-    LinuxOptionalData = (LINUX_LOADER_OPTIONAL_DATA*)BdsLoadOption->OptionalData;\r
-    if (LinuxOptionalData->CmdLineLength > 0) {\r
-      CopyMem (CmdLine, (CHAR8*)LinuxOptionalData + sizeof(LINUX_LOADER_OPTIONAL_DATA), LinuxOptionalData->CmdLineLength);\r
-    } else {\r
-      CmdLine[0] = '\0';\r
-    }\r
-\r
-    if (LinuxOptionalData->InitrdPathListLength > 0) {\r
-      CopyMem (Initrd, (CHAR8*)LinuxOptionalData + sizeof(LINUX_LOADER_OPTIONAL_DATA) + LinuxOptionalData->CmdLineLength, LinuxOptionalData->InitrdPathListLength);\r
-    } else {\r
-      Initrd[0] = L'\0';\r
-    }\r
-    DEBUG((EFI_D_ERROR,"L\n"));\r
-  }\r
-\r
-  // Description\r
-  Print (L"Description: ");\r
-  Status = EditHIInputStr (Description, MAX_STR_INPUT);\r
-  if (EFI_ERROR(Status)) {\r
-    return Status;\r
-  }\r
-  if (StrLen (Description) == 0) {\r
-    StrnCpy (Description, DEFAULT_BOOT_ENTRY_DESCRIPTION, MAX_STR_INPUT);\r
-  }\r
-  BdsLoadOption->Description = Description;\r
-\r
-  // CmdLine\r
-  Print (L"Command Line: ");\r
-  Status = EditHIInputAscii (CmdLine, MAX_ASCII_INPUT);\r
-  if (EFI_ERROR(Status)) {\r
-    return Status;\r
-  }\r
-\r
-  // Initrd\r
-  Print (L"Initrd name: ");\r
-  Status = EditHIInputStr (Initrd, MAX_STR_INPUT);\r
-  if (EFI_ERROR(Status)) {\r
-    return Status;\r
-  }\r
-\r
-  CmdLineLength = AsciiStrLen (CmdLine);\r
-  if (CmdLineLength > 0) {\r
-    CmdLineLength += sizeof(CHAR8);\r
-  }\r
-\r
-  InitrdPathListLength = StrLen (Initrd) * sizeof(CHAR16);\r
-  if (InitrdPathListLength > 0) {\r
-    InitrdPathListLength += sizeof(CHAR16);\r
-  }\r
-\r
-  BdsLoadOption->OptionalDataSize = sizeof(LINUX_LOADER_OPTIONAL_DATA) + CmdLineLength + InitrdPathListLength;\r
-\r
-  LinuxOptionalData = (LINUX_LOADER_OPTIONAL_DATA*)AllocatePool (BdsLoadOption->OptionalDataSize);\r
-  BdsLoadOption->OptionalData = LinuxOptionalData;\r
-\r
-  LinuxOptionalData->Signature = LINUX_LOADER_SIGNATURE;\r
-  LinuxOptionalData->CmdLineLength = CmdLineLength;\r
-  LinuxOptionalData->InitrdPathListLength = InitrdPathListLength;\r
-\r
-  if (CmdLineLength > 0) {\r
-    CopyMem (LinuxOptionalData + 1, CmdLine, CmdLineLength);\r
-  }\r
-  if (InitrdPathListLength > 0) {\r
-    CopyMem ((UINT8*)(LinuxOptionalData + 1) + CmdLineLength, Initrd, InitrdPathListLength);\r
-  }\r
-\r
-  // Create or Update the boot entry\r
-  Status = BootOptionToLoadOptionVariable (BdsLoadOption);\r
-\r
-  return Status;\r
-}\r
diff --git a/ArmPkg/Application/LinuxLoader/LinuxFdtLoader.c b/ArmPkg/Application/LinuxLoader/LinuxFdtLoader.c
deleted file mode 100644 (file)
index 8e5d1c6..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/** @file\r
-*\r
-*  Copyright (c) 2011, ARM Limited. All rights reserved.\r
-*\r
-*  This program and the accompanying materials\r
-*  are licensed and made available under the terms and conditions of the BSD License\r
-*  which accompanies this distribution.  The full text of the license may be found at\r
-*  http://opensource.org/licenses/bsd-license.php\r
-*\r
-*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-*\r
-**/\r
-\r
-#include "LinuxInternal.h"\r
-\r
-#include <Library/PrintLib.h>\r
-#include <Library/UefiApplicationEntryPoint.h>\r
-\r
-/**\r
-  The user Entry Point for Application. The user code starts with this function\r
-  as the real entry point for the application.\r
-\r
-  @param[in] ImageHandle    The firmware allocated handle for the EFI image.\r
-  @param[in] SystemTable    A pointer to the EFI System Table.\r
-\r
-  @retval EFI_SUCCESS       The entry point is executed successfully.\r
-  @retval other             Some error occurs when executing this entry point.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-UefiMain (\r
-  IN EFI_HANDLE        ImageHandle,\r
-  IN EFI_SYSTEM_TABLE  *SystemTable\r
-  )\r
-{\r
-  EFI_STATUS                   Status;\r
-  EFI_LOADED_IMAGE_PROTOCOL   *LoadedImage;\r
-  LINUX_LOADER_OPTIONAL_DATA*  LinuxOptionalData;\r
-  EFI_DEVICE_PATH*             DevicePathKernel;\r
-  EFI_DEVICE_PATH*             InitrdDevicePath;\r
-  CHAR16*                      OptionalDataInitrd;\r
-  CHAR8*                       OptionalDataArguments;\r
-  CHAR16*                      Initrd;\r
-\r
-  Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&LoadedImage);\r
-  ASSERT_EFI_ERROR (Status);\r
-\r
-  if (LoadedImage->LoadOptionsSize == 0) {\r
-    Status = LinuxLoaderConfig (LoadedImage);\r
-  } else {\r
-    // Ensure the signature is correct\r
-    LinuxOptionalData = (LINUX_LOADER_OPTIONAL_DATA*)LoadedImage->LoadOptions;\r
-    if (LinuxOptionalData->Signature != LINUX_LOADER_SIGNATURE) {\r
-      return EFI_UNSUPPORTED;\r
-    }\r
-\r
-    // Generate the File Path Node for the Linux Kernel\r
-    DevicePathKernel = FileDevicePath (LoadedImage->DeviceHandle, LINUX_KERNEL_NAME);\r
-\r
-    if (LinuxOptionalData->CmdLineLength > 0) {\r
-      OptionalDataArguments = (CHAR8*)LinuxOptionalData + sizeof(LINUX_LOADER_OPTIONAL_DATA);\r
-    } else {\r
-      OptionalDataArguments = NULL;\r
-    }\r
-\r
-    if (LinuxOptionalData->InitrdPathListLength > 0) {\r
-      if (OptionalDataArguments != NULL) {\r
-        OptionalDataInitrd = (CHAR16*)(OptionalDataArguments + LinuxOptionalData->CmdLineLength);\r
-      } else {\r
-        OptionalDataInitrd = (CHAR16*)LinuxOptionalData + sizeof(LINUX_LOADER_OPTIONAL_DATA);\r
-      }\r
-\r
-      // If pointer not aligned\r
-      if ((UINTN)OptionalDataInitrd & 0x1) {\r
-        Initrd = (CHAR16*)AllocateCopyPool (LinuxOptionalData->InitrdPathListLength, OptionalDataInitrd);\r
-      } else {\r
-        Initrd = OptionalDataInitrd;\r
-      }\r
-\r
-      InitrdDevicePath = FileDevicePath (LoadedImage->DeviceHandle, Initrd);\r
-    } else {\r
-      OptionalDataInitrd = NULL;\r
-      InitrdDevicePath   = NULL;\r
-      Initrd             = NULL;\r
-    }\r
-\r
-    // Load and Start the Linux Kernel (we should never return)\r
-    Status = BdsBootLinuxFdt (DevicePathKernel, InitrdDevicePath, OptionalDataArguments);\r
-\r
-    if ((UINTN)OptionalDataInitrd & 0x1) {\r
-      FreePool (Initrd);\r
-    }\r
-\r
-    FreePool (DevicePathKernel);\r
-    if (InitrdDevicePath) {\r
-      FreePool (InitrdDevicePath);\r
-    }\r
-  }\r
-\r
-  return Status;\r
-}\r
diff --git a/ArmPkg/Application/LinuxLoader/LinuxFdtLoader.inf b/ArmPkg/Application/LinuxLoader/LinuxFdtLoader.inf
deleted file mode 100644 (file)
index 55a6969..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-#/* @file\r
-#  Copyright (c) 2011-2013, ARM Limited. All rights reserved.\r
-#\r
-#  This program and the accompanying materials\r
-#  are licensed and made available under the terms and conditions of the BSD License\r
-#  which accompanies this distribution.  The full text of the license may be found at\r
-#  http://opensource.org/licenses/bsd-license.php\r
-#\r
-#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-#\r
-#*/\r
-\r
-[Defines]\r
-  INF_VERSION                    = 0x00010006\r
-  BASE_NAME                      = LinuxFdtLoader\r
-  FILE_GUID                      = f536d559-459f-48fa-8bbc-43b554ecae8d\r
-  MODULE_TYPE                    = UEFI_APPLICATION\r
-  VERSION_STRING                 = 0.1\r
-  ENTRY_POINT                    = UefiMain\r
-\r
-[Sources]\r
-  LinuxFdtLoader.c\r
-  LinuxConfig.c\r
-\r
-[Packages]\r
-  ArmPkg/ArmPkg.dec\r
-  MdePkg/MdePkg.dec\r
-\r
-[LibraryClasses]\r
-  BdsLib\r
-  DxeServicesTableLib\r
-  UefiLib\r
-  UefiApplicationEntryPoint\r
-\r
-[Protocols]\r
-  gEfiLoadedImageProtocolGuid\r
-  gEfiDevicePathToTextProtocolGuid\r
-\r
diff --git a/ArmPkg/Application/LinuxLoader/LinuxInternal.h b/ArmPkg/Application/LinuxLoader/LinuxInternal.h
deleted file mode 100644 (file)
index 88d786f..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/** @file\r
-*\r
-*  Copyright (c) 2011-2013, ARM Limited. All rights reserved.\r
-*\r
-*  This program and the accompanying materials\r
-*  are licensed and made available under the terms and conditions of the BSD License\r
-*  which accompanies this distribution.  The full text of the license may be found at\r
-*  http://opensource.org/licenses/bsd-license.php\r
-*\r
-*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-*\r
-**/\r
-\r
-#ifndef __LOADER_INTERNAL_H\r
-#define __LOADER_INTERNAL_H\r
-\r
-#include <Uefi.h>\r
-#include <Library/BaseMemoryLib.h>\r
-#include <Library/BdsLib.h>\r
-#include <Library/DebugLib.h>\r
-#include <Library/DevicePathLib.h>\r
-#include <Library/MemoryAllocationLib.h>\r
-#include <Library/UefiBootServicesTableLib.h>\r
-#include <Library/UefiLib.h>\r
-\r
-#include <Protocol/LoadedImage.h>\r
-#include <Protocol/DevicePathToText.h>\r
-\r
-#define LINUX_KERNEL_NAME               L"zImage"\r
-#define FDT_NAME                        L"platform.dtb"\r
-\r
-#define LINUX_LOADER_SIGNATURE    SIGNATURE_32('l', 'i', 'l', 'o')\r
-\r
-typedef struct {\r
-  UINT32                        Signature;\r
-  UINT16                        CmdLineLength;\r
-  UINT16                        InitrdPathListLength;\r
-\r
-  // These following fields have variable length:\r
-  //CHAR8*                      CmdLine;\r
-  //CHAR16*                     Initrd;\r
-} LINUX_LOADER_OPTIONAL_DATA;\r
-\r
-EFI_STATUS\r
-LinuxLoaderConfig (\r
-  IN EFI_LOADED_IMAGE_PROTOCOL   *LoadedImage\r
-  );\r
-\r
-#endif\r
diff --git a/ArmPkg/Application/LinuxLoader/LinuxLoader.c b/ArmPkg/Application/LinuxLoader/LinuxLoader.c
new file mode 100644 (file)
index 0000000..70b960b
--- /dev/null
@@ -0,0 +1,246 @@
+/** @file\r
+*\r
+*  Copyright (c) 2011-2015, ARM Limited. All rights reserved.\r
+*\r
+*  This program and the accompanying materials\r
+*  are licensed and made available under the terms and conditions of the BSD License\r
+*  which accompanies this distribution.  The full text of the license may be found at\r
+*  http://opensource.org/licenses/bsd-license.php\r
+*\r
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+*\r
+**/\r
+\r
+#include <Library/UefiApplicationEntryPoint.h>\r
+#include <Library/BaseMemoryLib.h>\r
+\r
+#include <Protocol/DevicePathFromText.h>\r
+\r
+#include "LinuxLoader.h"\r
+\r
+/**\r
+  The user Entry Point for Application. The user code starts with this function\r
+  as the real entry point for the application.\r
+\r
+  @param[in]  ImageHandle  The firmware allocated handle for the EFI image.\r
+  @param[in]  SystemTable  A pointer to the EFI System Table.\r
+\r
+  @retval  EFI_SUCCESS            The entry point was executed successfully.\r
+  @retval  EFI_NOT_FOUND          Protocol not found.\r
+  @retval  EFI_NOT_FOUND          Path to the Linux kernel not found.\r
+  @retval  EFI_ABORTED            The initialisation of the Shell Library failed.\r
+  @retval  EFI_INVALID_PARAMETER  At least one parameter is not valid or there is a\r
+                                  conflict between two parameters.\r
+  @retval  EFI_OUT_OF_RESOURCES   A memory allocation failed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LinuxLoaderEntryPoint (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL  *EfiDevicePathFromTextProtocol;\r
+  EFI_SHELL_PARAMETERS_PROTOCOL       *ShellParameters;\r
+  CHAR16                              *KernelPath;\r
+  CHAR16                              *FdtPath;\r
+  CHAR16                              *InitrdPath;\r
+  CHAR16                              *KernelTextDevicePath;\r
+  CHAR16                              *FdtTextDevicePath;\r
+  CHAR16                              *InitrdTextDevicePath;\r
+  CHAR16                              *LinuxCommandLine;\r
+  UINTN                               AtagMachineType;\r
+  EFI_DEVICE_PATH                     *KernelDevicePath;\r
+  EFI_DEVICE_PATH                     *FdtDevicePath;\r
+  EFI_DEVICE_PATH                     *InitrdDevicePath;\r
+  CHAR8                               *AsciiLinuxCommandLine;\r
+  LIST_ENTRY                          ResourceList;\r
+  LIST_ENTRY                          *ResourceLink;\r
+  SYSTEM_MEMORY_RESOURCE              *Resource;\r
+  EFI_PHYSICAL_ADDRESS                SystemMemoryBase;\r
+\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiDevicePathFromTextProtocolGuid,\r
+                  NULL,\r
+                  (VOID **)&EfiDevicePathFromTextProtocol\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // Register the strings for the user interface in the HII Database.\r
+  // This shows the way to the multi-language support, even if\r
+  // only the English language is actually supported. The strings to register\r
+  // are stored in the "LinuxLoaderStrings[]" array. This array is\r
+  // built by the building process from the "*.uni" file associated to\r
+  // the present application (cf. LinuxLoader.inf). Examine the Build\r
+  // folder of the application and you will find the array defined in the\r
+  // LinuxLoaderStrDefs.h file.\r
+  //\r
+  mLinuxLoaderHiiHandle = HiiAddPackages (\r
+                             &mLinuxLoaderHiiGuid,\r
+                             ImageHandle,\r
+                             LinuxLoaderStrings,\r
+                             NULL\r
+                             );\r
+  if (mLinuxLoaderHiiHandle == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  Status = gBS->HandleProtocol (\r
+                  ImageHandle,\r
+                  &gEfiShellParametersProtocolGuid,\r
+                  (VOID**)&ShellParameters\r
+                  );\r
+\r
+  KernelDevicePath      = NULL;\r
+  FdtDevicePath         = NULL;\r
+  InitrdDevicePath      = NULL;\r
+  AsciiLinuxCommandLine = NULL;\r
+\r
+  //\r
+  // Call the proper function to handle the command line\r
+  // depending on whether the application has been called\r
+  // from the Shell or not.\r
+  //\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    KernelTextDevicePath = NULL;\r
+    FdtTextDevicePath    = NULL;\r
+    InitrdTextDevicePath = NULL;\r
+\r
+    Status = ProcessShellParameters (\r
+               &KernelPath, &FdtPath, &InitrdPath, &LinuxCommandLine, &AtagMachineType\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
+\r
+    KernelDevicePath = gEfiShellProtocol->GetDevicePathFromFilePath (KernelPath);\r
+    if (KernelDevicePath != NULL) {\r
+      FreePool (KernelPath);\r
+    } else {\r
+      KernelTextDevicePath = KernelPath;\r
+    }\r
+\r
+    if (FdtPath != NULL) {\r
+      FdtDevicePath = gEfiShellProtocol->GetDevicePathFromFilePath (FdtPath);\r
+      if (FdtDevicePath != NULL) {\r
+        FreePool (FdtPath);\r
+      } else {\r
+        FdtTextDevicePath = FdtPath;\r
+      }\r
+    }\r
+\r
+    if (InitrdPath != NULL) {\r
+      InitrdDevicePath = gEfiShellProtocol->GetDevicePathFromFilePath (InitrdPath);\r
+      if (InitrdDevicePath != NULL) {\r
+        FreePool (InitrdPath);\r
+      } else {\r
+        InitrdTextDevicePath = InitrdPath;\r
+      }\r
+    }\r
+\r
+  } else {\r
+    Status = ProcessAppCommandLine (\r
+               &KernelTextDevicePath, &FdtTextDevicePath,\r
+               &InitrdTextDevicePath, &LinuxCommandLine, &AtagMachineType\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
+  }\r
+\r
+  Status = EFI_INVALID_PARAMETER;\r
+  if (KernelTextDevicePath != NULL) {\r
+    KernelDevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (\r
+                                                        KernelTextDevicePath\r
+                                                        );\r
+    if (KernelDevicePath == NULL) {\r
+      goto Error;\r
+    }\r
+  }\r
+  if (FdtTextDevicePath != NULL) {\r
+    FdtDevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (\r
+                                                     FdtTextDevicePath\r
+                                                     );\r
+    if (FdtDevicePath == NULL) {\r
+      goto Error;\r
+    }\r
+  }\r
+  if (InitrdTextDevicePath != NULL) {\r
+    InitrdDevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (\r
+                                                        InitrdTextDevicePath\r
+                                                        );\r
+    if (InitrdDevicePath == NULL) {\r
+      goto Error;\r
+    }\r
+  }\r
+\r
+  if (LinuxCommandLine != NULL) {\r
+    AsciiLinuxCommandLine = AllocatePool ((StrLen (LinuxCommandLine) + 1) * sizeof (CHAR8));\r
+    if (AsciiLinuxCommandLine == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto Error;\r
+    }\r
+    UnicodeStrToAsciiStr (LinuxCommandLine, AsciiLinuxCommandLine);\r
+  }\r
+\r
+  //\r
+  // Find Base of System Memory - we keep the lowest physical address\r
+  //\r
+  SystemMemoryBase = ~0;\r
+  GetSystemMemoryResources (&ResourceList);\r
+  ResourceLink = ResourceList.ForwardLink;\r
+  while (ResourceLink != NULL && ResourceLink != &ResourceList) {\r
+    Resource = (SYSTEM_MEMORY_RESOURCE*)ResourceLink;\r
+    if (Resource->PhysicalStart < SystemMemoryBase) {\r
+      SystemMemoryBase = Resource->PhysicalStart;\r
+    }\r
+    ResourceLink = ResourceLink->ForwardLink;\r
+  }\r
+\r
+  if (AtagMachineType != ARM_FDT_MACHINE_TYPE) {\r
+    Status = BootLinuxAtag (SystemMemoryBase, KernelDevicePath, InitrdDevicePath, AsciiLinuxCommandLine, AtagMachineType);\r
+  } else {\r
+    Status = BootLinuxFdt (SystemMemoryBase, KernelDevicePath, InitrdDevicePath, FdtDevicePath, AsciiLinuxCommandLine);\r
+  }\r
+\r
+Error:\r
+  if (KernelTextDevicePath != NULL) {\r
+    FreePool (KernelTextDevicePath);\r
+  }\r
+  if (FdtTextDevicePath != NULL) {\r
+    FreePool (FdtTextDevicePath);\r
+  }\r
+  if (InitrdTextDevicePath != NULL) {\r
+    FreePool (InitrdTextDevicePath);\r
+  }\r
+  if (LinuxCommandLine != NULL) {\r
+    FreePool (LinuxCommandLine);\r
+  }\r
+  if (KernelDevicePath != NULL) {\r
+    FreePool (KernelDevicePath);\r
+  }\r
+  if (FdtDevicePath != NULL) {\r
+    FreePool (FdtDevicePath);\r
+  }\r
+  if (InitrdDevicePath != NULL) {\r
+    FreePool (InitrdDevicePath);\r
+  }\r
+  if (AsciiLinuxCommandLine != NULL) {\r
+    FreePool (AsciiLinuxCommandLine);\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    PrintHii (NULL, STRING_TOKEN (STR_ERROR), Status);\r
+  }\r
+\r
+  HiiRemovePackages (mLinuxLoaderHiiHandle);\r
+\r
+  return Status;\r
+}\r
diff --git a/ArmPkg/Application/LinuxLoader/LinuxLoader.h b/ArmPkg/Application/LinuxLoader/LinuxLoader.h
new file mode 100644 (file)
index 0000000..8a23d7f
--- /dev/null
@@ -0,0 +1,166 @@
+/** @file\r
+*\r
+*  Copyright (c) 2011-2015, ARM Limited. All rights reserved.\r
+*\r
+*  This program and the accompanying materials\r
+*  are licensed and made available under the terms and conditions of the BSD License\r
+*  which accompanies this distribution.  The full text of the license may be found at\r
+*  http://opensource.org/licenses/bsd-license.php\r
+*\r
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+*\r
+**/\r
+\r
+#ifndef __LINUX_LOADER_H__\r
+#define __LINUX_LOADER_H__\r
+\r
+#include <Library/BdsLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/HiiLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/PerformanceLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/ShellLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+\r
+#include <Protocol/EfiShellParameters.h>\r
+#include <Protocol/EfiShell.h>\r
+\r
+#include <libfdt.h>\r
+\r
+//\r
+// Definitions\r
+//\r
+\r
+#define MAX_MSG_LEN 80\r
+\r
+#define LINUX_UIMAGE_SIGNATURE    0x56190527\r
+#define LINUX_KERNEL_MAX_OFFSET   (SystemMemoryBase + PcdGet32(PcdArmLinuxKernelMaxOffset))\r
+#define LINUX_ATAG_MAX_OFFSET     (SystemMemoryBase + PcdGet32(PcdArmLinuxAtagMaxOffset))\r
+#define LINUX_FDT_MAX_OFFSET      (SystemMemoryBase + PcdGet32(PcdArmLinuxFdtMaxOffset))\r
+\r
+#define ARM_FDT_MACHINE_TYPE      0xFFFFFFFF\r
+\r
+// Additional size that could be used for FDT entries added by the UEFI OS Loader\r
+// Estimation based on: EDID (300bytes) + bootargs (200bytes) + initrd region (20bytes)\r
+//                      + system memory region (20bytes) + mp_core entries (200 bytes)\r
+#define FDT_ADDITIONAL_ENTRIES_SIZE     0x300\r
+\r
+//\r
+// Global variables\r
+//\r
+extern CONST EFI_GUID mLinuxLoaderHiiGuid;\r
+extern EFI_HANDLE mLinuxLoaderHiiHandle;\r
+\r
+//\r
+// Local Types\r
+//\r
+typedef struct _SYSTEM_MEMORY_RESOURCE {\r
+  LIST_ENTRY                  Link; // This attribute must be the first entry of this structure (to avoid pointer computation)\r
+  EFI_PHYSICAL_ADDRESS        PhysicalStart;\r
+  UINT64                      ResourceLength;\r
+} SYSTEM_MEMORY_RESOURCE;\r
+\r
+typedef VOID (*LINUX_KERNEL)(UINT32 Zero, UINT32 Arch, UINTN ParametersBase);\r
+\r
+//\r
+// Functions\r
+//\r
+EFI_STATUS\r
+PrintHii (\r
+  IN CONST CHAR8          *Language OPTIONAL,\r
+  IN CONST EFI_STRING_ID  HiiFormatStringId,\r
+  ...\r
+  );\r
+\r
+VOID\r
+PrintHelp (\r
+  IN CONST CHAR8  *Language OPTIONAL\r
+  );\r
+\r
+EFI_STATUS\r
+ProcessShellParameters (\r
+  OUT  CHAR16   **KernelPath,\r
+  OUT  CHAR16   **FdtPath,\r
+  OUT  CHAR16   **InitrdPath,\r
+  OUT  CHAR16   **LinuxCommandLine,\r
+  OUT  UINTN    *AtagMachineType\r
+  );\r
+\r
+EFI_STATUS\r
+ProcessAppCommandLine (\r
+  OUT  CHAR16   **KernelTextDevicePath,\r
+  OUT  CHAR16   **FdtTextDevicePath,\r
+  OUT  CHAR16   **InitrdTextDevicePath,\r
+  OUT  CHAR16   **LinuxCommandLine,\r
+  OUT  UINTN    *AtagMachineType\r
+  );\r
+\r
+VOID\r
+PrintPerformance (\r
+  VOID\r
+  );\r
+\r
+EFI_STATUS\r
+GetSystemMemoryResources (\r
+  IN  LIST_ENTRY *ResourceList\r
+  );\r
+\r
+EFI_STATUS\r
+PrepareFdt (\r
+  IN     EFI_PHYSICAL_ADDRESS SystemMemoryBase,\r
+  IN     CONST CHAR8*         CommandLineArguments,\r
+  IN     EFI_PHYSICAL_ADDRESS InitrdImage,\r
+  IN     UINTN                InitrdImageSize,\r
+  IN OUT EFI_PHYSICAL_ADDRESS *FdtBlobBase,\r
+  IN OUT UINTN                *FdtBlobSize\r
+  );\r
+\r
+/**\r
+  Start a Linux kernel from a Device Path\r
+\r
+  @param  SystemMemoryBase      Base of the system memory\r
+  @param  LinuxKernel           Device Path to the Linux Kernel\r
+  @param  Parameters            Linux kernel arguments\r
+  @param  Fdt                   Device Path to the Flat Device Tree\r
+  @param  MachineType           ARM machine type value\r
+\r
+  @retval EFI_SUCCESS           All drivers have been connected\r
+  @retval EFI_NOT_FOUND         The Linux kernel Device Path has not been found\r
+  @retval EFI_OUT_OF_RESOURCES  There is not enough resource memory to store the matching results.\r
+  @retval RETURN_UNSUPPORTED    ATAG is not support by this architecture\r
+\r
+**/\r
+EFI_STATUS\r
+BootLinuxAtag (\r
+  IN  EFI_PHYSICAL_ADDRESS      SystemMemoryBase,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath,\r
+  IN  CONST CHAR8*              CommandLineArguments,\r
+  IN  UINTN                     MachineType\r
+  );\r
+\r
+/**\r
+  Start a Linux kernel from a Device Path\r
+\r
+  @param[in]  LinuxKernelDevicePath  Device Path to the Linux Kernel\r
+  @param[in]  InitrdDevicePath       Device Path to the Initrd\r
+  @param[in]  Arguments              Linux kernel arguments\r
+\r
+  @retval EFI_SUCCESS           All drivers have been connected\r
+  @retval EFI_NOT_FOUND         The Linux kernel Device Path has not been found\r
+  @retval EFI_OUT_OF_RESOURCES  There is not enough resource memory to store the matching results.\r
+\r
+**/\r
+EFI_STATUS\r
+BootLinuxFdt (\r
+  IN  EFI_PHYSICAL_ADDRESS      SystemMemoryBase,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL* FdtDevicePath,\r
+  IN  CONST CHAR8*              Arguments\r
+  );\r
+\r
+#endif /* __LINUX_LOADER_H__ */\r
diff --git a/ArmPkg/Application/LinuxLoader/LinuxLoader.inf b/ArmPkg/Application/LinuxLoader/LinuxLoader.inf
new file mode 100644 (file)
index 0000000..59ab99c
--- /dev/null
@@ -0,0 +1,91 @@
+#/* @file\r
+#  Copyright (c) 2015, ARM Limited. All rights reserved.\r
+#\r
+#  This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution.  The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php\r
+#\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#*/\r
+\r
+[Defines]\r
+  INF_VERSION     = 0x00010006\r
+  BASE_NAME       = LinuxLoader\r
+  MODULE_UNI_FILE = LinuxLoader.uni\r
+  FILE_GUID       = 701f54f2-0d70-4b89-bc0a-d9ca25379059\r
+  MODULE_TYPE     = UEFI_APPLICATION\r
+  VERSION_STRING  = 0.1\r
+  ENTRY_POINT     = LinuxLoaderEntryPoint\r
+\r
+[Sources]\r
+  LinuxLoader.c\r
+  LinuxLoader.h\r
+  LinuxLoader.uni\r
+  LinuxLoaderFdt.c\r
+  LinuxLoaderHelper.c\r
+  LinuxLoaderEfiApp.c\r
+  LinuxLoaderShellApp.c\r
+\r
+[Sources.AARCH64]\r
+  AArch64/LinuxStarter.c\r
+  AArch64/LinuxStarterHelper.S\r
+\r
+[Sources.ARM]\r
+  Arm/LinuxAtag.h\r
+  Arm/LinuxAtag.c\r
+  Arm/LinuxStarter.c\r
+\r
+[Packages]\r
+  ArmPkg/ArmPkg.dec\r
+  EmbeddedPkg/EmbeddedPkg.dec\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  ShellPkg/ShellPkg.dec\r
+\r
+[Guids]\r
+  gFdtTableGuid\r
+\r
+[Guids]\r
+  gArmMpCoreInfoGuid\r
+\r
+[LibraryClasses]\r
+  ArmLib\r
+  BdsLib\r
+  DebugLib\r
+  DxeServicesTableLib\r
+  FdtLib\r
+  HiiLib\r
+  HobLib\r
+  PerformanceLib\r
+  ShellLib\r
+  SerialPortLib\r
+  TimerLib\r
+  UefiApplicationEntryPoint\r
+  UefiLib\r
+\r
+[LibraryClasses.AARCH64]\r
+  ArmGicLib\r
+  PcdLib\r
+\r
+[Protocols]\r
+  gEfiLoadedImageProtocolGuid\r
+  gEfiDevicePathToTextProtocolGuid\r
+  gEfiShellParametersProtocolGuid\r
+\r
+[FeaturePcd]\r
+  gArmTokenSpaceGuid.PcdArmLinuxSpinTable\r
+\r
+[FixedPcd]\r
+  gArmTokenSpaceGuid.PcdArmLinuxFdtMaxOffset\r
+  gArmTokenSpaceGuid.PcdArmLinuxFdtAlignment\r
+  gArmTokenSpaceGuid.PcdArmLinuxKernelMaxOffset\r
+\r
+[FixedPcd.ARM]\r
+  gArmTokenSpaceGuid.PcdArmLinuxAtagMaxOffset\r
+\r
+[Pcd.AARCH64]\r
+  gArmTokenSpaceGuid.PcdGicDistributorBase\r
+  gArmTokenSpaceGuid.PcdGicSgiIntId\r
diff --git a/ArmPkg/Application/LinuxLoader/LinuxLoader.uni b/ArmPkg/Application/LinuxLoader/LinuxLoader.uni
new file mode 100644 (file)
index 0000000..861c2b4
Binary files /dev/null and b/ArmPkg/Application/LinuxLoader/LinuxLoader.uni differ
diff --git a/ArmPkg/Application/LinuxLoader/LinuxLoaderEfiApp.c b/ArmPkg/Application/LinuxLoader/LinuxLoaderEfiApp.c
new file mode 100644 (file)
index 0000000..57a9cd3
--- /dev/null
@@ -0,0 +1,303 @@
+/** @file\r
+*\r
+*  Copyright (c) 2011-2015, ARM Limited. All rights reserved.\r
+*\r
+*  This program and the accompanying materials\r
+*  are licensed and made available under the terms and conditions of the BSD License\r
+*  which accompanies this distribution.  The full text of the license may be found at\r
+*  http://opensource.org/licenses/bsd-license.php\r
+*\r
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+*\r
+**/\r
+\r
+#include "LinuxLoader.h"\r
+\r
+/**\r
+  Extract the next item from the command line.\r
+\r
+  The items are separated by spaces. Quotation marks (") are used for argument\r
+  grouping and the escaping character is "^" as for the EFI Shell command lines.\r
+\r
+  @param[in out]  CommandLine  Command line pointer.\r
+  @param[out]     Item         Pointer to the allocated buffer where the\r
+                               item is stored.\r
+\r
+  @retval  EFI_SUCCESS           The token was found and extracted.\r
+  @retval  EFI_NOT_FOUND         No item found.\r
+  @retval  EFI_OUT_OF_RESOURCES  The memory allocation failed.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+ExtractNextItem (\r
+  IN OUT CONST CHAR16  **CommandLine,\r
+  OUT CHAR16           **Item\r
+  )\r
+{\r
+  CONST CHAR16  *Walker;\r
+  VOID          *Buffer;\r
+  CHAR16        *WritePtr;\r
+  BOOLEAN       InQuotedString;\r
+  BOOLEAN       Interpret;\r
+\r
+  for (Walker = *CommandLine; *Walker == L' '; Walker++) {\r
+    ;\r
+  }\r
+\r
+  Buffer = AllocatePool (StrSize (Walker));\r
+  if (Buffer == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  for (WritePtr = Buffer, Interpret = TRUE, InQuotedString = FALSE;\r
+       ((*Walker != L' ') || InQuotedString) && (*Walker != L'\0');\r
+       Walker++\r
+       ) {\r
+    if (Interpret) {\r
+      if (*Walker == L'^') {\r
+        Interpret = FALSE;\r
+        continue;\r
+      }\r
+      if (*Walker == L'"') {\r
+        InQuotedString = !InQuotedString;\r
+        continue;\r
+      }\r
+    } else {\r
+      Interpret = TRUE;\r
+    }\r
+    *(WritePtr++) = *Walker;\r
+  }\r
+\r
+  if (WritePtr == Buffer) {\r
+    FreePool (Buffer);\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  *WritePtr = L'\0';\r
+  *CommandLine = Walker;\r
+  *Item        = Buffer;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Check if an item of the command line is a flag or not.\r
+\r
+  @param[in]  Item  Command line item.\r
+\r
+  @retval  TRUE   The item is a flag.\r
+  @retval  FALSE  The item is not a flag.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+IsFlag (\r
+  IN CONST CHAR16 *Item\r
+  )\r
+{\r
+  return ((Item[0] == L'-') && (Item[2] == L'\0'));\r
+}\r
+\r
+/**\r
+  Process the application command line.\r
+\r
+  @param[out]  KernelTextDevicePath  A pointer to the buffer where the device\r
+                                     path to the Linux kernel is stored. The\r
+                                     address of the buffer is NULL in case of\r
+                                     an error. Otherwise, the returned address\r
+                                     is the address of a buffer allocated with\r
+                                     a call to AllocatePool() that has to be\r
+                                     freed by the caller.\r
+  @param[out]  FdtTextDevicePath     A pointer to the buffer where the device\r
+                                     path to the FDT is stored. The address of\r
+                                     the buffer is NULL in case of an error or\r
+                                     if the device path to the FDT is not\r
+                                     defined. Otherwise, the returned address\r
+                                     is the address of a buffer allocated with\r
+                                     a call to AllocatePool() that has to be\r
+                                     freed by the caller.\r
+  @param[out]  InitrdTextDevicePath  A pointer to the buffer where the device\r
+                                     path to the RAM root file system is stored.\r
+                                     The address of the buffer is NULL in case\r
+                                     of an error or if the device path to the\r
+                                     RAM root file system is not defined.\r
+                                     Otherwise, the returned address is the\r
+                                     address of a buffer allocated with a call\r
+                                     to AllocatePool() that has to be freed by\r
+                                     the caller.\r
+  @param[out]  LinuxCommandLine      A pointer to the buffer where the Linux\r
+                                     kernel command line is stored. The address\r
+                                     of the buffer is NULL in case of an error\r
+                                     or if the Linux command line is not\r
+                                     defined. Otherwise, the returned address\r
+                                     is the address of a buffer allocated with\r
+                                     a call to AllocatePool() that has to be\r
+                                     freed by the caller.\r
+\r
+  @param[out]  AtagMachineType       Value of the ARM Machine Type\r
+\r
+  @retval  EFI_SUCCESS            The processing was successfull.\r
+  @retval  EFI_NOT_FOUND          EFI_LOADED_IMAGE_PROTOCOL not found.\r
+  @retval  EFI_NOT_FOUND          Path to the Linux kernel not found.\r
+  @retval  EFI_INVALID_PARAMETER  At least one parameter is not valid or there is a\r
+                                  conflict between two parameters.\r
+  @retval  EFI_OUT_OF_RESOURCES   A memory allocation failed.\r
+\r
+**/\r
+EFI_STATUS\r
+ProcessAppCommandLine (\r
+  OUT  CHAR16   **KernelTextDevicePath,\r
+  OUT  CHAR16   **FdtTextDevicePath,\r
+  OUT  CHAR16   **InitrdTextDevicePath,\r
+  OUT  CHAR16   **LinuxCommandLine,\r
+  OUT  UINTN    *AtagMachineType\r
+  )\r
+{\r
+  EFI_STATUS                 Status;\r
+  EFI_STATUS                 Status2;\r
+  EFI_LOADED_IMAGE_PROTOCOL  *LoadedImage;\r
+  CONST CHAR16               *Walker;\r
+  CHAR16                     *Item;\r
+  CHAR16                     Flag;\r
+  BOOLEAN                    HasAtagSupport;\r
+  BOOLEAN                    HasFdtSupport;\r
+\r
+  *KernelTextDevicePath = NULL;\r
+  *FdtTextDevicePath    = NULL;\r
+  *InitrdTextDevicePath = NULL;\r
+  *LinuxCommandLine     = NULL;\r
+  *AtagMachineType      = ARM_FDT_MACHINE_TYPE;\r
+\r
+  HasAtagSupport        = FALSE;\r
+  HasFdtSupport         = FALSE;\r
+\r
+  Status = gBS->HandleProtocol (\r
+                  gImageHandle,\r
+                  &gEfiLoadedImageProtocolGuid,\r
+                  (VOID**)&LoadedImage\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    ASSERT_EFI_ERROR (Status);\r
+    return Status;\r
+  }\r
+\r
+  Walker = (CHAR16*)LoadedImage->LoadOptions;\r
+  if (Walker == NULL) {\r
+    PrintHelp (NULL);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Get the device path to the Linux kernel.\r
+  //\r
+\r
+  Status = ExtractNextItem (&Walker, &Item);\r
+  if (!EFI_ERROR (Status)) {\r
+    if (!IsFlag (Item)) {\r
+      *KernelTextDevicePath = Item;\r
+    } else {\r
+      PrintHii (NULL, STRING_TOKEN (STR_MISSING_KERNEL_PATH));\r
+      FreePool (Item);\r
+      return EFI_NOT_FOUND;\r
+    }\r
+  } else {\r
+    if (Status != EFI_NOT_FOUND) {\r
+      return Status;\r
+    }\r
+    PrintHelp (NULL);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = EFI_INVALID_PARAMETER;\r
+  while (*Walker != L'\0') {\r
+    Status2 = ExtractNextItem (&Walker, &Item);\r
+    if (Status2 == EFI_NOT_FOUND) {\r
+      break;\r
+    }\r
+    if (EFI_ERROR (Status2)) {\r
+      Status = Status2;\r
+      goto Error;\r
+    }\r
+\r
+    if (!IsFlag (Item)) {\r
+      PrintHii (NULL, STRING_TOKEN (STR_INVALID_FLAG), Item[0], Item[1]);\r
+      FreePool (Item);\r
+      goto Error;\r
+    }\r
+    Flag = Item[1];\r
+    FreePool (Item);\r
+\r
+    Status2 = ExtractNextItem (&Walker, &Item);\r
+    if (Status2 == EFI_NOT_FOUND) {\r
+      PrintHii (NULL, STRING_TOKEN (STR_MISSING_VALUE), Flag);\r
+      goto Error;\r
+    }\r
+    if (EFI_ERROR (Status2)) {\r
+      Status = Status2;\r
+      goto Error;\r
+    }\r
+    if (IsFlag (Item)) {\r
+      PrintHii (NULL, STRING_TOKEN (STR_MISSING_VALUE), Flag);\r
+      FreePool (Item);\r
+      goto Error;\r
+    }\r
+\r
+    switch (Flag) {\r
+    case  L'a':\r
+      if (HasFdtSupport) {\r
+        PrintHii (NULL, STRING_TOKEN (STR_ATAG_FDT_CONFLICT));\r
+        goto Error;\r
+      }\r
+      *AtagMachineType = StrDecimalToUintn (Item);\r
+      HasAtagSupport = TRUE;\r
+      break;\r
+    case L'd':\r
+      *FdtTextDevicePath = Item;\r
+      if (HasAtagSupport) {\r
+        PrintHii (NULL, STRING_TOKEN (STR_ATAG_FDT_CONFLICT));\r
+        goto Error;\r
+      }\r
+      HasFdtSupport = TRUE;\r
+      break;\r
+\r
+    case L'c':\r
+      *LinuxCommandLine = Item;\r
+      break;\r
+\r
+    case L'f':\r
+      *InitrdTextDevicePath = Item;\r
+      break;\r
+\r
+    default:\r
+      PrintHii (NULL, STRING_TOKEN (STR_INVALID_FLAG), L'-', Flag);\r
+      FreePool (Item);\r
+      goto Error;\r
+    }\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+Error:\r
+  if (EFI_ERROR (Status)) {\r
+    if (*KernelTextDevicePath != NULL) {\r
+      FreePool (*KernelTextDevicePath);\r
+      *KernelTextDevicePath = NULL;\r
+    }\r
+    if (*FdtTextDevicePath != NULL) {\r
+      FreePool (*FdtTextDevicePath);\r
+      *FdtTextDevicePath = NULL;\r
+    }\r
+    if (*InitrdTextDevicePath != NULL) {\r
+      FreePool (*InitrdTextDevicePath);\r
+      *InitrdTextDevicePath = NULL;\r
+    }\r
+    if (*LinuxCommandLine != NULL) {\r
+      FreePool (*LinuxCommandLine);\r
+      *LinuxCommandLine = NULL;\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
diff --git a/ArmPkg/Application/LinuxLoader/LinuxLoaderFdt.c b/ArmPkg/Application/LinuxLoader/LinuxLoaderFdt.c
new file mode 100644 (file)
index 0000000..0f53784
--- /dev/null
@@ -0,0 +1,411 @@
+/** @file\r
+*\r
+*  Copyright (c) 2011-2015, ARM Limited. All rights reserved.\r
+*\r
+*  This program and the accompanying materials\r
+*  are licensed and made available under the terms and conditions of the BSD License\r
+*  which accompanies this distribution.  The full text of the license may be found at\r
+*  http://opensource.org/licenses/bsd-license.php\r
+*\r
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+*\r
+**/\r
+\r
+#include <PiDxe.h>\r
+#include <Library/ArmLib.h>\r
+#include <Library/HobLib.h>\r
+\r
+#include <Guid/ArmMpCoreInfo.h>\r
+\r
+#include "LinuxLoader.h"\r
+\r
+#define ALIGN(x, a)     (((x) + ((a) - 1)) & ~((a) - 1))\r
+#define PALIGN(p, a)    ((void *)(ALIGN ((unsigned long)(p), (a))))\r
+#define GET_CELL(p)     (p += 4, *((const UINT32 *)(p-4)))\r
+\r
+STATIC\r
+UINTN\r
+cpu_to_fdtn (UINTN x) {\r
+  if (sizeof (UINTN) == sizeof (UINT32)) {\r
+    return cpu_to_fdt32 (x);\r
+  } else {\r
+    return cpu_to_fdt64 (x);\r
+  }\r
+}\r
+\r
+typedef struct {\r
+  UINTN   Base;\r
+  UINTN   Size;\r
+} FDT_REGION;\r
+\r
+STATIC\r
+BOOLEAN\r
+IsLinuxReservedRegion (\r
+  IN EFI_MEMORY_TYPE MemoryType\r
+  )\r
+{\r
+  switch (MemoryType) {\r
+  case EfiRuntimeServicesCode:\r
+  case EfiRuntimeServicesData:\r
+  case EfiUnusableMemory:\r
+  case EfiACPIReclaimMemory:\r
+  case EfiACPIMemoryNVS:\r
+  case EfiReservedMemoryType:\r
+    return TRUE;\r
+  default:\r
+    return FALSE;\r
+  }\r
+}\r
+\r
+/**\r
+** Relocate the FDT blob to a more appropriate location for the Linux kernel.\r
+** This function will allocate memory for the relocated FDT blob.\r
+**\r
+** @retval EFI_SUCCESS on success.\r
+** @retval EFI_OUT_OF_RESOURCES or EFI_INVALID_PARAMETER on failure.\r
+*/\r
+STATIC\r
+EFI_STATUS\r
+RelocateFdt (\r
+  EFI_PHYSICAL_ADDRESS   SystemMemoryBase,\r
+  EFI_PHYSICAL_ADDRESS   OriginalFdt,\r
+  UINTN                  OriginalFdtSize,\r
+  EFI_PHYSICAL_ADDRESS   *RelocatedFdt,\r
+  UINTN                  *RelocatedFdtSize,\r
+  EFI_PHYSICAL_ADDRESS   *RelocatedFdtAlloc\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  INTN                  Error;\r
+  UINT64                FdtAlignment;\r
+\r
+  *RelocatedFdtSize = OriginalFdtSize + FDT_ADDITIONAL_ENTRIES_SIZE;\r
+\r
+  // If FDT load address needs to be aligned, allocate more space.\r
+  FdtAlignment = PcdGet32 (PcdArmLinuxFdtAlignment);\r
+  if (FdtAlignment != 0) {\r
+    *RelocatedFdtSize += FdtAlignment;\r
+  }\r
+\r
+  // Try below a watermark address.\r
+  Status = EFI_NOT_FOUND;\r
+  if (PcdGet32 (PcdArmLinuxFdtMaxOffset) != 0) {\r
+    *RelocatedFdt = LINUX_FDT_MAX_OFFSET;\r
+    Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData,\r
+                    EFI_SIZE_TO_PAGES (*RelocatedFdtSize), RelocatedFdt);\r
+    if (EFI_ERROR (Status)) {\r
+      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));\r
+    }\r
+  }\r
+\r
+  // Try anywhere there is available space.\r
+  if (EFI_ERROR (Status)) {\r
+    Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData,\r
+                    EFI_SIZE_TO_PAGES (*RelocatedFdtSize), RelocatedFdt);\r
+    if (EFI_ERROR (Status)) {\r
+      ASSERT_EFI_ERROR (Status);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    } else {\r
+      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));\r
+    }\r
+  }\r
+\r
+  *RelocatedFdtAlloc = *RelocatedFdt;\r
+  if (FdtAlignment != 0) {\r
+    *RelocatedFdt = ALIGN (*RelocatedFdt, FdtAlignment);\r
+  }\r
+\r
+  // Load the Original FDT tree into the new region\r
+  Error = fdt_open_into ((VOID*)(UINTN) OriginalFdt,\r
+            (VOID*)(UINTN)(*RelocatedFdt), *RelocatedFdtSize);\r
+  if (Error) {\r
+    DEBUG ((EFI_D_ERROR, "fdt_open_into(): %a\n", fdt_strerror (Error)));\r
+    gBS->FreePages (*RelocatedFdtAlloc, EFI_SIZE_TO_PAGES (*RelocatedFdtSize));\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+PrepareFdt (\r
+  IN     EFI_PHYSICAL_ADDRESS SystemMemoryBase,\r
+  IN     CONST CHAR8*         CommandLineArguments,\r
+  IN     EFI_PHYSICAL_ADDRESS InitrdImage,\r
+  IN     UINTN                InitrdImageSize,\r
+  IN OUT EFI_PHYSICAL_ADDRESS *FdtBlobBase,\r
+  IN OUT UINTN                *FdtBlobSize\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_PHYSICAL_ADDRESS  NewFdtBlobBase;\r
+  EFI_PHYSICAL_ADDRESS  NewFdtBlobAllocation;\r
+  UINTN                 NewFdtBlobSize;\r
+  VOID*                 fdt;\r
+  INTN                  err;\r
+  INTN                  node;\r
+  INTN                  cpu_node;\r
+  INT32                 lenp;\r
+  CONST VOID*           BootArg;\r
+  CONST VOID*           Method;\r
+  EFI_PHYSICAL_ADDRESS  InitrdImageStart;\r
+  EFI_PHYSICAL_ADDRESS  InitrdImageEnd;\r
+  FDT_REGION            Region;\r
+  UINTN                 Index;\r
+  CHAR8                 Name[10];\r
+  LIST_ENTRY            ResourceList;\r
+  SYSTEM_MEMORY_RESOURCE  *Resource;\r
+  ARM_PROCESSOR_TABLE   *ArmProcessorTable;\r
+  ARM_CORE_INFO         *ArmCoreInfoTable;\r
+  UINT32                MpId;\r
+  UINT32                ClusterId;\r
+  UINT32                CoreId;\r
+  UINT64                CpuReleaseAddr;\r
+  UINTN                 MemoryMapSize;\r
+  EFI_MEMORY_DESCRIPTOR *MemoryMap;\r
+  EFI_MEMORY_DESCRIPTOR *MemoryMapPtr;\r
+  UINTN                 MapKey;\r
+  UINTN                 DescriptorSize;\r
+  UINT32                DescriptorVersion;\r
+  UINTN                 Pages;\r
+  UINTN                 OriginalFdtSize;\r
+  BOOLEAN               CpusNodeExist;\r
+  UINTN                 CoreMpId;\r
+\r
+  NewFdtBlobAllocation = 0;\r
+\r
+  //\r
+  // Sanity checks on the original FDT blob.\r
+  //\r
+  err = fdt_check_header ((VOID*)(UINTN)(*FdtBlobBase));\r
+  if (err != 0) {\r
+    Print (L"ERROR: Device Tree header not valid (err:%d)\n", err);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  // The original FDT blob might have been loaded partially.\r
+  // Check that it is not the case.\r
+  OriginalFdtSize = (UINTN)fdt_totalsize ((VOID*)(UINTN)(*FdtBlobBase));\r
+  if (OriginalFdtSize > *FdtBlobSize) {\r
+    Print (L"ERROR: Incomplete FDT. Only %d/%d bytes have been loaded.\n",\r
+           *FdtBlobSize, OriginalFdtSize);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Relocate the FDT to its final location.\r
+  //\r
+  Status = RelocateFdt (SystemMemoryBase, *FdtBlobBase, OriginalFdtSize,\r
+             &NewFdtBlobBase, &NewFdtBlobSize, &NewFdtBlobAllocation);\r
+  if (EFI_ERROR (Status)) {\r
+    goto FAIL_RELOCATE_FDT;\r
+  }\r
+\r
+  fdt = (VOID*)(UINTN)NewFdtBlobBase;\r
+\r
+  node = fdt_subnode_offset (fdt, 0, "chosen");\r
+  if (node < 0) {\r
+    // The 'chosen' node does not exist, create it\r
+    node = fdt_add_subnode (fdt, 0, "chosen");\r
+    if (node < 0) {\r
+      DEBUG ((EFI_D_ERROR, "Error on finding 'chosen' node\n"));\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto FAIL_COMPLETE_FDT;\r
+    }\r
+  }\r
+\r
+  DEBUG_CODE_BEGIN ();\r
+    BootArg = fdt_getprop (fdt, node, "bootargs", &lenp);\r
+    if (BootArg != NULL) {\r
+      DEBUG ((EFI_D_ERROR, "BootArg: %a\n", BootArg));\r
+    }\r
+  DEBUG_CODE_END ();\r
+\r
+  //\r
+  // Set Linux CmdLine\r
+  //\r
+  if ((CommandLineArguments != NULL) && (AsciiStrLen (CommandLineArguments) > 0)) {\r
+    err = fdt_setprop (fdt, node, "bootargs", CommandLineArguments, AsciiStrSize (CommandLineArguments));\r
+    if (err) {\r
+      DEBUG ((EFI_D_ERROR, "Fail to set new 'bootarg' (err:%d)\n", err));\r
+    }\r
+  }\r
+\r
+  //\r
+  // Set Linux Initrd\r
+  //\r
+  if (InitrdImageSize != 0) {\r
+    InitrdImageStart = cpu_to_fdt64 (InitrdImage);\r
+    err = fdt_setprop (fdt, node, "linux,initrd-start", &InitrdImageStart, sizeof (EFI_PHYSICAL_ADDRESS));\r
+    if (err) {\r
+      DEBUG ((EFI_D_ERROR, "Fail to set new 'linux,initrd-start' (err:%d)\n", err));\r
+    }\r
+    InitrdImageEnd = cpu_to_fdt64 (InitrdImage + InitrdImageSize);\r
+    err = fdt_setprop (fdt, node, "linux,initrd-end", &InitrdImageEnd, sizeof (EFI_PHYSICAL_ADDRESS));\r
+    if (err) {\r
+      DEBUG ((EFI_D_ERROR, "Fail to set new 'linux,initrd-start' (err:%d)\n", err));\r
+    }\r
+  }\r
+\r
+  //\r
+  // Set Physical memory setup if does not exist\r
+  //\r
+  node = fdt_subnode_offset (fdt, 0, "memory");\r
+  if (node < 0) {\r
+    // The 'memory' node does not exist, create it\r
+    node = fdt_add_subnode (fdt, 0, "memory");\r
+    if (node >= 0) {\r
+      fdt_setprop_string (fdt, node, "name", "memory");\r
+      fdt_setprop_string (fdt, node, "device_type", "memory");\r
+\r
+      GetSystemMemoryResources (&ResourceList);\r
+      Resource = (SYSTEM_MEMORY_RESOURCE*)ResourceList.ForwardLink;\r
+\r
+      Region.Base = cpu_to_fdtn ((UINTN)Resource->PhysicalStart);\r
+      Region.Size = cpu_to_fdtn ((UINTN)Resource->ResourceLength);\r
+\r
+      err = fdt_setprop (fdt, node, "reg", &Region, sizeof (Region));\r
+      if (err) {\r
+        DEBUG ((EFI_D_ERROR, "Fail to set new 'memory region' (err:%d)\n", err));\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Add the memory regions reserved by the UEFI Firmware\r
+  //\r
+\r
+  // Retrieve the UEFI Memory Map\r
+  MemoryMap = NULL;\r
+  MemoryMapSize = 0;\r
+  Status = gBS->GetMemoryMap (&MemoryMapSize, MemoryMap, &MapKey, &DescriptorSize, &DescriptorVersion);\r
+  if (Status == EFI_BUFFER_TOO_SMALL) {\r
+    // The UEFI specification advises to allocate more memory for the MemoryMap buffer between successive\r
+    // calls to GetMemoryMap(), since allocation of the new buffer may potentially increase memory map size.\r
+    Pages = EFI_SIZE_TO_PAGES (MemoryMapSize) + 1;\r
+    MemoryMap = AllocatePages (Pages);\r
+    if (MemoryMap == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto FAIL_COMPLETE_FDT;\r
+    }\r
+    Status = gBS->GetMemoryMap (&MemoryMapSize, MemoryMap, &MapKey, &DescriptorSize, &DescriptorVersion);\r
+  }\r
+\r
+  // Go through the list and add the reserved region to the Device Tree\r
+  if (!EFI_ERROR (Status)) {\r
+    MemoryMapPtr = MemoryMap;\r
+    for (Index = 0; Index < (MemoryMapSize / DescriptorSize); Index++) {\r
+      if (IsLinuxReservedRegion ((EFI_MEMORY_TYPE)MemoryMapPtr->Type)) {\r
+        DEBUG ((DEBUG_VERBOSE, "Reserved region of type %d [0x%lX, 0x%lX]\n",\r
+            MemoryMapPtr->Type,\r
+            (UINTN)MemoryMapPtr->PhysicalStart,\r
+            (UINTN)(MemoryMapPtr->PhysicalStart + MemoryMapPtr->NumberOfPages * EFI_PAGE_SIZE)));\r
+        err = fdt_add_mem_rsv (fdt, MemoryMapPtr->PhysicalStart, MemoryMapPtr->NumberOfPages * EFI_PAGE_SIZE);\r
+        if (err != 0) {\r
+          Print (L"Warning: Fail to add 'memreserve' (err:%d)\n", err);\r
+        }\r
+      }\r
+      MemoryMapPtr = (EFI_MEMORY_DESCRIPTOR*)((UINTN)MemoryMapPtr + DescriptorSize);\r
+    }\r
+  }\r
+\r
+  //\r
+  // Setup Arm Mpcore Info if it is a multi-core or multi-cluster platforms.\r
+  //\r
+  // For 'cpus' and 'cpu' device tree nodes bindings, refer to this file\r
+  // in the kernel documentation:\r
+  // Documentation/devicetree/bindings/arm/cpus.txt\r
+  //\r
+  for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {\r
+    // Check for correct GUID type\r
+    if (CompareGuid (&gArmMpCoreInfoGuid, &(gST->ConfigurationTable[Index].VendorGuid))) {\r
+      MpId = ArmReadMpidr ();\r
+      ClusterId = GET_CLUSTER_ID (MpId);\r
+      CoreId    = GET_CORE_ID (MpId);\r
+\r
+      node = fdt_subnode_offset (fdt, 0, "cpus");\r
+      if (node < 0) {\r
+        // Create the /cpus node\r
+        node = fdt_add_subnode (fdt, 0, "cpus");\r
+        fdt_setprop_string (fdt, node, "name", "cpus");\r
+        fdt_setprop_cell (fdt, node, "#address-cells", sizeof (UINTN) / 4);\r
+        fdt_setprop_cell (fdt, node, "#size-cells", 0);\r
+        CpusNodeExist = FALSE;\r
+      } else {\r
+        CpusNodeExist = TRUE;\r
+      }\r
+\r
+      // Get pointer to ARM processor table\r
+      ArmProcessorTable = (ARM_PROCESSOR_TABLE *)gST->ConfigurationTable[Index].VendorTable;\r
+      ArmCoreInfoTable = ArmProcessorTable->ArmCpus;\r
+\r
+      for (Index = 0; Index < ArmProcessorTable->NumberOfEntries; Index++) {\r
+        CoreMpId = (UINTN) GET_MPID (ArmCoreInfoTable[Index].ClusterId,\r
+                             ArmCoreInfoTable[Index].CoreId);\r
+        AsciiSPrint (Name, 10, "cpu@%x", CoreMpId);\r
+\r
+        // If the 'cpus' node did not exist then create all the 'cpu' nodes.\r
+        // In case 'cpus' node is provided in the original FDT then we do not add\r
+        // any 'cpu' node.\r
+        if (!CpusNodeExist) {\r
+          cpu_node = fdt_add_subnode (fdt, node, Name);\r
+          if (cpu_node < 0) {\r
+            DEBUG ((EFI_D_ERROR, "Error on creating '%s' node\n", Name));\r
+            Status = EFI_INVALID_PARAMETER;\r
+            goto FAIL_COMPLETE_FDT;\r
+          }\r
+\r
+          fdt_setprop_string (fdt, cpu_node, "device_type", "cpu");\r
+\r
+          CoreMpId = cpu_to_fdtn (CoreMpId);\r
+          fdt_setprop (fdt, cpu_node, "reg", &CoreMpId, sizeof (CoreMpId));\r
+        } else {\r
+          cpu_node = fdt_subnode_offset (fdt, node, Name);\r
+        }\r
+\r
+        if (cpu_node >= 0) {\r
+          Method = fdt_getprop (fdt, cpu_node, "enable-method", &lenp);\r
+          // We only care when 'enable-method' == 'spin-table'. If the enable-method is not defined\r
+          // or defined as 'psci' then we ignore its properties.\r
+          if ((Method != NULL) && (AsciiStrCmp ((CHAR8 *)Method, "spin-table") == 0)) {\r
+            // There are two cases;\r
+            //  - UEFI firmware parked the secondary cores and/or UEFI firmware is aware of the CPU\r
+            //    release addresses (PcdArmLinuxSpinTable == TRUE)\r
+            //  - the parking of the secondary cores has been managed before starting UEFI and/or UEFI\r
+            //    does not anything about the CPU release addresses - in this case we do nothing\r
+            if (FeaturePcdGet (PcdArmLinuxSpinTable)) {\r
+              CpuReleaseAddr = cpu_to_fdt64 (ArmCoreInfoTable[Index].MailboxSetAddress);\r
+              fdt_setprop (fdt, cpu_node, "cpu-release-addr", &CpuReleaseAddr, sizeof (CpuReleaseAddr));\r
+\r
+              // If it is not the primary core than the cpu should be disabled\r
+              if (((ArmCoreInfoTable[Index].ClusterId != ClusterId) || (ArmCoreInfoTable[Index].CoreId != CoreId))) {\r
+                fdt_setprop_string (fdt, cpu_node, "status", "disabled");\r
+              }\r
+            }\r
+          }\r
+        }\r
+      }\r
+      break;\r
+    }\r
+  }\r
+\r
+  // If we succeeded to generate the new Device Tree then free the old Device Tree\r
+  gBS->FreePages (*FdtBlobBase, EFI_SIZE_TO_PAGES (*FdtBlobSize));\r
+\r
+  // Update the real size of the Device Tree\r
+  fdt_pack ((VOID*)(UINTN)(NewFdtBlobBase));\r
+\r
+  *FdtBlobBase = NewFdtBlobBase;\r
+  *FdtBlobSize = (UINTN)fdt_totalsize ((VOID*)(UINTN)(NewFdtBlobBase));\r
+  return EFI_SUCCESS;\r
+\r
+FAIL_COMPLETE_FDT:\r
+  gBS->FreePages (NewFdtBlobAllocation, EFI_SIZE_TO_PAGES (NewFdtBlobSize));\r
+\r
+FAIL_RELOCATE_FDT:\r
+  *FdtBlobSize = (UINTN)fdt_totalsize ((VOID*)(UINTN)(*FdtBlobBase));\r
+  // Return success even if we failed to update the FDT blob.\r
+  // The original one is still valid.\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/ArmPkg/Application/LinuxLoader/LinuxLoaderHelper.c b/ArmPkg/Application/LinuxLoader/LinuxLoaderHelper.c
new file mode 100644 (file)
index 0000000..4d7a844
--- /dev/null
@@ -0,0 +1,192 @@
+/** @file\r
+*\r
+*  Copyright (c) 2011-2015, ARM Limited. All rights reserved.\r
+*\r
+*  This program and the accompanying materials\r
+*  are licensed and made available under the terms and conditions of the BSD License\r
+*  which accompanies this distribution.  The full text of the license may be found at\r
+*  http://opensource.org/licenses/bsd-license.php\r
+*\r
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+*\r
+**/\r
+\r
+#include <PiDxe.h>\r
+#include <Library/HobLib.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/SerialPortLib.h>\r
+\r
+#include "LinuxLoader.h"\r
+\r
+STATIC CONST CHAR8 *mTokenList[] = {\r
+  /*"SEC",*/\r
+  "PEI",\r
+  "DXE",\r
+  "BDS",\r
+  NULL\r
+};\r
+\r
+VOID\r
+PrintPerformance (\r
+  VOID\r
+  )\r
+{\r
+  UINTN       Key;\r
+  CONST VOID  *Handle;\r
+  CONST CHAR8 *Token, *Module;\r
+  UINT64      Start, Stop, TimeStamp;\r
+  UINT64      Delta, TicksPerSecond, Milliseconds;\r
+  UINTN       Index;\r
+  CHAR8       Buffer[100];\r
+  UINTN       CharCount;\r
+  BOOLEAN     CountUp;\r
+\r
+  TicksPerSecond = GetPerformanceCounterProperties (&Start, &Stop);\r
+  if (Start < Stop) {\r
+    CountUp = TRUE;\r
+  } else {\r
+    CountUp = FALSE;\r
+  }\r
+\r
+  TimeStamp = 0;\r
+  Key       = 0;\r
+  do {\r
+    Key = GetPerformanceMeasurement (Key, (CONST VOID **)&Handle, &Token, &Module, &Start, &Stop);\r
+    if (Key != 0) {\r
+      for (Index = 0; mTokenList[Index] != NULL; Index++) {\r
+        if (AsciiStriCmp (mTokenList[Index], Token) == 0) {\r
+          Delta = CountUp ? (Stop - Start) : (Start - Stop);\r
+          TimeStamp += Delta;\r
+          Milliseconds = DivU64x64Remainder (MultU64x32 (Delta, 1000), TicksPerSecond, NULL);\r
+          CharCount = AsciiSPrint (Buffer, sizeof (Buffer), "%6a %6ld ms\n", Token, Milliseconds);\r
+          SerialPortWrite ((UINT8 *) Buffer, CharCount);\r
+          break;\r
+        }\r
+      }\r
+    }\r
+  } while (Key != 0);\r
+\r
+  CharCount = AsciiSPrint (Buffer, sizeof (Buffer), "Total Time = %ld ms\n\n",\r
+      DivU64x64Remainder (MultU64x32 (TimeStamp, 1000), TicksPerSecond, NULL));\r
+  SerialPortWrite ((UINT8 *) Buffer, CharCount);\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+InsertSystemMemoryResources (\r
+  LIST_ENTRY *ResourceList,\r
+  EFI_HOB_RESOURCE_DESCRIPTOR *ResHob\r
+  )\r
+{\r
+  SYSTEM_MEMORY_RESOURCE  *NewResource;\r
+  LIST_ENTRY              *Link;\r
+  LIST_ENTRY              *NextLink;\r
+  LIST_ENTRY              AttachedResources;\r
+  SYSTEM_MEMORY_RESOURCE  *Resource;\r
+  EFI_PHYSICAL_ADDRESS    NewResourceEnd;\r
+\r
+  if (IsListEmpty (ResourceList)) {\r
+    NewResource = AllocateZeroPool (sizeof (SYSTEM_MEMORY_RESOURCE));\r
+    NewResource->PhysicalStart = ResHob->PhysicalStart;\r
+    NewResource->ResourceLength = ResHob->ResourceLength;\r
+    InsertTailList (ResourceList, &NewResource->Link);\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  InitializeListHead (&AttachedResources);\r
+\r
+  Link = ResourceList->ForwardLink;\r
+  ASSERT (Link != NULL);\r
+  while (Link != ResourceList) {\r
+    Resource = (SYSTEM_MEMORY_RESOURCE*)Link;\r
+\r
+    // Sanity Check. The resources should not overlapped.\r
+    ASSERT (!((ResHob->PhysicalStart >= Resource->PhysicalStart) && (ResHob->PhysicalStart < (Resource->PhysicalStart + Resource->ResourceLength))));\r
+    ASSERT (!((ResHob->PhysicalStart + ResHob->ResourceLength - 1 >= Resource->PhysicalStart) &&\r
+        ((ResHob->PhysicalStart + ResHob->ResourceLength - 1) < (Resource->PhysicalStart + Resource->ResourceLength))));\r
+\r
+    // The new resource is attached after this resource descriptor\r
+    if (ResHob->PhysicalStart == Resource->PhysicalStart + Resource->ResourceLength) {\r
+      Resource->ResourceLength =  Resource->ResourceLength + ResHob->ResourceLength;\r
+\r
+      NextLink = RemoveEntryList (&Resource->Link);\r
+      InsertTailList (&AttachedResources, &Resource->Link);\r
+      Link = NextLink;\r
+    }\r
+    // The new resource is attached before this resource descriptor\r
+    else if (ResHob->PhysicalStart + ResHob->ResourceLength == Resource->PhysicalStart) {\r
+      Resource->PhysicalStart = ResHob->PhysicalStart;\r
+      Resource->ResourceLength =  Resource->ResourceLength + ResHob->ResourceLength;\r
+\r
+      NextLink = RemoveEntryList (&Resource->Link);\r
+      InsertTailList (&AttachedResources, &Resource->Link);\r
+      Link = NextLink;\r
+    } else {\r
+      Link = Link->ForwardLink;\r
+    }\r
+  }\r
+\r
+  if (!IsListEmpty (&AttachedResources)) {\r
+    // See if we can merge the attached resource with other resources\r
+\r
+    NewResource = (SYSTEM_MEMORY_RESOURCE*)GetFirstNode (&AttachedResources);\r
+    Link = RemoveEntryList (&NewResource->Link);\r
+    while (!IsListEmpty (&AttachedResources)) {\r
+      // Merge resources\r
+      Resource = (SYSTEM_MEMORY_RESOURCE*)Link;\r
+\r
+      // Ensure they overlap each other\r
+      ASSERT (\r
+          ((NewResource->PhysicalStart >= Resource->PhysicalStart) && (NewResource->PhysicalStart < (Resource->PhysicalStart + Resource->ResourceLength))) ||\r
+          (((NewResource->PhysicalStart + NewResource->ResourceLength) >= Resource->PhysicalStart) && ((NewResource->PhysicalStart + NewResource->ResourceLength) < (Resource->PhysicalStart + Resource->ResourceLength)))\r
+      );\r
+\r
+      NewResourceEnd = MAX (NewResource->PhysicalStart + NewResource->ResourceLength, Resource->PhysicalStart + Resource->ResourceLength);\r
+      NewResource->PhysicalStart = MIN (NewResource->PhysicalStart, Resource->PhysicalStart);\r
+      NewResource->ResourceLength = NewResourceEnd - NewResource->PhysicalStart;\r
+\r
+      Link = RemoveEntryList (Link);\r
+    }\r
+  } else {\r
+    // None of the Resource of the list is attached to this ResHob. Create a new entry for it\r
+    NewResource = AllocateZeroPool (sizeof (SYSTEM_MEMORY_RESOURCE));\r
+    NewResource->PhysicalStart = ResHob->PhysicalStart;\r
+    NewResource->ResourceLength = ResHob->ResourceLength;\r
+  }\r
+  InsertTailList (ResourceList, &NewResource->Link);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+GetSystemMemoryResources (\r
+  IN  LIST_ENTRY *ResourceList\r
+  )\r
+{\r
+  EFI_HOB_RESOURCE_DESCRIPTOR *ResHob;\r
+\r
+  InitializeListHead (ResourceList);\r
+\r
+  // Find the first System Memory Resource Descriptor\r
+  ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);\r
+  while ((ResHob != NULL) && (ResHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY)) {\r
+    ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, (VOID *)((UINTN)ResHob + ResHob->Header.HobLength));\r
+  }\r
+\r
+  // Did not find any\r
+  if (ResHob == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  } else {\r
+    InsertSystemMemoryResources (ResourceList, ResHob);\r
+  }\r
+\r
+  ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, (VOID *)((UINTN)ResHob + ResHob->Header.HobLength));\r
+  while (ResHob != NULL) {\r
+    if (ResHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {\r
+      InsertSystemMemoryResources (ResourceList, ResHob);\r
+    }\r
+    ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, (VOID *)((UINTN)ResHob + ResHob->Header.HobLength));\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/ArmPkg/Application/LinuxLoader/LinuxLoaderShellApp.c b/ArmPkg/Application/LinuxLoader/LinuxLoaderShellApp.c
new file mode 100644 (file)
index 0000000..2245185
--- /dev/null
@@ -0,0 +1,298 @@
+/** @file\r
+*\r
+*  Copyright (c) 2011-2015, ARM Limited. All rights reserved.\r
+*\r
+*  This program and the accompanying materials\r
+*  are licensed and made available under the terms and conditions of the BSD License\r
+*  which accompanies this distribution.  The full text of the license may be found at\r
+*  http://opensource.org/licenses/bsd-license.php\r
+*\r
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+*\r
+**/\r
+\r
+#include "LinuxLoader.h"\r
+\r
+//\r
+// Internal variables\r
+//\r
+\r
+CONST EFI_GUID mLinuxLoaderHiiGuid = {\r
+                         0xd5d16edc, 0x35c5, 0x4866,\r
+                         {0xbd, 0xe5, 0x2b, 0x64, 0xa2, 0x26, 0x55, 0x6e}\r
+                         };\r
+EFI_HANDLE mLinuxLoaderHiiHandle;\r
+\r
+STATIC CONST SHELL_PARAM_ITEM ParamList[] = {\r
+  {L"-f", TypeValue},\r
+  {L"-d", TypeValue},\r
+  {L"-c", TypeValue},\r
+  {L"-a", TypeValue},\r
+  {NULL , TypeMax  }\r
+  };\r
+\r
+/**\r
+  Print a string given the "HII Id" of the format string and a list of\r
+  arguments.\r
+\r
+  @param[in] Language           The language of the string to retrieve. If\r
+                                this parameter is NULL, then the current\r
+                                platform language is used.\r
+  @param[in] HiiFormatStringId  The format string Id for getting from Hii.\r
+  @param[in] ...                The variable argument list.\r
+\r
+  @retval EFI_SUCCESS           The printing was successful.\r
+  @retval EFI_OUT_OF_RESOURCES  A memory allocation failed.\r
+\r
+**/\r
+EFI_STATUS\r
+PrintHii (\r
+  IN CONST CHAR8          *Language OPTIONAL,\r
+  IN CONST EFI_STRING_ID  HiiFormatStringId,\r
+  ...\r
+  )\r
+{\r
+  VA_LIST  Marker;\r
+  CHAR16   *HiiFormatString;\r
+  CHAR16   Buffer[MAX_MSG_LEN];\r
+\r
+  VA_START (Marker, HiiFormatStringId);\r
+\r
+  HiiFormatString = HiiGetString (mLinuxLoaderHiiHandle, HiiFormatStringId, Language);\r
+  if (HiiFormatString != NULL) {\r
+    UnicodeVSPrint (Buffer, sizeof (Buffer), HiiFormatString, Marker);\r
+    Print (L"%s", Buffer);\r
+    FreePool (HiiFormatString);\r
+  } else {\r
+    ASSERT (FALSE);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  VA_END (Marker);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Print the help.\r
+\r
+  @param[in]  Language  The language of the string to retrieve.  If this\r
+                        parameter is NULL, then the current platform\r
+                        language is used.\r
+**/\r
+VOID\r
+PrintHelp (\r
+  IN CONST CHAR8  *Language OPTIONAL\r
+  )\r
+{\r
+  CHAR16  *Help;\r
+  CHAR16  *Walker;\r
+  CHAR16  *LineEnd;\r
+\r
+  //\r
+  // Print the help line by line as it is too big to be printed at once.\r
+  //\r
+\r
+  Help = HiiGetString (mLinuxLoaderHiiHandle, STRING_TOKEN (STR_HELP), Language);\r
+  if (Help != NULL) {\r
+    Walker = Help;\r
+    while (*Walker != L'\0') {\r
+      LineEnd = StrStr (Walker, L"\r\n");\r
+      if (LineEnd != NULL) {\r
+        *LineEnd = L'\0';\r
+      }\r
+      Print (L"%s\r\n", Walker);\r
+      if (LineEnd == NULL) {\r
+        break;\r
+      }\r
+      Walker = LineEnd + 2;\r
+    }\r
+    FreePool (Help);\r
+  }\r
+\r
+}\r
+\r
+/**\r
+  Process the Shell parameters in the case the application has been called\r
+  from the EFI Shell.\r
+\r
+  @param[out]  KernelPath        A pointer to the buffer where the path\r
+                                 to the Linux kernel (EFI Shell file path\r
+                                 or device path is stored. The address of\r
+                                 the buffer is NULL in case of an error.\r
+                                 Otherwise, the returned address is the\r
+                                 address of a buffer allocated with\r
+                                 a call to AllocatePool() that has to be\r
+                                 freed by the caller.\r
+  @param[out]  FdtPath           A pointer to the buffer where the path\r
+                                 to the FDT (EFI Shell file path or\r
+                                 device path) is stored. The address of\r
+                                 the buffer is NULL in case of an error or\r
+                                 if the path to the FDT is not defined.\r
+                                 Otherwise, the returned address is the\r
+                                 address of a buffer allocated with a call\r
+                                 to AllocatePool() that has to be freed by\r
+                                 the caller.\r
+  @param[out]  InitrdPath        A pointer to the buffer where the path\r
+                                 (EFI Shell file path or device path)\r
+                                 to the RAM root file system is stored.\r
+                                 The address of the buffer is NULL in case\r
+                                 of an error or if the path to the RAM root\r
+                                 file system is not defined. Otherwise, the\r
+                                 returned address is the address of a\r
+                                 buffer allocated with a call to\r
+                                 AllocatePool() that has to be freed by\r
+                                 the caller.\r
+  @param[out]  LinuxCommandLine  A pointer to the buffer where the Linux\r
+                                 kernel command line is stored. The address\r
+                                 of the buffer is NULL in case of an error\r
+                                 or if the Linux command line is not\r
+                                 defined. Otherwise, the returned address\r
+                                 is the address of a buffer allocated with\r
+                                 a call to AllocatePool() that has to be\r
+                                 freed by the caller.\r
+  @param[out]  AtagMachineType   Value of the ARM Machine Type\r
+\r
+  @retval  EFI_SUCCESS            The processing was successfull.\r
+  @retval  EFI_ABORTED            The initialisation of the Shell Library failed.\r
+  @retval  EFI_NOT_FOUND          Path to the Linux kernel not found.\r
+  @retval  EFI_INVALID_PARAMETER  At least one parameter is not valid or there is a\r
+                                  conflict between two parameters.\r
+  @retval  EFI_OUT_OF_RESOURCES   A memory allocation failed.\r
+\r
+**/\r
+EFI_STATUS\r
+ProcessShellParameters (\r
+  OUT  CHAR16   **KernelPath,\r
+  OUT  CHAR16   **FdtPath,\r
+  OUT  CHAR16   **InitrdPath,\r
+  OUT  CHAR16   **LinuxCommandLine,\r
+  OUT  UINTN    *AtagMachineType\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  LIST_ENTRY    *CheckPackage;\r
+  CHAR16        *ProblemParam;\r
+  CONST CHAR16  *FlagValue;\r
+  CONST CHAR16  *ParameterValue;\r
+  UINTN         LinuxCommandLineLen;\r
+\r
+\r
+  *KernelPath       = NULL;\r
+  *FdtPath          = NULL;\r
+  *InitrdPath       = NULL;\r
+  *LinuxCommandLine = NULL;\r
+  *AtagMachineType  = ARM_FDT_MACHINE_TYPE;\r
+\r
+  //\r
+  // Initialise the Shell Library as we are going to use it.\r
+  // Assert that the return code is EFI_SUCCESS as it should.\r
+  // To anticipate any change is the codes returned by\r
+  // ShellInitialize(), leave in case of error.\r
+  //\r
+  Status = ShellInitialize ();\r
+  if (EFI_ERROR (Status)) {\r
+    ASSERT_EFI_ERROR (Status);\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  Status = ShellCommandLineParse (ParamList, &CheckPackage, &ProblemParam, TRUE);\r
+  if (EFI_ERROR (Status)) {\r
+    if ((Status == EFI_VOLUME_CORRUPTED) &&\r
+        (ProblemParam != NULL) ) {\r
+      PrintHii (\r
+        NULL, STRING_TOKEN (STR_SHELL_INVALID_PARAMETER), ProblemParam\r
+        );\r
+      FreePool (ProblemParam);\r
+    } else {\r
+      ASSERT (FALSE);\r
+    }\r
+    goto Error;\r
+  }\r
+\r
+  Status = EFI_INVALID_PARAMETER;\r
+  if (ShellCommandLineGetCount (CheckPackage) != 2) {\r
+    PrintHelp (NULL);\r
+    goto Error;\r
+  }\r
+\r
+  Status = EFI_OUT_OF_RESOURCES;\r
+\r
+  FlagValue = ShellCommandLineGetValue (CheckPackage, L"-a");\r
+  if (FlagValue != NULL) {\r
+    if (ShellCommandLineGetFlag (CheckPackage, L"-d")) {\r
+      PrintHii (NULL, STRING_TOKEN (STR_ATAG_FDT_CONFLICT));\r
+      goto Error;\r
+    }\r
+    *AtagMachineType = StrDecimalToUintn (FlagValue);\r
+  }\r
+\r
+  ParameterValue = ShellCommandLineGetRawValue (CheckPackage, 1);\r
+  *KernelPath = AllocateCopyPool (StrSize (ParameterValue), ParameterValue);\r
+  if (*KernelPath == NULL) {\r
+    goto Error;\r
+  }\r
+\r
+  FlagValue = ShellCommandLineGetValue (CheckPackage, L"-d");\r
+  if (FlagValue != NULL) {\r
+    *FdtPath = AllocateCopyPool (StrSize (FlagValue), FlagValue);\r
+    if (*FdtPath == NULL) {\r
+      goto Error;\r
+    }\r
+  }\r
+\r
+  FlagValue = ShellCommandLineGetValue (CheckPackage, L"-f");\r
+  if (FlagValue != NULL) {\r
+    *InitrdPath = AllocateCopyPool (StrSize (FlagValue), FlagValue);\r
+    if (*InitrdPath == NULL) {\r
+      goto Error;\r
+    }\r
+  }\r
+\r
+  FlagValue = ShellCommandLineGetValue (CheckPackage, L"-c");\r
+  if (FlagValue != NULL) {\r
+    LinuxCommandLineLen = StrLen (FlagValue);\r
+    if ((LinuxCommandLineLen != 0) &&\r
+        (FlagValue[0] == L'"'    ) &&\r
+        (FlagValue[LinuxCommandLineLen - 1] == L'"')) {\r
+      FlagValue++;\r
+      LinuxCommandLineLen -= 2;\r
+    }\r
+\r
+    *LinuxCommandLine = AllocateCopyPool (\r
+                          (LinuxCommandLineLen + 1) * sizeof (CHAR16),\r
+                          FlagValue\r
+                          );\r
+    if (*LinuxCommandLine == NULL) {\r
+      goto Error;\r
+    }\r
+    (*LinuxCommandLine)[LinuxCommandLineLen] = L'\0';\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+Error:\r
+  ShellCommandLineFreeVarList (CheckPackage);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    if (*KernelPath != NULL) {\r
+      FreePool (*KernelPath);\r
+      *KernelPath = NULL;\r
+    }\r
+    if (*FdtPath != NULL) {\r
+      FreePool (*FdtPath);\r
+      *FdtPath = NULL;\r
+    }\r
+    if (*InitrdPath != NULL) {\r
+      FreePool (*InitrdPath);\r
+      *InitrdPath = NULL;\r
+    }\r
+    if (*LinuxCommandLine != NULL) {\r
+      FreePool (*LinuxCommandLine);\r
+      *LinuxCommandLine = NULL;\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
index 6959fde22c12f3570d9f25b548eb8935da31107a..1f69799dc24b9fee7db9d2af297d48b9557f7f86 100644 (file)
   BdsLib|ArmPkg/Library/BdsLib/BdsLib.inf\r
   FdtLib|EmbeddedPkg/Library/FdtLib/FdtLib.inf\r
 \r
+  ShellLib|ShellPkg/Library/UefiShellLib/UefiShellLib.inf\r
+  FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf\r
+  SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf\r
+\r
   IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf\r
 \r
 [LibraryClasses.ARM]\r
 \r
   ArmPkg/Filesystem/SemihostFs/SemihostFs.inf\r
 \r
-  ArmPkg/Application/LinuxLoader/LinuxFdtLoader.inf\r
+  ArmPkg/Application/LinuxLoader/LinuxLoader.inf\r
 \r
 [Components.ARM]\r
   ArmPkg/Library/BaseMemoryLibVstm/BaseMemoryLibVstm.inf\r
   ArmPkg/Library/ArmLib/ArmV7/ArmV7LibSec.inf\r
   ArmPkg/Library/ArmLib/ArmV7/ArmV7LibPrePi.inf\r
 \r
-  ArmPkg/Application/LinuxLoader/LinuxAtagLoader.inf\r
-\r
 [Components.AARCH64]\r
   ArmPkg/Drivers/ArmCpuLib/ArmCortexAEMv8Lib/ArmCortexAEMv8Lib.inf\r
   ArmPkg/Drivers/ArmCpuLib/ArmCortexA5xLib/ArmCortexA5xLib.inf\r