| /** @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; | |
| } |