mirror of https://github.com/acidanthera/audk.git
EmbeddedPkg/AndroidFastboot: Introduce Android FastBoot Application
This application enables Android FastBoot on UEFI. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Olivier Martin <olivier.martin@arm.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15312 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
parent
ddd1436622
commit
f6755908de
|
@ -0,0 +1,90 @@
|
|||
/** @file
|
||||
|
||||
Copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>
|
||||
|
||||
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 "AndroidFastbootApp.h"
|
||||
|
||||
#define BOOT_MAGIC "ANDROID!"
|
||||
#define BOOT_MAGIC_LENGTH sizeof (BOOT_MAGIC) - 1
|
||||
|
||||
// Check Val (unsigned) is a power of 2 (has only one bit set)
|
||||
#define IS_POWER_OF_2(Val) (Val != 0 && ((Val & (Val - 1)) == 0))
|
||||
|
||||
// No documentation for this really - sizes of fields has been determined
|
||||
// empirically.
|
||||
#pragma pack(1)
|
||||
typedef struct {
|
||||
CHAR8 BootMagic[BOOT_MAGIC_LENGTH];
|
||||
UINT32 KernelSize;
|
||||
UINT32 KernelAddress;
|
||||
UINT32 RamdiskSize;
|
||||
UINT32 RamdiskAddress;
|
||||
UINT32 SecondStageBootloaderSize;
|
||||
UINT32 SecondStageBootloaderAddress;
|
||||
UINT32 KernelTaggsAddress;
|
||||
UINT32 PageSize;
|
||||
UINT32 Reserved[2];
|
||||
CHAR8 ProductName[16];
|
||||
CHAR8 KernelArgs[BOOTIMG_KERNEL_ARGS_SIZE];
|
||||
UINT32 Id[32];
|
||||
} ANDROID_BOOTIMG_HEADER;
|
||||
#pragma pack()
|
||||
|
||||
// Find the kernel and ramdisk in an Android boot.img.
|
||||
// return EFI_INVALID_PARAMTER if the boot.img is invalid (i.e. doesn't have the
|
||||
// right magic value),
|
||||
// return EFI_NOT_FOUND if there was no kernel in the boot.img.
|
||||
// Note that the Ramdisk is optional - *Ramdisk won't be touched if it isn't
|
||||
// present, but RamdiskSize will be set to 0.
|
||||
EFI_STATUS
|
||||
ParseAndroidBootImg (
|
||||
IN VOID *BootImg,
|
||||
OUT VOID **Kernel,
|
||||
OUT UINTN *KernelSize,
|
||||
OUT VOID **Ramdisk,
|
||||
OUT UINTN *RamdiskSize,
|
||||
OUT CHAR8 *KernelArgs
|
||||
)
|
||||
{
|
||||
ANDROID_BOOTIMG_HEADER *Header;
|
||||
UINT8 *BootImgBytePtr;
|
||||
|
||||
// Cast to UINT8 so we can do pointer arithmetic
|
||||
BootImgBytePtr = (UINT8 *) BootImg;
|
||||
|
||||
Header = (ANDROID_BOOTIMG_HEADER *) BootImg;
|
||||
|
||||
if (AsciiStrnCmp (Header->BootMagic, BOOT_MAGIC, BOOT_MAGIC_LENGTH) != 0) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (Header->KernelSize == 0) {
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
ASSERT (IS_POWER_OF_2 (Header->PageSize));
|
||||
|
||||
*KernelSize = Header->KernelSize;
|
||||
*Kernel = BootImgBytePtr + Header->PageSize;
|
||||
*RamdiskSize = Header->RamdiskSize;
|
||||
|
||||
if (Header->RamdiskSize != 0) {
|
||||
*Ramdisk = (VOID *) (BootImgBytePtr
|
||||
+ Header->PageSize
|
||||
+ ALIGN_VALUE (Header->KernelSize, Header->PageSize));
|
||||
}
|
||||
|
||||
AsciiStrnCpy (KernelArgs, Header->KernelArgs, BOOTIMG_KERNEL_ARGS_SIZE);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,524 @@
|
|||
/** @file
|
||||
|
||||
Copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>
|
||||
|
||||
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 "AndroidFastbootApp.h"
|
||||
|
||||
#include <Protocol/AndroidFastbootTransport.h>
|
||||
#include <Protocol/AndroidFastbootPlatform.h>
|
||||
#include <Protocol/SimpleTextOut.h>
|
||||
#include <Protocol/SimpleTextIn.h>
|
||||
|
||||
#include <Library/PcdLib.h>
|
||||
#include <Library/UefiRuntimeServicesTableLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/UefiApplicationEntryPoint.h>
|
||||
#include <Library/PrintLib.h>
|
||||
|
||||
/*
|
||||
* UEFI Application using the FASTBOOT_TRANSPORT_PROTOCOL and
|
||||
* FASTBOOT_PLATFORM_PROTOCOL to implement the Android Fastboot protocol.
|
||||
*/
|
||||
|
||||
STATIC FASTBOOT_TRANSPORT_PROTOCOL *mTransport;
|
||||
STATIC FASTBOOT_PLATFORM_PROTOCOL *mPlatform;
|
||||
|
||||
STATIC EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *mTextOut;
|
||||
|
||||
typedef enum {
|
||||
ExpectCmdState,
|
||||
ExpectDataState,
|
||||
FastbootStateMax
|
||||
} ANDROID_FASTBOOT_STATE;
|
||||
|
||||
STATIC ANDROID_FASTBOOT_STATE mState = ExpectCmdState;
|
||||
|
||||
// When in ExpectDataState, the number of bytes of data to expect:
|
||||
STATIC UINT32 mNumDataBytes;
|
||||
// .. and the number of bytes so far received this data phase
|
||||
STATIC UINT32 mBytesReceivedSoFar;
|
||||
// .. and the buffer to save data into
|
||||
STATIC UINT8 *mDataBuffer = NULL;
|
||||
|
||||
// Event notify functions, from which gBS->Exit shouldn't be called, can signal
|
||||
// this event when the application should exit
|
||||
STATIC EFI_EVENT mFinishedEvent;
|
||||
|
||||
STATIC EFI_EVENT mFatalSendErrorEvent;
|
||||
|
||||
// This macro uses sizeof - only use it on arrays (i.e. string literals)
|
||||
#define SEND_LITERAL(Str) mTransport->Send ( \
|
||||
sizeof (Str) - 1, \
|
||||
Str, \
|
||||
&mFatalSendErrorEvent \
|
||||
)
|
||||
#define MATCH_CMD_LITERAL(Cmd, Buf) !AsciiStrnCmp (Cmd, Buf, sizeof (Cmd) - 1)
|
||||
|
||||
#define IS_LOWERCASE_ASCII(Char) (Char >= 'a' && Char <= 'z')
|
||||
|
||||
#define FASTBOOT_STRING_MAX_LENGTH 256
|
||||
#define FASTBOOT_COMMAND_MAX_LENGTH 64
|
||||
|
||||
STATIC
|
||||
VOID
|
||||
HandleGetVar (
|
||||
IN CHAR8 *CmdArg
|
||||
)
|
||||
{
|
||||
CHAR8 Response[FASTBOOT_COMMAND_MAX_LENGTH + 1] = "OKAY";
|
||||
EFI_STATUS Status;
|
||||
|
||||
// Respond to getvar:version with 0.4 (version of Fastboot protocol)
|
||||
if (!AsciiStrnCmp ("version", CmdArg, sizeof ("version") - 1 )) {
|
||||
SEND_LITERAL ("OKAY" ANDROID_FASTBOOT_VERSION);
|
||||
} else {
|
||||
// All other variables are assumed to be platform specific
|
||||
Status = mPlatform->GetVar (CmdArg, Response + 4);
|
||||
if (EFI_ERROR (Status)) {
|
||||
SEND_LITERAL ("FAILSomething went wrong when looking up the variable");
|
||||
} else {
|
||||
mTransport->Send (AsciiStrLen (Response), Response, &mFatalSendErrorEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC
|
||||
VOID
|
||||
HandleDownload (
|
||||
IN CHAR8 *NumBytesString
|
||||
)
|
||||
{
|
||||
CHAR8 Response[12] = "DATA";
|
||||
CHAR16 OutputString[FASTBOOT_STRING_MAX_LENGTH];
|
||||
|
||||
// Argument is 8-character ASCII string hex representation of number of bytes
|
||||
// that will be sent in the data phase.
|
||||
// Response is "DATA" + that same 8-character string.
|
||||
|
||||
// Replace any previously downloaded data
|
||||
if (mDataBuffer != NULL) {
|
||||
FreePool (mDataBuffer);
|
||||
mDataBuffer = NULL;
|
||||
}
|
||||
|
||||
// Parse out number of data bytes to expect
|
||||
mNumDataBytes = AsciiStrHexToUint64 (NumBytesString);
|
||||
if (mNumDataBytes == 0) {
|
||||
mTextOut->OutputString (mTextOut, L"ERROR: Fail to get the number of bytes to download.\r\n");
|
||||
SEND_LITERAL ("FAILFailed to get the number of bytes to download");
|
||||
return;
|
||||
}
|
||||
|
||||
UnicodeSPrint (OutputString, sizeof (OutputString), L"Downloading %d bytes\r\n", mNumDataBytes);
|
||||
mTextOut->OutputString (mTextOut, OutputString);
|
||||
|
||||
mDataBuffer = AllocatePool (mNumDataBytes);
|
||||
if (mDataBuffer == NULL) {
|
||||
SEND_LITERAL ("FAILNot enough memory");
|
||||
} else {
|
||||
AsciiStrnCpy (Response + 4, NumBytesString, 8);
|
||||
mTransport->Send (sizeof(Response), Response, &mFatalSendErrorEvent);
|
||||
|
||||
mState = ExpectDataState;
|
||||
mBytesReceivedSoFar = 0;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC
|
||||
VOID
|
||||
HandleFlash (
|
||||
IN CHAR8 *PartitionName
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
CHAR16 OutputString[FASTBOOT_STRING_MAX_LENGTH];
|
||||
|
||||
// Build output string
|
||||
UnicodeSPrint (OutputString, sizeof (OutputString), L"Flashing partition %a\r\n", PartitionName);
|
||||
mTextOut->OutputString (mTextOut, OutputString);
|
||||
|
||||
if (mDataBuffer == NULL) {
|
||||
// Doesn't look like we were sent any data
|
||||
SEND_LITERAL ("FAILNo data to flash");
|
||||
return;
|
||||
}
|
||||
|
||||
Status = mPlatform->FlashPartition (
|
||||
PartitionName,
|
||||
mNumDataBytes,
|
||||
mDataBuffer
|
||||
);
|
||||
if (Status == EFI_NOT_FOUND) {
|
||||
SEND_LITERAL ("FAILNo such partition.");
|
||||
mTextOut->OutputString (mTextOut, L"No such partition.\r\n");
|
||||
} else if (EFI_ERROR (Status)) {
|
||||
SEND_LITERAL ("FAILError flashing partition.");
|
||||
mTextOut->OutputString (mTextOut, L"Error flashing partition.\r\n");
|
||||
DEBUG ((EFI_D_ERROR, "Couldn't flash image: %r\n", Status));
|
||||
} else {
|
||||
mTextOut->OutputString (mTextOut, L"Done.\r\n");
|
||||
SEND_LITERAL ("OKAY");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC
|
||||
VOID
|
||||
HandleErase (
|
||||
IN CHAR8 *PartitionName
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
CHAR16 OutputString[FASTBOOT_STRING_MAX_LENGTH];
|
||||
|
||||
// Build output string
|
||||
UnicodeSPrint (OutputString, sizeof (OutputString), L"Erasing partition %a\r\n", PartitionName);
|
||||
mTextOut->OutputString (mTextOut, OutputString);
|
||||
|
||||
Status = mPlatform->ErasePartition (PartitionName);
|
||||
if (EFI_ERROR (Status)) {
|
||||
SEND_LITERAL ("FAILCheck device console.");
|
||||
DEBUG ((EFI_D_ERROR, "Couldn't erase image: %r\n", Status));
|
||||
} else {
|
||||
SEND_LITERAL ("OKAY");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC
|
||||
VOID
|
||||
HandleBoot (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
mTextOut->OutputString (mTextOut, L"Booting downloaded image\r\n");
|
||||
|
||||
if (mDataBuffer == NULL) {
|
||||
// Doesn't look like we were sent any data
|
||||
SEND_LITERAL ("FAILNo image in memory");
|
||||
return;
|
||||
}
|
||||
|
||||
// We don't really have any choice but to report success, because once we
|
||||
// boot we lose control of the system.
|
||||
SEND_LITERAL ("OKAY");
|
||||
|
||||
Status = BootAndroidBootImg (mNumDataBytes, mDataBuffer);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "Failed to boot downloaded image: %r\n", Status));
|
||||
}
|
||||
// We shouldn't get here
|
||||
}
|
||||
|
||||
STATIC
|
||||
VOID
|
||||
HandleOemCommand (
|
||||
IN CHAR8 *Command
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
Status = mPlatform->DoOemCommand (Command);
|
||||
if (Status == EFI_NOT_FOUND) {
|
||||
SEND_LITERAL ("FAILOEM Command not recognised.");
|
||||
} else if (Status == EFI_DEVICE_ERROR) {
|
||||
SEND_LITERAL ("FAILError while executing command");
|
||||
} else if (EFI_ERROR (Status)) {
|
||||
SEND_LITERAL ("FAIL");
|
||||
} else {
|
||||
SEND_LITERAL ("OKAY");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC
|
||||
VOID
|
||||
AcceptCmd (
|
||||
IN UINTN Size,
|
||||
IN CONST CHAR8 *Data
|
||||
)
|
||||
{
|
||||
CHAR8 Command[FASTBOOT_COMMAND_MAX_LENGTH + 1];
|
||||
|
||||
// Max command size is 64 bytes
|
||||
if (Size > FASTBOOT_COMMAND_MAX_LENGTH) {
|
||||
SEND_LITERAL ("FAILCommand too large");
|
||||
return;
|
||||
}
|
||||
|
||||
// Commands aren't null-terminated. Let's get a null-terminated version.
|
||||
AsciiStrnCpy (Command, Data, Size);
|
||||
Command[Size] = '\0';
|
||||
|
||||
// Parse command
|
||||
if (MATCH_CMD_LITERAL ("getvar", Command)) {
|
||||
HandleGetVar (Command + sizeof ("getvar"));
|
||||
} else if (MATCH_CMD_LITERAL ("download", Command)) {
|
||||
HandleDownload (Command + sizeof ("download"));
|
||||
} else if (MATCH_CMD_LITERAL ("verify", Command)) {
|
||||
SEND_LITERAL ("FAILNot supported");
|
||||
} else if (MATCH_CMD_LITERAL ("flash", Command)) {
|
||||
HandleFlash (Command + sizeof ("flash"));
|
||||
} else if (MATCH_CMD_LITERAL ("erase", Command)) {
|
||||
HandleErase (Command + sizeof ("erase"));
|
||||
} else if (MATCH_CMD_LITERAL ("boot", Command)) {
|
||||
HandleBoot ();
|
||||
} else if (MATCH_CMD_LITERAL ("continue", Command)) {
|
||||
SEND_LITERAL ("OKAY");
|
||||
mTextOut->OutputString (mTextOut, L"Received 'continue' command. Exiting Fastboot mode\r\n");
|
||||
|
||||
gBS->SignalEvent (mFinishedEvent);
|
||||
} else if (MATCH_CMD_LITERAL ("reboot", Command)) {
|
||||
if (MATCH_CMD_LITERAL ("reboot-booloader", Command)) {
|
||||
// fastboot_protocol.txt:
|
||||
// "reboot-bootloader Reboot back into the bootloader."
|
||||
// I guess this means reboot back into fastboot mode to save the user
|
||||
// having to do whatever they did to get here again.
|
||||
// Here we just reboot normally.
|
||||
SEND_LITERAL ("INFOreboot-bootloader not supported, rebooting normally.");
|
||||
}
|
||||
SEND_LITERAL ("OKAY");
|
||||
gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
|
||||
|
||||
// Shouldn't get here
|
||||
DEBUG ((EFI_D_ERROR, "Fastboot: gRT->ResetSystem didn't work\n"));
|
||||
} else if (MATCH_CMD_LITERAL ("powerdown", Command)) {
|
||||
SEND_LITERAL ("OKAY");
|
||||
gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL);
|
||||
|
||||
// Shouldn't get here
|
||||
DEBUG ((EFI_D_ERROR, "Fastboot: gRT->ResetSystem didn't work\n"));
|
||||
} else if (MATCH_CMD_LITERAL ("oem", Command)) {
|
||||
// The "oem" command isn't in the specification, but it was observed in the
|
||||
// wild, followed by a space, followed by the actual command.
|
||||
HandleOemCommand (Command + sizeof ("oem"));
|
||||
} else if (IS_LOWERCASE_ASCII (Command[0])) {
|
||||
// Commands starting with lowercase ASCII characters are reserved for the
|
||||
// Fastboot protocol. If we don't recognise it, it's probably the future
|
||||
// and there are new commmands in the protocol.
|
||||
// (By the way, the "oem" command mentioned above makes this reservation
|
||||
// redundant, but we handle it here to be spec-compliant)
|
||||
SEND_LITERAL ("FAILCommand not recognised. Check Fastboot version.");
|
||||
} else {
|
||||
HandleOemCommand (Command);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC
|
||||
VOID
|
||||
AcceptData (
|
||||
IN UINTN Size,
|
||||
IN VOID *Data
|
||||
)
|
||||
{
|
||||
UINT32 RemainingBytes = mNumDataBytes - mBytesReceivedSoFar;
|
||||
CHAR16 OutputString[FASTBOOT_STRING_MAX_LENGTH];
|
||||
STATIC UINTN Count = 0;
|
||||
|
||||
// Protocol doesn't say anything about sending extra data so just ignore it.
|
||||
if (Size > RemainingBytes) {
|
||||
Size = RemainingBytes;
|
||||
}
|
||||
|
||||
CopyMem (&mDataBuffer[mBytesReceivedSoFar], Data, Size);
|
||||
|
||||
mBytesReceivedSoFar += Size;
|
||||
|
||||
// Show download progress. Don't do it for every packet as outputting text
|
||||
// might be time consuming - do it on the last packet and on every 32nd packet
|
||||
if ((Count++ % 32) == 0 || Size == RemainingBytes) {
|
||||
// (Note no newline in format string - it will overwrite the line each time)
|
||||
UnicodeSPrint (
|
||||
OutputString,
|
||||
sizeof (OutputString),
|
||||
L"\r%8d / %8d bytes downloaded (%d%%)",
|
||||
mBytesReceivedSoFar,
|
||||
mNumDataBytes,
|
||||
(mBytesReceivedSoFar * 100) / mNumDataBytes // percentage
|
||||
);
|
||||
mTextOut->OutputString (mTextOut, OutputString);
|
||||
}
|
||||
|
||||
if (mBytesReceivedSoFar == mNumDataBytes) {
|
||||
// Download finished.
|
||||
|
||||
mTextOut->OutputString (mTextOut, L"\r\n");
|
||||
SEND_LITERAL ("OKAY");
|
||||
mState = ExpectCmdState;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
This is the NotifyFunction passed to CreateEvent in the FastbootAppEntryPoint
|
||||
It will be called by the UEFI event framework when the transport protocol
|
||||
implementation signals that data has been received from the Fastboot host.
|
||||
The parameters are ignored.
|
||||
*/
|
||||
STATIC
|
||||
VOID
|
||||
DataReady (
|
||||
IN EFI_EVENT Event,
|
||||
IN VOID *Context
|
||||
)
|
||||
{
|
||||
UINTN Size;
|
||||
VOID *Data;
|
||||
EFI_STATUS Status;
|
||||
|
||||
do {
|
||||
Status = mTransport->Receive (&Size, &Data);
|
||||
if (!EFI_ERROR (Status)) {
|
||||
if (mState == ExpectCmdState) {
|
||||
AcceptCmd (Size, (CHAR8 *) Data);
|
||||
} else if (mState == ExpectDataState) {
|
||||
AcceptData (Size, Data);
|
||||
} else {
|
||||
ASSERT (FALSE);
|
||||
}
|
||||
FreePool (Data);
|
||||
}
|
||||
} while (!EFI_ERROR (Status));
|
||||
|
||||
// Quit if there was a fatal error
|
||||
if (Status != EFI_NOT_READY) {
|
||||
ASSERT (Status == EFI_DEVICE_ERROR);
|
||||
// (Put a newline at the beginning as we are probably in the data phase,
|
||||
// so the download progress line, with no '\n' is probably on the console)
|
||||
mTextOut->OutputString (mTextOut, L"\r\nFatal error receiving data. Exiting.\r\n");
|
||||
gBS->SignalEvent (mFinishedEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Event notify for a fatal error in transmission.
|
||||
*/
|
||||
STATIC
|
||||
VOID
|
||||
FatalErrorNotify (
|
||||
IN EFI_EVENT Event,
|
||||
IN VOID *Context
|
||||
)
|
||||
{
|
||||
mTextOut->OutputString (mTextOut, L"Fatal error sending command response. Exiting.\r\n");
|
||||
gBS->SignalEvent (mFinishedEvent);
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
FastbootAppEntryPoint (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_EVENT ReceiveEvent;
|
||||
EFI_EVENT WaitEventArray[2];
|
||||
UINTN EventIndex;
|
||||
EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn;
|
||||
|
||||
mDataBuffer = NULL;
|
||||
|
||||
Status = gBS->LocateProtocol (
|
||||
&gAndroidFastbootTransportProtocolGuid,
|
||||
NULL,
|
||||
(VOID **) &mTransport
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "Fastboot: Couldn't open Fastboot Transport Protocol: %r\n", Status));
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = gBS->LocateProtocol (&gAndroidFastbootPlatformProtocolGuid, NULL, (VOID **) &mPlatform);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "Fastboot: Couldn't open Fastboot Platform Protocol: %r\n", Status));
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = mPlatform->Init ();
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "Fastboot: Couldn't initialise Fastboot Platform Protocol: %r\n", Status));
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = gBS->LocateProtocol (&gEfiSimpleTextOutProtocolGuid, NULL, (VOID **) &mTextOut);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR,
|
||||
"Fastboot: Couldn't open Text Output Protocol: %r\n", Status
|
||||
));
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = gBS->LocateProtocol (&gEfiSimpleTextInProtocolGuid, NULL, (VOID **) &TextIn);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "Fastboot: Couldn't open Text Input Protocol: %r\n", Status));
|
||||
return Status;
|
||||
}
|
||||
|
||||
// Disable watchdog
|
||||
Status = gBS->SetWatchdogTimer (0, 0x10000, 0, NULL);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "Fastboot: Couldn't disable watchdog timer: %r\n", Status));
|
||||
}
|
||||
|
||||
// Create event for receipt of data from the host
|
||||
Status = gBS->CreateEvent (
|
||||
EVT_NOTIFY_SIGNAL,
|
||||
TPL_CALLBACK,
|
||||
DataReady,
|
||||
NULL,
|
||||
&ReceiveEvent
|
||||
);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
// Create event for exiting application when "continue" command is received
|
||||
Status = gBS->CreateEvent (0, TPL_CALLBACK, NULL, NULL, &mFinishedEvent);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
// Create event to pass to FASTBOOT_TRANSPORT_PROTOCOL.Send, signalling a
|
||||
// fatal error
|
||||
Status = gBS->CreateEvent (
|
||||
EVT_NOTIFY_SIGNAL,
|
||||
TPL_CALLBACK,
|
||||
FatalErrorNotify,
|
||||
NULL,
|
||||
&mFatalSendErrorEvent
|
||||
);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
|
||||
// Start listening for data
|
||||
Status = mTransport->Start (
|
||||
ReceiveEvent
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "Fastboot: Couldn't start transport: %r\n", Status));
|
||||
return Status;
|
||||
}
|
||||
|
||||
// Talk to the user
|
||||
mTextOut->OutputString (mTextOut,
|
||||
L"Android Fastboot mode - version " ANDROID_FASTBOOT_VERSION ". Press any key to quit.\r\n");
|
||||
|
||||
// Quit when the user presses any key, or mFinishedEvent is signalled
|
||||
WaitEventArray[0] = mFinishedEvent;
|
||||
WaitEventArray[1] = TextIn->WaitForKey;
|
||||
gBS->WaitForEvent (2, WaitEventArray, &EventIndex);
|
||||
|
||||
mTransport->Stop ();
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "Warning: Fastboot Transport Stop: %r\n", Status));
|
||||
}
|
||||
mPlatform->UnInit ();
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/** @file
|
||||
|
||||
Copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>
|
||||
|
||||
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 __ANDROID_FASTBOOT_APP_H__
|
||||
#define __ANDROID_FASTBOOT_APP_H__
|
||||
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
|
||||
#define BOOTIMG_KERNEL_ARGS_SIZE 512
|
||||
|
||||
#define ANDROID_FASTBOOT_VERSION "0.4"
|
||||
|
||||
EFI_STATUS
|
||||
BootAndroidBootImg (
|
||||
IN UINTN BufferSize,
|
||||
IN VOID *Buffer
|
||||
);
|
||||
|
||||
EFI_STATUS
|
||||
ParseAndroidBootImg (
|
||||
IN VOID *BootImg,
|
||||
OUT VOID **Kernel,
|
||||
OUT UINTN *KernelSize,
|
||||
OUT VOID **Ramdisk,
|
||||
OUT UINTN *RamdiskSize,
|
||||
OUT CHAR8 *KernelArgs
|
||||
);
|
||||
|
||||
#endif //ifdef __ANDROID_FASTBOOT_APP_H__
|
|
@ -0,0 +1,60 @@
|
|||
#/** @file
|
||||
#
|
||||
# Copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>
|
||||
#
|
||||
# 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 = 0x00010005
|
||||
BASE_NAME = AndroidFastbootApp
|
||||
FILE_GUID = 9588502a-5370-11e3-8631-d7c5951364c8
|
||||
MODULE_TYPE = UEFI_APPLICATION
|
||||
VERSION_STRING = 1.0
|
||||
ENTRY_POINT = FastbootAppEntryPoint
|
||||
|
||||
[Sources.common]
|
||||
AndroidFastbootApp.c
|
||||
AndroidBootImg.c
|
||||
|
||||
[Sources.ARM, Sources.AARCH64]
|
||||
Arm/BootAndroidBootImg.c
|
||||
|
||||
[LibraryClasses]
|
||||
BaseLib
|
||||
BaseMemoryLib
|
||||
BdsLib
|
||||
DebugLib
|
||||
DevicePathLib
|
||||
DxeServicesTableLib
|
||||
MemoryAllocationLib
|
||||
PcdLib
|
||||
PrintLib
|
||||
UefiApplicationEntryPoint
|
||||
UefiBootServicesTableLib
|
||||
UefiRuntimeServicesTableLib
|
||||
|
||||
[Protocols]
|
||||
gAndroidFastbootTransportProtocolGuid
|
||||
gAndroidFastbootPlatformProtocolGuid
|
||||
gEfiSimpleTextOutProtocolGuid
|
||||
gEfiSimpleTextInProtocolGuid
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
EmbeddedPkg/EmbeddedPkg.dec
|
||||
|
||||
[Packages.ARM, Packages.AARCH64]
|
||||
ArmPkg/ArmPkg.dec
|
||||
ArmPlatformPkg/ArmPlatformPkg.dec
|
||||
|
||||
[Guids.ARM, Guids.AARCH64]
|
||||
gArmGlobalVariableGuid
|
|
@ -0,0 +1,125 @@
|
|||
/** @file
|
||||
|
||||
Copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>
|
||||
|
||||
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 "AndroidFastbootApp.h"
|
||||
|
||||
#include <Protocol/DevicePath.h>
|
||||
|
||||
#include <Library/BdsLib.h>
|
||||
#include <Library/DevicePathLib.h>
|
||||
|
||||
#include <Guid/ArmGlobalVariableHob.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
|
||||
};
|
||||
|
||||
EFI_STATUS
|
||||
BootAndroidBootImg (
|
||||
IN UINTN BufferSize,
|
||||
IN VOID *Buffer
|
||||
)
|
||||
{
|
||||
EFI_DEVICE_PATH_PROTOCOL *FdtDevicePath;
|
||||
EFI_STATUS Status;
|
||||
CHAR8 KernelArgs[BOOTIMG_KERNEL_ARGS_SIZE];
|
||||
VOID *Kernel;
|
||||
UINTN KernelSize;
|
||||
VOID *Ramdisk;
|
||||
UINTN RamdiskSize;
|
||||
MEMORY_DEVICE_PATH KernelDevicePath;
|
||||
MEMORY_DEVICE_PATH* RamdiskDevicePath;
|
||||
|
||||
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;
|
||||
|
||||
RamdiskDevicePath = NULL;
|
||||
if (RamdiskSize != 0) {
|
||||
RamdiskDevicePath = (MEMORY_DEVICE_PATH*)DuplicateDevicePath ((EFI_DEVICE_PATH_PROTOCOL*) &MemoryDevicePathTemplate);
|
||||
|
||||
RamdiskDevicePath->Node1.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Ramdisk;
|
||||
RamdiskDevicePath->Node1.EndingAddress = ((EFI_PHYSICAL_ADDRESS)(UINTN) Ramdisk) + RamdiskSize;
|
||||
}
|
||||
|
||||
// Get the default FDT device path
|
||||
Status = GetEnvironmentVariable ((CHAR16 *)L"Fdt", &gArmGlobalVariableGuid,
|
||||
NULL, 0, (VOID **)&FdtDevicePath);
|
||||
if (Status == EFI_NOT_FOUND) {
|
||||
DEBUG ((EFI_D_ERROR, "Error: Please update FDT path in boot manager\n"));
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
Status = BdsBootLinuxFdt (
|
||||
(EFI_DEVICE_PATH_PROTOCOL *) &KernelDevicePath,
|
||||
(EFI_DEVICE_PATH_PROTOCOL *) RamdiskDevicePath,
|
||||
KernelArgs,
|
||||
FdtDevicePath
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "Couldn't Boot Linux: %d\n", Status));
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
if (RamdiskDevicePath) {
|
||||
FreePool (RamdiskDevicePath);
|
||||
}
|
||||
|
||||
// If we got here we do a confused face because BootLinuxFdt returned,
|
||||
// reporting success.
|
||||
DEBUG ((EFI_D_ERROR, "WARNING: BdsBootLinuxFdt returned EFI_SUCCESS.\n"));
|
||||
return EFI_SUCCESS;
|
||||
}
|
|
@ -93,12 +93,12 @@
|
|||
UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
|
||||
UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf
|
||||
|
||||
|
||||
PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
|
||||
EblCmdLib|EmbeddedPkg/Library/EblCmdLibNull/EblCmdLibNull.inf
|
||||
|
||||
EblNetworkLib|EmbeddedPkg/Library/EblNetworkLib/EblNetworkLib.inf
|
||||
|
||||
|
||||
FdtLib|EmbeddedPkg/Library/FdtLib/FdtLib.inf
|
||||
|
||||
[LibraryClasses.common.DXE_DRIVER]
|
||||
PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
|
||||
|
@ -117,9 +117,18 @@
|
|||
ExtractGuidedSectionLib|EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.inf
|
||||
|
||||
[LibraryClasses.ARM, LibraryClasses.AARCH64]
|
||||
ArmGicLib|ArmPkg/Drivers/ArmGic/ArmGicLib.inf
|
||||
ArmSmcLib|ArmPkg/Library/ArmSmcLib/ArmSmcLib.inf
|
||||
BdsLib|ArmPkg/Library/BdsLib/BdsLib.inf
|
||||
SemihostLib|ArmPkg/Library/SemihostLib/SemihostLib.inf
|
||||
NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf
|
||||
|
||||
[LibraryClasses.ARM]
|
||||
ArmLib|ArmPkg/Library/ArmLib/ArmV7/ArmV7Lib.inf
|
||||
|
||||
[LibraryClasses.AARCH64]
|
||||
ArmLib|ArmPkg/Library/ArmLib/AArch64/AArch64Lib.inf
|
||||
|
||||
|
||||
################################################################################
|
||||
#
|
||||
|
@ -211,6 +220,9 @@
|
|||
# RELEASE_*_IA32_DLINK_FLAGS = /ALIGN:4096
|
||||
# *_*_IA32_CC_FLAGS = /D EFI_SPECIFICATION_VERSION=0x0002000A /D TIANO_RELEASE_VERSION=0x00080006
|
||||
|
||||
[BuildOptions]
|
||||
RVCT:*_*_ARM_PLATFORM_FLAGS == --cpu=7-A.security
|
||||
|
||||
|
||||
################################################################################
|
||||
#
|
||||
|
@ -242,5 +254,7 @@
|
|||
|
||||
EmbeddedPkg/Universal/MmcDxe/MmcDxe.inf
|
||||
|
||||
EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.inf
|
||||
|
||||
[Components.IA32, Components.X64, Components.IPF, Components.ARM]
|
||||
EmbeddedPkg/GdbStub/GdbStub.inf
|
||||
|
|
Loading…
Reference in New Issue