--- /dev/null
+/** @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
--- /dev/null
+//\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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
+++ /dev/null
-/** @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
+++ /dev/null
-#/* @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
+++ /dev/null
-/** @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
+++ /dev/null
-/** @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
+++ /dev/null
-#/* @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
+++ /dev/null
-/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+#/* @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
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