/** @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 <Library/UefiApplicationEntryPoint.h>
#include <Library/BaseMemoryLib.h>
#include <Protocol/DevicePathFromText.h>
#include "LinuxLoader.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 was executed successfully.
@retval EFI_NOT_FOUND Protocol not found.
@retval EFI_NOT_FOUND Path to the Linux kernel not found.
@retval EFI_ABORTED The initialisation of the Shell Library failed.
@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
EFIAPI
LinuxLoaderEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol;
EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters;
CHAR16 *KernelPath;
CHAR16 *FdtPath;
CHAR16 *InitrdPath;
CHAR16 *KernelTextDevicePath;
CHAR16 *FdtTextDevicePath;
CHAR16 *InitrdTextDevicePath;
CHAR16 *LinuxCommandLine;
UINTN AtagMachineType;
EFI_DEVICE_PATH *KernelDevicePath;
EFI_DEVICE_PATH *FdtDevicePath;
EFI_DEVICE_PATH *InitrdDevicePath;
CHAR8 *AsciiLinuxCommandLine;
LIST_ENTRY ResourceList;
LIST_ENTRY *ResourceLink;
SYSTEM_MEMORY_RESOURCE *Resource;
EFI_PHYSICAL_ADDRESS SystemMemoryBase;
Status = gBS->LocateProtocol (
&gEfiDevicePathFromTextProtocolGuid,
NULL,
(VOID **)&EfiDevicePathFromTextProtocol
);
if (EFI_ERROR (Status)) {
return EFI_NOT_FOUND;
}
//
// Register the strings for the user interface in the HII Database.
// This shows the way to the multi-language support, even if
// only the English language is actually supported. The strings to register
// are stored in the "LinuxLoaderStrings[]" array. This array is
// built by the building process from the "*.uni" file associated to
// the present application (cf. LinuxLoader.inf). Examine the Build
// folder of the application and you will find the array defined in the
// LinuxLoaderStrDefs.h file.
//
mLinuxLoaderHiiHandle = HiiAddPackages (
&mLinuxLoaderHiiGuid,
ImageHandle,
LinuxLoaderStrings,
NULL
);
if (mLinuxLoaderHiiHandle == NULL) {
return EFI_NOT_FOUND;
}
Status = gBS->HandleProtocol (
ImageHandle,
&gEfiShellParametersProtocolGuid,
(VOID**)&ShellParameters
);
KernelDevicePath = NULL;
FdtDevicePath = NULL;
InitrdDevicePath = NULL;
AsciiLinuxCommandLine = NULL;
//
// Call the proper function to handle the command line
// depending on whether the application has been called
// from the Shell or not.
//
if (!EFI_ERROR (Status)) {
KernelTextDevicePath = NULL;
FdtTextDevicePath = NULL;
InitrdTextDevicePath = NULL;
Status = ProcessShellParameters (
&KernelPath, &FdtPath, &InitrdPath, &LinuxCommandLine, &AtagMachineType
);
if (EFI_ERROR (Status)) {
goto Error;
}
KernelDevicePath = gEfiShellProtocol->GetDevicePathFromFilePath (KernelPath);
if (KernelDevicePath != NULL) {
FreePool (KernelPath);
} else {
KernelTextDevicePath = KernelPath;
}
if (FdtPath != NULL) {
FdtDevicePath = gEfiShellProtocol->GetDevicePathFromFilePath (FdtPath);
if (FdtDevicePath != NULL) {
FreePool (FdtPath);
} else {
FdtTextDevicePath = FdtPath;
}
}
if (InitrdPath != NULL) {
InitrdDevicePath = gEfiShellProtocol->GetDevicePathFromFilePath (InitrdPath);
if (InitrdDevicePath != NULL) {
FreePool (InitrdPath);
} else {
InitrdTextDevicePath = InitrdPath;
}
}
} else {
Status = ProcessAppCommandLine (
&KernelTextDevicePath, &FdtTextDevicePath,
&InitrdTextDevicePath, &LinuxCommandLine, &AtagMachineType
);
if (EFI_ERROR (Status)) {
goto Error;
}
}
Status = EFI_INVALID_PARAMETER;
if (KernelTextDevicePath != NULL) {
KernelDevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (
KernelTextDevicePath
);
if (KernelDevicePath == NULL) {
goto Error;
}
}
if (FdtTextDevicePath != NULL) {
FdtDevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (
FdtTextDevicePath
);
if (FdtDevicePath == NULL) {
goto Error;
}
}
if (InitrdTextDevicePath != NULL) {
InitrdDevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (
InitrdTextDevicePath
);
if (InitrdDevicePath == NULL) {
goto Error;
}
}
if (LinuxCommandLine != NULL) {
AsciiLinuxCommandLine = AllocatePool ((StrLen (LinuxCommandLine) + 1) * sizeof (CHAR8));
if (AsciiLinuxCommandLine == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto Error;
}
UnicodeStrToAsciiStr (LinuxCommandLine, AsciiLinuxCommandLine);
}
//
// Find Base of System Memory - we keep the lowest physical address
//
SystemMemoryBase = ~0;
GetSystemMemoryResources (&ResourceList);
ResourceLink = ResourceList.ForwardLink;
while (ResourceLink != NULL && ResourceLink != &ResourceList) {
Resource = (SYSTEM_MEMORY_RESOURCE*)ResourceLink;
if (Resource->PhysicalStart < SystemMemoryBase) {
SystemMemoryBase = Resource->PhysicalStart;
}
ResourceLink = ResourceLink->ForwardLink;
}
if (AtagMachineType != ARM_FDT_MACHINE_TYPE) {
Status = BootLinuxAtag (SystemMemoryBase, KernelDevicePath, InitrdDevicePath, AsciiLinuxCommandLine, AtagMachineType);
} else {
Status = BootLinuxFdt (SystemMemoryBase, KernelDevicePath, InitrdDevicePath, FdtDevicePath, AsciiLinuxCommandLine);
}
Error:
if (KernelTextDevicePath != NULL) {
FreePool (KernelTextDevicePath);
}
if (FdtTextDevicePath != NULL) {
FreePool (FdtTextDevicePath);
}
if (InitrdTextDevicePath != NULL) {
FreePool (InitrdTextDevicePath);
}
if (LinuxCommandLine != NULL) {
FreePool (LinuxCommandLine);
}
if (KernelDevicePath != NULL) {
FreePool (KernelDevicePath);
}
if (FdtDevicePath != NULL) {
FreePool (FdtDevicePath);
}
if (InitrdDevicePath != NULL) {
FreePool (InitrdDevicePath);
}
if (AsciiLinuxCommandLine != NULL) {
FreePool (AsciiLinuxCommandLine);
}
if (EFI_ERROR (Status)) {
PrintHii (NULL, STRING_TOKEN (STR_ERROR), Status);
}
HiiRemovePackages (mLinuxLoaderHiiHandle);
return Status;
}