summaryrefslogtreecommitdiff
path: root/ArmPkg/Application/LinuxLoader/LinuxLoaderEfiApp.c
diff options
context:
space:
mode:
Diffstat (limited to 'ArmPkg/Application/LinuxLoader/LinuxLoaderEfiApp.c')
-rw-r--r--ArmPkg/Application/LinuxLoader/LinuxLoaderEfiApp.c303
1 files changed, 303 insertions, 0 deletions
diff --git a/ArmPkg/Application/LinuxLoader/LinuxLoaderEfiApp.c b/ArmPkg/Application/LinuxLoader/LinuxLoaderEfiApp.c
new file mode 100644
index 0000000000..57a9cd38cf
--- /dev/null
+++ b/ArmPkg/Application/LinuxLoader/LinuxLoaderEfiApp.c
@@ -0,0 +1,303 @@
+/** @file
+*
+* Copyright (c) 2011-2015, ARM Limited. All rights reserved.
+*
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include "LinuxLoader.h"
+
+/**
+ Extract the next item from the command line.
+
+ The items are separated by spaces. Quotation marks (") are used for argument
+ grouping and the escaping character is "^" as for the EFI Shell command lines.
+
+ @param[in out] CommandLine Command line pointer.
+ @param[out] Item Pointer to the allocated buffer where the
+ item is stored.
+
+ @retval EFI_SUCCESS The token was found and extracted.
+ @retval EFI_NOT_FOUND No item found.
+ @retval EFI_OUT_OF_RESOURCES The memory allocation failed.
+
+**/
+STATIC
+EFI_STATUS
+ExtractNextItem (
+ IN OUT CONST CHAR16 **CommandLine,
+ OUT CHAR16 **Item
+ )
+{
+ CONST CHAR16 *Walker;
+ VOID *Buffer;
+ CHAR16 *WritePtr;
+ BOOLEAN InQuotedString;
+ BOOLEAN Interpret;
+
+ for (Walker = *CommandLine; *Walker == L' '; Walker++) {
+ ;
+ }
+
+ Buffer = AllocatePool (StrSize (Walker));
+ if (Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ for (WritePtr = Buffer, Interpret = TRUE, InQuotedString = FALSE;
+ ((*Walker != L' ') || InQuotedString) && (*Walker != L'\0');
+ Walker++
+ ) {
+ if (Interpret) {
+ if (*Walker == L'^') {
+ Interpret = FALSE;
+ continue;
+ }
+ if (*Walker == L'"') {
+ InQuotedString = !InQuotedString;
+ continue;
+ }
+ } else {
+ Interpret = TRUE;
+ }
+ *(WritePtr++) = *Walker;
+ }
+
+ if (WritePtr == Buffer) {
+ FreePool (Buffer);
+ return EFI_NOT_FOUND;
+ }
+
+ *WritePtr = L'\0';
+ *CommandLine = Walker;
+ *Item = Buffer;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if an item of the command line is a flag or not.
+
+ @param[in] Item Command line item.
+
+ @retval TRUE The item is a flag.
+ @retval FALSE The item is not a flag.
+
+**/
+STATIC
+BOOLEAN
+IsFlag (
+ IN CONST CHAR16 *Item
+ )
+{
+ return ((Item[0] == L'-') && (Item[2] == L'\0'));
+}
+
+/**
+ Process the application command line.
+
+ @param[out] KernelTextDevicePath A pointer to the buffer where the device
+ path to the Linux kernel is stored. The
+ address of the buffer is NULL in case of
+ an error. Otherwise, the returned address
+ is the address of a buffer allocated with
+ a call to AllocatePool() that has to be
+ freed by the caller.
+ @param[out] FdtTextDevicePath A pointer to the buffer where the device
+ path to the FDT is stored. The address of
+ the buffer is NULL in case of an error or
+ if the device path to the FDT is not
+ defined. Otherwise, the returned address
+ is the address of a buffer allocated with
+ a call to AllocatePool() that has to be
+ freed by the caller.
+ @param[out] InitrdTextDevicePath A pointer to the buffer where the device
+ path to the RAM root file system is stored.
+ The address of the buffer is NULL in case
+ of an error or if the device path to the
+ RAM root file system is not defined.
+ Otherwise, the returned address is the
+ address of a buffer allocated with a call
+ to AllocatePool() that has to be freed by
+ the caller.
+ @param[out] LinuxCommandLine A pointer to the buffer where the Linux
+ kernel command line is stored. The address
+ of the buffer is NULL in case of an error
+ or if the Linux command line is not
+ defined. Otherwise, the returned address
+ is the address of a buffer allocated with
+ a call to AllocatePool() that has to be
+ freed by the caller.
+
+ @param[out] AtagMachineType Value of the ARM Machine Type
+
+ @retval EFI_SUCCESS The processing was successfull.
+ @retval EFI_NOT_FOUND EFI_LOADED_IMAGE_PROTOCOL not found.
+ @retval EFI_NOT_FOUND Path to the Linux kernel not found.
+ @retval EFI_INVALID_PARAMETER At least one parameter is not valid or there is a
+ conflict between two parameters.
+ @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
+
+**/
+EFI_STATUS
+ProcessAppCommandLine (
+ OUT CHAR16 **KernelTextDevicePath,
+ OUT CHAR16 **FdtTextDevicePath,
+ OUT CHAR16 **InitrdTextDevicePath,
+ OUT CHAR16 **LinuxCommandLine,
+ OUT UINTN *AtagMachineType
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS Status2;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ CONST CHAR16 *Walker;
+ CHAR16 *Item;
+ CHAR16 Flag;
+ BOOLEAN HasAtagSupport;
+ BOOLEAN HasFdtSupport;
+
+ *KernelTextDevicePath = NULL;
+ *FdtTextDevicePath = NULL;
+ *InitrdTextDevicePath = NULL;
+ *LinuxCommandLine = NULL;
+ *AtagMachineType = ARM_FDT_MACHINE_TYPE;
+
+ HasAtagSupport = FALSE;
+ HasFdtSupport = FALSE;
+
+ Status = gBS->HandleProtocol (
+ gImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID**)&LoadedImage
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ Walker = (CHAR16*)LoadedImage->LoadOptions;
+ if (Walker == NULL) {
+ PrintHelp (NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get the device path to the Linux kernel.
+ //
+
+ Status = ExtractNextItem (&Walker, &Item);
+ if (!EFI_ERROR (Status)) {
+ if (!IsFlag (Item)) {
+ *KernelTextDevicePath = Item;
+ } else {
+ PrintHii (NULL, STRING_TOKEN (STR_MISSING_KERNEL_PATH));
+ FreePool (Item);
+ return EFI_NOT_FOUND;
+ }
+ } else {
+ if (Status != EFI_NOT_FOUND) {
+ return Status;
+ }
+ PrintHelp (NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_INVALID_PARAMETER;
+ while (*Walker != L'\0') {
+ Status2 = ExtractNextItem (&Walker, &Item);
+ if (Status2 == EFI_NOT_FOUND) {
+ break;
+ }
+ if (EFI_ERROR (Status2)) {
+ Status = Status2;
+ goto Error;
+ }
+
+ if (!IsFlag (Item)) {
+ PrintHii (NULL, STRING_TOKEN (STR_INVALID_FLAG), Item[0], Item[1]);
+ FreePool (Item);
+ goto Error;
+ }
+ Flag = Item[1];
+ FreePool (Item);
+
+ Status2 = ExtractNextItem (&Walker, &Item);
+ if (Status2 == EFI_NOT_FOUND) {
+ PrintHii (NULL, STRING_TOKEN (STR_MISSING_VALUE), Flag);
+ goto Error;
+ }
+ if (EFI_ERROR (Status2)) {
+ Status = Status2;
+ goto Error;
+ }
+ if (IsFlag (Item)) {
+ PrintHii (NULL, STRING_TOKEN (STR_MISSING_VALUE), Flag);
+ FreePool (Item);
+ goto Error;
+ }
+
+ switch (Flag) {
+ case L'a':
+ if (HasFdtSupport) {
+ PrintHii (NULL, STRING_TOKEN (STR_ATAG_FDT_CONFLICT));
+ goto Error;
+ }
+ *AtagMachineType = StrDecimalToUintn (Item);
+ HasAtagSupport = TRUE;
+ break;
+ case L'd':
+ *FdtTextDevicePath = Item;
+ if (HasAtagSupport) {
+ PrintHii (NULL, STRING_TOKEN (STR_ATAG_FDT_CONFLICT));
+ goto Error;
+ }
+ HasFdtSupport = TRUE;
+ break;
+
+ case L'c':
+ *LinuxCommandLine = Item;
+ break;
+
+ case L'f':
+ *InitrdTextDevicePath = Item;
+ break;
+
+ default:
+ PrintHii (NULL, STRING_TOKEN (STR_INVALID_FLAG), L'-', Flag);
+ FreePool (Item);
+ goto Error;
+ }
+ }
+
+ Status = EFI_SUCCESS;
+
+Error:
+ if (EFI_ERROR (Status)) {
+ if (*KernelTextDevicePath != NULL) {
+ FreePool (*KernelTextDevicePath);
+ *KernelTextDevicePath = NULL;
+ }
+ if (*FdtTextDevicePath != NULL) {
+ FreePool (*FdtTextDevicePath);
+ *FdtTextDevicePath = NULL;
+ }
+ if (*InitrdTextDevicePath != NULL) {
+ FreePool (*InitrdTextDevicePath);
+ *InitrdTextDevicePath = NULL;
+ }
+ if (*LinuxCommandLine != NULL) {
+ FreePool (*LinuxCommandLine);
+ *LinuxCommandLine = NULL;
+ }
+ }
+
+ return Status;
+}