summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ArmPkg/Application/LinuxLoader/LinuxAtagLoader.c103
-rw-r--r--ArmPkg/Application/LinuxLoader/LinuxAtagLoader.inf40
-rw-r--r--ArmPkg/Application/LinuxLoader/LinuxConfig.c355
-rw-r--r--ArmPkg/Application/LinuxLoader/LinuxFdtLoader.c105
-rw-r--r--ArmPkg/Application/LinuxLoader/LinuxFdtLoader.inf40
-rw-r--r--ArmPkg/Application/LinuxLoader/LinuxInternal.h49
6 files changed, 692 insertions, 0 deletions
diff --git a/ArmPkg/Application/LinuxLoader/LinuxAtagLoader.c b/ArmPkg/Application/LinuxLoader/LinuxAtagLoader.c
new file mode 100644
index 0000000000..50a4b474cf
--- /dev/null
+++ b/ArmPkg/Application/LinuxLoader/LinuxAtagLoader.c
@@ -0,0 +1,103 @@
+/** @file
+*
+* Copyright (c) 2011, ARM Limited. All rights reserved.
+*
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include "LinuxInternal.h"
+
+#include <Library/PrintLib.h>
+#include <Library/UefiApplicationEntryPoint.h>
+
+/**
+ The user Entry Point for Application. The user code starts with this function
+ as the real entry point for the application.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ LINUX_LOADER_OPTIONAL_DATA* LinuxOptionalData;
+ EFI_DEVICE_PATH* DevicePathKernel;
+ EFI_DEVICE_PATH* InitrdDevicePath;
+ CHAR16* OptionalDataInitrd;
+ CHAR8* OptionalDataArguments;
+ CHAR16* Initrd;
+
+ Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&LoadedImage);
+ ASSERT_EFI_ERROR (Status);
+
+ if (LoadedImage->LoadOptionsSize == 0) {
+ Status = LinuxLoaderConfig (LoadedImage);
+ } else {
+ // Ensure the signature is correct
+ LinuxOptionalData = (LINUX_LOADER_OPTIONAL_DATA*)LoadedImage->LoadOptions;
+ if (LinuxOptionalData->Signature != LINUX_LOADER_SIGNATURE) {
+ return EFI_UNSUPPORTED;
+ }
+
+ // Generate the File Path Node for the Linux Kernel
+ DevicePathKernel = FileDevicePath (LoadedImage->DeviceHandle, LINUX_KERNEL_NAME);
+
+ if (LinuxOptionalData->CmdLineLength > 0) {
+ OptionalDataArguments = (CHAR8*)LinuxOptionalData + sizeof(LINUX_LOADER_OPTIONAL_DATA);
+ } else {
+ OptionalDataArguments = NULL;
+ }
+
+ if (LinuxOptionalData->InitrdPathListLength > 0) {
+ if (OptionalDataArguments != NULL) {
+ OptionalDataInitrd = (CHAR16*)(OptionalDataArguments + LinuxOptionalData->CmdLineLength);
+ } else {
+ OptionalDataInitrd = (CHAR16*)LinuxOptionalData + sizeof(LINUX_LOADER_OPTIONAL_DATA);
+ }
+
+ // If pointer not aligned
+ if ((UINTN)OptionalDataInitrd & 0x1) {
+ Initrd = (CHAR16*)AllocateCopyPool (LinuxOptionalData->InitrdPathListLength, OptionalDataInitrd);
+ } else {
+ Initrd = OptionalDataInitrd;
+ }
+
+ InitrdDevicePath = FileDevicePath (LoadedImage->DeviceHandle, Initrd);
+ } else {
+ OptionalDataInitrd = NULL;
+ InitrdDevicePath = NULL;
+ Initrd = NULL;
+ }
+
+ // Load and Start the Linux Kernel (we should never return)
+ Status = BdsBootLinuxAtag (DevicePathKernel, InitrdDevicePath, OptionalDataArguments);
+
+ if ((UINTN)OptionalDataInitrd & 0x1) {
+ FreePool (Initrd);
+ }
+
+ FreePool (DevicePathKernel);
+ if (InitrdDevicePath) {
+ FreePool (InitrdDevicePath);
+ }
+ }
+
+ return Status;
+}
diff --git a/ArmPkg/Application/LinuxLoader/LinuxAtagLoader.inf b/ArmPkg/Application/LinuxLoader/LinuxAtagLoader.inf
new file mode 100644
index 0000000000..d3edb533b9
--- /dev/null
+++ b/ArmPkg/Application/LinuxLoader/LinuxAtagLoader.inf
@@ -0,0 +1,40 @@
+#/* @file
+# Copyright (c) 2011, ARM Limited. All rights reserved.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#*/
+
+[Defines]
+ INF_VERSION = 0x00010006
+ BASE_NAME = LinuxAtagLoader
+ FILE_GUID = a912f198-7f0e-4803-b908-b757b806ec83
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 0.1
+ ENTRY_POINT = UefiMain
+
+[Sources]
+ LinuxAtagLoader.c
+ LinuxConfig.c
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ BdsLib
+ DxeServicesTableLib
+ UefiLib
+ UefiApplicationEntryPoint
+
+[Protocols]
+ gEfiLoadedImageProtocolGuid
+
+ #TODO: RemoveMe
+ gEfiDevicePathToTextProtocolGuid
diff --git a/ArmPkg/Application/LinuxLoader/LinuxConfig.c b/ArmPkg/Application/LinuxLoader/LinuxConfig.c
new file mode 100644
index 0000000000..88b8500725
--- /dev/null
+++ b/ArmPkg/Application/LinuxLoader/LinuxConfig.c
@@ -0,0 +1,355 @@
+/** @file
+*
+* Copyright (c) 2011, ARM Limited. All rights reserved.
+*
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include "LinuxInternal.h"
+
+//TODO: RemoveMe
+#include <Protocol/DevicePathToText.h>
+
+#define DEFAULT_BOOT_ENTRY_DESCRIPTION L"Linux"
+#define MAX_STR_INPUT 300
+#define MAX_ASCII_INPUT 300
+
+typedef enum {
+ LINUX_LOADER_NEW = 1,
+ LINUX_LOADER_UPDATE
+} LINUX_LOADER_ACTION;
+
+STATIC
+EFI_STATUS
+EditHIInputStr (
+ IN OUT CHAR16 *CmdLine,
+ IN UINTN MaxCmdLine
+ )
+{
+ UINTN CmdLineIndex;
+ UINTN WaitIndex;
+ CHAR8 Char;
+ EFI_INPUT_KEY Key;
+ EFI_STATUS Status;
+
+ Print (CmdLine);
+
+ for (CmdLineIndex = StrLen (CmdLine); CmdLineIndex < MaxCmdLine; ) {
+ Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &WaitIndex);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+ ASSERT_EFI_ERROR (Status);
+
+ // Unicode character is valid when Scancode is NUll
+ if (Key.ScanCode == SCAN_NULL) {
+ // Scan code is NUll, hence read Unicode character
+ Char = (CHAR8)Key.UnicodeChar;
+ } else {
+ Char = CHAR_NULL;
+ }
+
+ if ((Char == CHAR_LINEFEED) || (Char == CHAR_CARRIAGE_RETURN) || (Char == 0x7f)) {
+ CmdLine[CmdLineIndex] = '\0';
+ Print (L"\n\r");
+
+ return EFI_SUCCESS;
+ } else if ((Key.UnicodeChar == L'\b') || (Key.ScanCode == SCAN_LEFT) || (Key.ScanCode == SCAN_DELETE)){
+ if (CmdLineIndex != 0) {
+ CmdLineIndex--;
+ Print (L"\b \b");
+ }
+ } else if ((Key.ScanCode == SCAN_ESC) || (Char == 0x1B) || (Char == 0x0)) {
+ return EFI_INVALID_PARAMETER;
+ } else {
+ CmdLine[CmdLineIndex++] = Key.UnicodeChar;
+ Print (L"%c", Key.UnicodeChar);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+EditHIInputAscii (
+ IN OUT CHAR8 *CmdLine,
+ IN UINTN MaxCmdLine
+ )
+{
+ CHAR16* Str;
+ EFI_STATUS Status;
+
+ Str = (CHAR16*)AllocatePool (MaxCmdLine * sizeof(CHAR16));
+ AsciiStrToUnicodeStr (CmdLine, Str);
+
+ Status = EditHIInputStr (Str, MaxCmdLine);
+
+ UnicodeStrToAsciiStr (Str, CmdLine);
+ FreePool (Str);
+
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+GetHIInputInteger (
+ OUT UINTN *Integer
+ )
+{
+ CHAR16 CmdLine[255];
+ EFI_STATUS Status;
+
+ CmdLine[0] = '\0';
+ Status = EditHIInputStr (CmdLine, 255);
+ if (!EFI_ERROR(Status)) {
+ *Integer = StrDecimalToUintn (CmdLine);
+ }
+
+ return Status;
+}
+
+#if 0
+EFI_STATUS
+GenerateDeviceDescriptionName (
+ IN EFI_HANDLE Handle,
+ IN OUT CHAR16* Description
+ )
+{
+ EFI_STATUS Status;
+ EFI_COMPONENT_NAME_PROTOCOL* ComponentName2Protocol;
+ EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;
+ EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol;
+ CHAR16* DriverName;
+ CHAR16* DevicePathTxt;
+ EFI_DEVICE_PATH* DevicePathNode;
+
+ ComponentName2Protocol = NULL;
+ Status = gBS->HandleProtocol (Handle, &gEfiComponentName2ProtocolGuid, (VOID **)&ComponentName2Protocol);
+ if (!EFI_ERROR(Status)) {
+ //TODO: Fixme. we must find the best langague
+ Status = ComponentName2Protocol->GetDriverName (ComponentName2Protocol,"en",&DriverName);
+ if (!EFI_ERROR(Status)) {
+ StrnCpy (Description,DriverName,BOOT_DEVICE_DESCRIPTION_MAX);
+ }
+ }
+
+ if (EFI_ERROR(Status)) {
+ // Use the lastest non null entry of the Device path as a description
+ Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ // Convert the last non end-type Device Path Node in text for the description
+ DevicePathNode = GetLastDevicePathNode (DevicePathProtocol);
+ Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);
+ ASSERT_EFI_ERROR(Status);
+ DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText(DevicePathNode,TRUE,TRUE);
+ StrnCpy (Description, DevicePathTxt, BOOT_DEVICE_DESCRIPTION_MAX);
+ FreePool (DevicePathTxt);
+ }
+
+ return EFI_SUCCESS;
+}
+#endif
+
+EFI_STATUS
+LinuxLoaderConfig (
+ IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage
+ )
+{
+ EFI_STATUS Status;
+ LINUX_LOADER_ACTION Choice;
+ UINTN BootOrderSize;
+ UINT16* BootOrder;
+ UINTN BootOrderCount;
+ UINTN Index;
+ CHAR16 Description[MAX_ASCII_INPUT];
+ CHAR8 CmdLine[MAX_ASCII_INPUT];
+ CHAR16 Initrd[MAX_STR_INPUT];
+ UINT16 InitrdPathListLength;
+ UINT16 CmdLineLength;
+ BDS_LOAD_OPTION* BdsLoadOption;
+ BDS_LOAD_OPTION** SupportedBdsLoadOptions;
+ UINTN SupportedBdsLoadOptionCount;
+ LINUX_LOADER_OPTIONAL_DATA* LinuxOptionalData;
+ EFI_DEVICE_PATH* DevicePathRoot;
+
+ SupportedBdsLoadOptions = NULL;
+ SupportedBdsLoadOptionCount = 0;
+
+ do {
+ Print (L"[%d] Create new Linux Boot Entry\n",LINUX_LOADER_NEW);
+ Print (L"[%d] Update Linux Boot Entry\n",LINUX_LOADER_UPDATE);
+
+ Print (L"Option: ");
+ Status = GetHIInputInteger (&Choice);
+ if (Status == EFI_INVALID_PARAMETER) {
+ Print (L"\n");
+ return Status;
+ } else if ((Choice != LINUX_LOADER_NEW) && (Choice != LINUX_LOADER_UPDATE)) {
+ Print (L"Error: the option should be either '%d' or '%d'\n",LINUX_LOADER_NEW,LINUX_LOADER_UPDATE);
+ Status = EFI_INVALID_PARAMETER;
+ }
+ } while (EFI_ERROR(Status));
+
+ if (Choice == LINUX_LOADER_UPDATE) {
+ // If no compatible entry then we just create a new entry
+ Choice = LINUX_LOADER_NEW;
+
+ // Scan the OptionalData of every entry for the correct signature
+ Status = GetEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
+ if (!EFI_ERROR(Status)) {
+ BootOrderCount = BootOrderSize / sizeof(UINT16);
+
+ // Allocate an array to handle maximum number of supported Boot Entry
+ SupportedBdsLoadOptions = (BDS_LOAD_OPTION**)AllocatePool(sizeof(BDS_LOAD_OPTION*) * BootOrderCount);
+
+ SupportedBdsLoadOptionCount = 0;
+
+ // Check if the signature is present in the list of the current Boot entries
+ for (Index = 0; Index < BootOrderCount; Index++) {
+ Status = BootOptionFromLoadOptionIndex (BootOrder[Index], &BdsLoadOption);
+ if (!EFI_ERROR(Status)) {
+ if ((BdsLoadOption->OptionalDataSize >= sizeof(UINT32)) &&
+ (*(UINT32*)BdsLoadOption->OptionalData == LINUX_LOADER_SIGNATURE)) {
+ SupportedBdsLoadOptions[SupportedBdsLoadOptionCount++] = BdsLoadOption;
+ Choice = LINUX_LOADER_UPDATE;
+ }
+ }
+ }
+ }
+ }
+
+ if (Choice == LINUX_LOADER_NEW) {
+ Description[0] = '\0';
+ CmdLine[0] = '\0';
+ Initrd[0] = '\0';
+
+ BdsLoadOption = (BDS_LOAD_OPTION*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION));
+
+ DEBUG_CODE_BEGIN();
+ CHAR16* DevicePathTxt;
+ EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;
+
+ Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);
+ ASSERT_EFI_ERROR(Status);
+ DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (LoadedImage->FilePath, TRUE, TRUE);
+
+ Print(L"EFI OS Loader: %s\n",DevicePathTxt);
+
+ FreePool(DevicePathTxt);
+ DEBUG_CODE_END();
+
+ //
+ // Fill the known fields of BdsLoadOption
+ //
+
+ BdsLoadOption->Attributes = LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_BOOT;
+
+ // Get the full Device Path for this file
+ Status = gBS->HandleProtocol (LoadedImage->DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathRoot);
+ ASSERT_EFI_ERROR(Status);
+
+ BdsLoadOption->FilePathList = AppendDevicePath (DevicePathRoot, LoadedImage->FilePath);
+ BdsLoadOption->FilePathListLength = GetDevicePathSize (BdsLoadOption->FilePathList);
+ } else {
+ if (SupportedBdsLoadOptionCount > 1) {
+ for (Index = 0; Index < SupportedBdsLoadOptionCount; Index++) {
+ Print (L"[%d] %s\n",Index + 1,SupportedBdsLoadOptions[Index]->Description);
+ }
+
+ do {
+ Print (L"Update Boot Entry: ");
+ Status = GetHIInputInteger (&Choice);
+ if (Status == EFI_INVALID_PARAMETER) {
+ Print (L"\n");
+ return Status;
+ } else if ((Choice < 1) && (Choice > SupportedBdsLoadOptionCount)) {
+ Print (L"Choose entry from 1 to %d\n",SupportedBdsLoadOptionCount);
+ Status = EFI_INVALID_PARAMETER;
+ }
+ } while (EFI_ERROR(Status));
+ BdsLoadOption = SupportedBdsLoadOptions[Choice-1];
+ }
+ StrnCpy (Description, BdsLoadOption->Description, MAX_STR_INPUT);
+
+ LinuxOptionalData = (LINUX_LOADER_OPTIONAL_DATA*)BdsLoadOption->OptionalData;
+ if (LinuxOptionalData->CmdLineLength > 0) {
+ CopyMem (CmdLine, (CHAR8*)LinuxOptionalData + sizeof(LINUX_LOADER_OPTIONAL_DATA), LinuxOptionalData->CmdLineLength);
+ } else {
+ CmdLine[0] = '\0';
+ }
+
+ if (LinuxOptionalData->InitrdPathListLength > 0) {
+ CopyMem (Initrd, (CHAR8*)LinuxOptionalData + sizeof(LINUX_LOADER_OPTIONAL_DATA) + LinuxOptionalData->CmdLineLength, LinuxOptionalData->InitrdPathListLength);
+ } else {
+ Initrd[0] = L'\0';
+ }
+ DEBUG((EFI_D_ERROR,"L\n"));
+ }
+
+ // Description
+ Print (L"Description: ");
+ Status = EditHIInputStr (Description, MAX_STR_INPUT);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ if (StrLen (Description) == 0) {
+ StrnCpy (Description, DEFAULT_BOOT_ENTRY_DESCRIPTION, MAX_STR_INPUT);
+ }
+ BdsLoadOption->Description = Description;
+
+ // CmdLine
+ Print (L"Command Line: ");
+ Status = EditHIInputAscii (CmdLine, MAX_ASCII_INPUT);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ // Initrd
+ Print (L"Initrd name: ");
+ Status = EditHIInputStr (Initrd, MAX_STR_INPUT);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ CmdLineLength = AsciiStrLen (CmdLine);
+ if (CmdLineLength > 0) {
+ CmdLineLength += sizeof(CHAR8);
+ }
+
+ InitrdPathListLength = StrLen (Initrd) * sizeof(CHAR16);
+ if (InitrdPathListLength > 0) {
+ InitrdPathListLength += sizeof(CHAR16);
+ }
+
+ BdsLoadOption->OptionalDataSize = sizeof(LINUX_LOADER_OPTIONAL_DATA) + CmdLineLength + InitrdPathListLength;
+
+ LinuxOptionalData = (LINUX_LOADER_OPTIONAL_DATA*)AllocatePool (BdsLoadOption->OptionalDataSize);
+ BdsLoadOption->OptionalData = LinuxOptionalData;
+
+ LinuxOptionalData->Signature = LINUX_LOADER_SIGNATURE;
+ LinuxOptionalData->CmdLineLength = CmdLineLength;
+ LinuxOptionalData->InitrdPathListLength = InitrdPathListLength;
+
+ if (CmdLineLength > 0) {
+ CopyMem (LinuxOptionalData + 1, CmdLine, CmdLineLength);
+ }
+ if (InitrdPathListLength > 0) {
+ CopyMem ((UINT8*)(LinuxOptionalData + 1) + CmdLineLength, Initrd, InitrdPathListLength);
+ }
+
+ // Create or Update the boot entry
+ Status = BootOptionToLoadOptionVariable (BdsLoadOption);
+
+ return Status;
+}
diff --git a/ArmPkg/Application/LinuxLoader/LinuxFdtLoader.c b/ArmPkg/Application/LinuxLoader/LinuxFdtLoader.c
new file mode 100644
index 0000000000..2e222de51b
--- /dev/null
+++ b/ArmPkg/Application/LinuxLoader/LinuxFdtLoader.c
@@ -0,0 +1,105 @@
+/** @file
+*
+* Copyright (c) 2011, ARM Limited. All rights reserved.
+*
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include "LinuxInternal.h"
+
+#include <Library/PrintLib.h>
+#include <Library/UefiApplicationEntryPoint.h>
+
+/**
+ The user Entry Point for Application. The user code starts with this function
+ as the real entry point for the application.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ LINUX_LOADER_OPTIONAL_DATA* LinuxOptionalData;
+ EFI_DEVICE_PATH* DevicePathKernel;
+ EFI_DEVICE_PATH* DevicePathFdt;
+ EFI_DEVICE_PATH* InitrdDevicePath;
+ CHAR16* OptionalDataInitrd;
+ CHAR8* OptionalDataArguments;
+ CHAR16* Initrd;
+
+ Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&LoadedImage);
+ ASSERT_EFI_ERROR (Status);
+
+ if (LoadedImage->LoadOptionsSize == 0) {
+ Status = LinuxLoaderConfig (LoadedImage);
+ } else {
+ // Ensure the signature is correct
+ LinuxOptionalData = (LINUX_LOADER_OPTIONAL_DATA*)LoadedImage->LoadOptions;
+ if (LinuxOptionalData->Signature != LINUX_LOADER_SIGNATURE) {
+ return EFI_UNSUPPORTED;
+ }
+
+ // Generate the File Path Node for the Linux Kernel & Device Tree blobl
+ DevicePathKernel = FileDevicePath (LoadedImage->DeviceHandle, LINUX_KERNEL_NAME);
+ DevicePathFdt = FileDevicePath (LoadedImage->DeviceHandle, FDT_NAME);
+
+ if (LinuxOptionalData->CmdLineLength > 0) {
+ OptionalDataArguments = (CHAR8*)LinuxOptionalData + sizeof(LINUX_LOADER_OPTIONAL_DATA);
+ } else {
+ OptionalDataArguments = NULL;
+ }
+
+ if (LinuxOptionalData->InitrdPathListLength > 0) {
+ if (OptionalDataArguments != NULL) {
+ OptionalDataInitrd = (CHAR16*)(OptionalDataArguments + LinuxOptionalData->CmdLineLength);
+ } else {
+ OptionalDataInitrd = (CHAR16*)LinuxOptionalData + sizeof(LINUX_LOADER_OPTIONAL_DATA);
+ }
+
+ // If pointer not aligned
+ if ((UINTN)OptionalDataInitrd & 0x1) {
+ Initrd = (CHAR16*)AllocateCopyPool (LinuxOptionalData->InitrdPathListLength, OptionalDataInitrd);
+ } else {
+ Initrd = OptionalDataInitrd;
+ }
+
+ InitrdDevicePath = FileDevicePath (LoadedImage->DeviceHandle, Initrd);
+ } else {
+ OptionalDataInitrd = NULL;
+ InitrdDevicePath = NULL;
+ Initrd = NULL;
+ }
+
+ // Load and Start the Linux Kernel (we should never return)
+ Status = BdsBootLinuxFdt (DevicePathKernel, InitrdDevicePath, OptionalDataArguments, DevicePathFdt);
+
+ if ((UINTN)OptionalDataInitrd & 0x1) {
+ FreePool (Initrd);
+ }
+
+ FreePool (DevicePathKernel);
+ if (InitrdDevicePath) {
+ FreePool (InitrdDevicePath);
+ }
+ }
+
+ return Status;
+}
diff --git a/ArmPkg/Application/LinuxLoader/LinuxFdtLoader.inf b/ArmPkg/Application/LinuxLoader/LinuxFdtLoader.inf
new file mode 100644
index 0000000000..76773af76b
--- /dev/null
+++ b/ArmPkg/Application/LinuxLoader/LinuxFdtLoader.inf
@@ -0,0 +1,40 @@
+#/* @file
+# Copyright (c) 2011, ARM Limited. All rights reserved.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#*/
+
+[Defines]
+ INF_VERSION = 0x00010006
+ BASE_NAME = LinuxFdtLoader
+ FILE_GUID = f536d559-459f-48fa-8bbc-43b554ecae8d
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 0.1
+ ENTRY_POINT = UefiMain
+
+[Sources]
+ LinuxFdtLoader.c
+ LinuxConfig.c
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ BdsLib
+ DxeServicesTableLib
+ UefiLib
+ UefiApplicationEntryPoint
+
+[Protocols]
+ gEfiLoadedImageProtocolGuid
+
+ #TODO: RemoveMe
+ gEfiDevicePathToTextProtocolGuid
diff --git a/ArmPkg/Application/LinuxLoader/LinuxInternal.h b/ArmPkg/Application/LinuxLoader/LinuxInternal.h
new file mode 100644
index 0000000000..e486273520
--- /dev/null
+++ b/ArmPkg/Application/LinuxLoader/LinuxInternal.h
@@ -0,0 +1,49 @@
+/** @file
+*
+* Copyright (c) 2011, ARM Limited. All rights reserved.
+*
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#ifndef __LOADER_INTERNAL_H
+#define __LOADER_INTERNAL_H
+
+#include <Uefi.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BdsLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Protocol/LoadedImage.h>
+
+#define LINUX_KERNEL_NAME L"zImage"
+#define FDT_NAME L"platform.dtb"
+
+#define LINUX_LOADER_SIGNATURE SIGNATURE_32('l', 'i', 'l', 'o')
+
+typedef struct {
+ UINT32 Signature;
+ UINT16 CmdLineLength;
+ UINT16 InitrdPathListLength;
+
+ // These following fields have variable length:
+ //CHAR8* CmdLine;
+ //CHAR16* Initrd;
+} LINUX_LOADER_OPTIONAL_DATA;
+
+EFI_STATUS
+LinuxLoaderConfig (
+ IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage
+ );
+
+#endif