From: Olivier Martin Date: Wed, 5 Mar 2014 04:15:44 +0000 (+0000) Subject: EmbeddedPkg/AndroidFastboot: Introduce Android FastBoot Application X-Git-Tag: edk2-stable201903~11652 X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=commitdiff_plain;h=f6755908dee0d71926ec4f440edd384523746ef6 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 git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15312 6f19259b-4bc3-4df7-8a09-765794883524 --- diff --git a/EmbeddedPkg/Application/AndroidFastboot/AndroidBootImg.c b/EmbeddedPkg/Application/AndroidFastboot/AndroidBootImg.c new file mode 100644 index 0000000000..bbca90fc08 --- /dev/null +++ b/EmbeddedPkg/Application/AndroidFastboot/AndroidBootImg.c @@ -0,0 +1,90 @@ +/** @file + + Copyright (c) 2013-2014, ARM Ltd. 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 "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; +} diff --git a/EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.c b/EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.c new file mode 100644 index 0000000000..f380817040 --- /dev/null +++ b/EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.c @@ -0,0 +1,524 @@ +/** @file + + Copyright (c) 2013-2014, ARM Ltd. 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 "AndroidFastbootApp.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* + * 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; +} diff --git a/EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.h b/EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.h new file mode 100644 index 0000000000..f62660feb7 --- /dev/null +++ b/EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.h @@ -0,0 +1,42 @@ +/** @file + + Copyright (c) 2013-2014, ARM Ltd. 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. + +**/ + +#ifndef __ANDROID_FASTBOOT_APP_H__ +#define __ANDROID_FASTBOOT_APP_H__ + +#include +#include +#include + +#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__ diff --git a/EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.inf b/EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.inf new file mode 100644 index 0000000000..ab9354c39a --- /dev/null +++ b/EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.inf @@ -0,0 +1,60 @@ +#/** @file +# +# Copyright (c) 2013-2014, ARM Ltd. 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. +# +# +#**/ + +[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 diff --git a/EmbeddedPkg/Application/AndroidFastboot/Arm/BootAndroidBootImg.c b/EmbeddedPkg/Application/AndroidFastboot/Arm/BootAndroidBootImg.c new file mode 100644 index 0000000000..6f4b66beeb --- /dev/null +++ b/EmbeddedPkg/Application/AndroidFastboot/Arm/BootAndroidBootImg.c @@ -0,0 +1,125 @@ +/** @file + + Copyright (c) 2013-2014, ARM Ltd. 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 "AndroidFastbootApp.h" + +#include + +#include +#include + +#include + +// 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; +} diff --git a/EmbeddedPkg/EmbeddedPkg.dsc b/EmbeddedPkg/EmbeddedPkg.dsc index 9eaf7dc97a..a9db4ed6af 100644 --- a/EmbeddedPkg/EmbeddedPkg.dsc +++ b/EmbeddedPkg/EmbeddedPkg.dsc @@ -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