mirror of https://github.com/acidanthera/audk.git
195 lines
5.5 KiB
C
195 lines
5.5 KiB
C
/** @file
|
|
|
|
Copyright (c) 2013-2015, ARM Ltd. All rights reserved.<BR>
|
|
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
#include "AndroidFastbootApp.h"
|
|
|
|
#include <Protocol/DevicePath.h>
|
|
#include <Protocol/LoadedImage.h>
|
|
|
|
#include <Library/DevicePathLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include <Library/UefiLib.h>
|
|
|
|
// Device Path representing an image in memory
|
|
#pragma pack(1)
|
|
typedef struct {
|
|
MEMMAP_DEVICE_PATH Node1;
|
|
EFI_DEVICE_PATH_PROTOCOL End;
|
|
} MEMORY_DEVICE_PATH;
|
|
#pragma pack()
|
|
|
|
STATIC CONST MEMORY_DEVICE_PATH MemoryDevicePathTemplate =
|
|
{
|
|
{
|
|
{
|
|
HARDWARE_DEVICE_PATH,
|
|
HW_MEMMAP_DP,
|
|
{
|
|
(UINT8)(sizeof (MEMMAP_DEVICE_PATH)),
|
|
(UINT8)((sizeof (MEMMAP_DEVICE_PATH)) >> 8),
|
|
},
|
|
}, // Header
|
|
0, // StartingAddress (set at runtime)
|
|
0 // EndingAddress (set at runtime)
|
|
}, // Node1
|
|
{
|
|
END_DEVICE_PATH_TYPE,
|
|
END_ENTIRE_DEVICE_PATH_SUBTYPE,
|
|
{ sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
|
|
} // End
|
|
};
|
|
|
|
/**
|
|
Start an EFI Application from a Device Path
|
|
|
|
@param ParentImageHandle Handle of the calling image
|
|
@param DevicePath Location of the EFI Application
|
|
|
|
@retval EFI_SUCCESS All drivers have been connected
|
|
@retval EFI_NOT_FOUND The Linux kernel Device Path has not been found
|
|
@retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results.
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
StartEfiApplication (
|
|
IN EFI_HANDLE ParentImageHandle,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
|
|
IN UINTN LoadOptionsSize,
|
|
IN VOID *LoadOptions
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE ImageHandle;
|
|
EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
|
|
|
|
// Load the image from the device path with Boot Services function
|
|
Status = gBS->LoadImage (
|
|
TRUE,
|
|
ParentImageHandle,
|
|
DevicePath,
|
|
NULL,
|
|
0,
|
|
&ImageHandle
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created
|
|
// with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now.
|
|
// If the caller doesn't have the option to defer the execution of an image, we should
|
|
// unload image for the EFI_SECURITY_VIOLATION to avoid resource leak.
|
|
//
|
|
if (Status == EFI_SECURITY_VIOLATION) {
|
|
gBS->UnloadImage (ImageHandle);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
// Passed LoadOptions to the EFI Application
|
|
if (LoadOptionsSize != 0) {
|
|
Status = gBS->HandleProtocol (
|
|
ImageHandle,
|
|
&gEfiLoadedImageProtocolGuid,
|
|
(VOID **)&LoadedImage
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
LoadedImage->LoadOptionsSize = LoadOptionsSize;
|
|
LoadedImage->LoadOptions = LoadOptions;
|
|
}
|
|
|
|
// Before calling the image, enable the Watchdog Timer for the 5 Minute period
|
|
gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
|
|
// Start the image
|
|
Status = gBS->StartImage (ImageHandle, NULL, NULL);
|
|
// Clear the Watchdog Timer after the image returns
|
|
gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
BootAndroidBootImg (
|
|
IN UINTN BufferSize,
|
|
IN VOID *Buffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
CHAR8 KernelArgs[ANDROID_BOOTIMG_KERNEL_ARGS_SIZE];
|
|
VOID *Kernel;
|
|
UINTN KernelSize;
|
|
VOID *Ramdisk;
|
|
UINTN RamdiskSize;
|
|
MEMORY_DEVICE_PATH KernelDevicePath;
|
|
CHAR16 *LoadOptions, *NewLoadOptions;
|
|
|
|
Status = ParseAndroidBootImg (
|
|
Buffer,
|
|
&Kernel,
|
|
&KernelSize,
|
|
&Ramdisk,
|
|
&RamdiskSize,
|
|
KernelArgs
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
KernelDevicePath = MemoryDevicePathTemplate;
|
|
|
|
// Have to cast to UINTN before casting to EFI_PHYSICAL_ADDRESS in order to
|
|
// appease GCC.
|
|
KernelDevicePath.Node1.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Kernel;
|
|
KernelDevicePath.Node1.EndingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Kernel + KernelSize;
|
|
|
|
// Initialize Linux command line
|
|
LoadOptions = CatSPrint (NULL, L"%a", KernelArgs);
|
|
if (LoadOptions == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
if (RamdiskSize != 0) {
|
|
NewLoadOptions = CatSPrint (
|
|
LoadOptions,
|
|
L" initrd=0x%x,0x%x",
|
|
(UINTN)Ramdisk,
|
|
RamdiskSize
|
|
);
|
|
FreePool (LoadOptions);
|
|
if (NewLoadOptions == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
LoadOptions = NewLoadOptions;
|
|
}
|
|
|
|
Status = StartEfiApplication (
|
|
gImageHandle,
|
|
(EFI_DEVICE_PATH_PROTOCOL *)&KernelDevicePath,
|
|
StrSize (LoadOptions),
|
|
LoadOptions
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Couldn't Boot Linux: %d\n", Status));
|
|
Status = EFI_DEVICE_ERROR;
|
|
goto FreeLoadOptions;
|
|
}
|
|
|
|
// If we got here we do a confused face because BootLinuxFdt returned,
|
|
// reporting success.
|
|
DEBUG ((DEBUG_ERROR, "WARNING: BdsBootLinuxFdt returned EFI_SUCCESS.\n"));
|
|
return EFI_SUCCESS;
|
|
|
|
FreeLoadOptions:
|
|
FreePool (LoadOptions);
|
|
return Status;
|
|
}
|