EmbeddedPkg/AndroidBoot: boot android kernel from storage
authorJun Nie <jun.nie@linaro.org>
Thu, 17 Aug 2017 12:58:59 +0000 (20:58 +0800)
committerLeif Lindholm <leif.lindholm@linaro.org>
Sun, 20 Aug 2017 11:36:34 +0000 (12:36 +0100)
Add an android kernel loader that could load kernel from storage
device.
This android boot image BDS add addtitional cmdline/dtb/ramfs
support besides kernel that is introduced by Android boot header.

This patch is derived from Haojian's code as below link.
https://patches.linaro.org/patch/94683/

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jun Nie <jun.nie@linaro.org>
Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.c [new file with mode: 0644]
EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.inf [new file with mode: 0644]
EmbeddedPkg/EmbeddedPkg.dec
EmbeddedPkg/EmbeddedPkg.dsc
EmbeddedPkg/Include/Library/AndroidBootImgLib.h
EmbeddedPkg/Include/Protocol/AndroidBootImg.h [new file with mode: 0644]
EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.c [new file with mode: 0644]
EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.inf [new file with mode: 0644]

diff --git a/EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.c b/EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.c
new file mode 100644 (file)
index 0000000..977167d
--- /dev/null
@@ -0,0 +1,140 @@
+/** @file\r
+\r
+  Copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>\r
+  Copyright (c) 2017, Linaro. All rights reserved.\r
+\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <Library/AndroidBootImgLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/BdsLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+\r
+#include <Protocol/BlockIo.h>\r
+#include <Protocol/DevicePathFromText.h>\r
+\r
+/* Validate the node is media hard drive type */\r
+EFI_STATUS\r
+ValidateAndroidMediaDevicePath (\r
+  IN EFI_DEVICE_PATH                  *DevicePath\r
+  )\r
+{\r
+  EFI_DEVICE_PATH_PROTOCOL            *Node, *NextNode;\r
+\r
+  NextNode = DevicePath;\r
+  while (NextNode != NULL) {\r
+    Node = NextNode;\r
+    if (IS_DEVICE_PATH_NODE (Node, MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP)) {\r
+      return EFI_SUCCESS;\r
+    }\r
+    NextNode = NextDevicePathNode (Node);\r
+  }\r
+  return EFI_INVALID_PARAMETER;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AndroidBootAppEntryPoint (\r
+  IN EFI_HANDLE                            ImageHandle,\r
+  IN EFI_SYSTEM_TABLE                      *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  CHAR16                              *BootPathStr;\r
+  EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL  *EfiDevicePathFromTextProtocol;\r
+  EFI_DEVICE_PATH                     *DevicePath;\r
+  EFI_BLOCK_IO_PROTOCOL               *BlockIo;\r
+  UINT32                              MediaId, BlockSize;\r
+  VOID                                *Buffer;\r
+  EFI_HANDLE                          Handle;\r
+  UINTN                               BootImgSize;\r
+\r
+  BootPathStr = (CHAR16 *)PcdGetPtr (PcdAndroidBootDevicePath);\r
+  ASSERT (BootPathStr != NULL);\r
+  Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL,\r
+                                (VOID **)&EfiDevicePathFromTextProtocol);\r
+  ASSERT_EFI_ERROR(Status);\r
+  DevicePath = (EFI_DEVICE_PATH *)EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (BootPathStr);\r
+  ASSERT (DevicePath != NULL);\r
+\r
+  Status = ValidateAndroidMediaDevicePath (DevicePath);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid,\r
+                                  &DevicePath, &Handle);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Handle,\r
+                  &gEfiBlockIoProtocolGuid,\r
+                  (VOID **) &BlockIo,\r
+                  gImageHandle,\r
+                  NULL,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "Failed to get BlockIo: %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  MediaId = BlockIo->Media->MediaId;\r
+  BlockSize = BlockIo->Media->BlockSize;\r
+  Buffer = AllocatePages (EFI_SIZE_TO_PAGES (sizeof(ANDROID_BOOTIMG_HEADER)));\r
+  if (Buffer == NULL) {\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+  /* Load header of boot.img */\r
+  Status = BlockIo->ReadBlocks (\r
+                      BlockIo,\r
+                      MediaId,\r
+                      0,\r
+                      BlockSize,\r
+                      Buffer\r
+                      );\r
+  Status = AndroidBootImgGetImgSize (Buffer, &BootImgSize);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "Failed to get AndroidBootImg Size: %r\n", Status));\r
+    return Status;\r
+  }\r
+  BootImgSize = ALIGN_VALUE (BootImgSize, BlockSize);\r
+  FreePages (Buffer, EFI_SIZE_TO_PAGES (sizeof(ANDROID_BOOTIMG_HEADER)));\r
+\r
+  /* Both PartitionStart and PartitionSize are counted as block size. */\r
+  Buffer = AllocatePages (EFI_SIZE_TO_PAGES (BootImgSize));\r
+  if (Buffer == NULL) {\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+\r
+  /* Load header of boot.img */\r
+  Status = BlockIo->ReadBlocks (\r
+                      BlockIo,\r
+                      MediaId,\r
+                      0,\r
+                      BootImgSize,\r
+                      Buffer\r
+                      );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "Failed to read blocks: %r\n", Status));\r
+    goto EXIT;\r
+  }\r
+\r
+  Status = AndroidBootImgBoot (Buffer, BootImgSize);\r
+\r
+EXIT:\r
+  return Status;\r
+}\r
diff --git a/EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.inf b/EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.inf
new file mode 100644 (file)
index 0000000..f1ee0bd
--- /dev/null
@@ -0,0 +1,64 @@
+#/** @file\r
+#\r
+#  Copyright (c) 2013-2015, ARM Ltd. All rights reserved.<BR>\r
+#  Copyright (c) 2017, Linaro. All rights reserved.\r
+#\r
+#  This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution. The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+#**/\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010019\r
+  BASE_NAME                      = AndroidBootApp\r
+  FILE_GUID                      = 3a738b36-b9c5-4763-abbd-6cbd4b25f9ff\r
+  MODULE_TYPE                    = UEFI_APPLICATION\r
+  VERSION_STRING                 = 1.0\r
+  ENTRY_POINT                    = AndroidBootAppEntryPoint\r
+\r
+[Sources.common]\r
+  AndroidBootApp.c\r
+\r
+[LibraryClasses]\r
+  AndroidBootImgLib\r
+  BaseLib\r
+  BaseMemoryLib\r
+  BdsLib\r
+  DebugLib\r
+  DevicePathLib\r
+  DxeServicesTableLib\r
+  FdtLib\r
+  MemoryAllocationLib\r
+  PcdLib\r
+  PrintLib\r
+  UefiApplicationEntryPoint\r
+  UefiBootServicesTableLib\r
+  UefiLib\r
+  UefiRuntimeServicesTableLib\r
+\r
+[Protocols]\r
+  gAndroidFastbootPlatformProtocolGuid\r
+  gEfiBlockIoProtocolGuid\r
+  gEfiDevicePathFromTextProtocolGuid\r
+  gEfiSimpleTextOutProtocolGuid\r
+  gEfiSimpleTextInProtocolGuid\r
+\r
+[Packages]\r
+  EmbeddedPkg/EmbeddedPkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  MdePkg/MdePkg.dec\r
+\r
+[Packages.ARM, Packages.AARCH64]\r
+  ArmPkg/ArmPkg.dec\r
+  ArmPlatformPkg/ArmPlatformPkg.dec\r
+\r
+[Guids]\r
+  gFdtTableGuid\r
+\r
+[Pcd]\r
+  gEmbeddedTokenSpaceGuid.PcdAndroidBootDevicePath\r
index 4cd528a..8ad2a84 100644 (file)
@@ -80,6 +80,7 @@
   gAndroidFastbootPlatformProtocolGuid =  { 0x524685a0, 0x89a0, 0x11e3, {0x9d, 0x4d, 0xbf, 0xa9, 0xf6, 0xa4, 0x03, 0x08}}\r
   gUsbDeviceProtocolGuid =  { 0x021bd2ca, 0x51d2, 0x11e3, {0x8e, 0x56, 0xb7, 0x54, 0x17, 0xc7,  0x0b, 0x44 }}\r
   gPlatformGpioProtocolGuid = { 0x52ce9845, 0x5af4, 0x43e2, {0xba, 0xfd, 0x23, 0x08, 0x12, 0x54, 0x7a, 0xc2 }}\r
+  gAndroidBootImgProtocolGuid = { 0x9859bb19, 0x407c, 0x4f8b, {0xbc, 0xe1, 0xf8, 0xda, 0x65, 0x65, 0xf4, 0xa5 }}\r
 \r
 [PcdsFeatureFlag.common]\r
   gEmbeddedTokenSpaceGuid.PcdEmbeddedMacBoot|FALSE|BOOLEAN|0x00000001\r
   gEmbeddedTokenSpaceGuid.PcdAndroidFastbootUsbProductId|0xbeef|UINT32|0x00000023\r
   gEmbeddedTokenSpaceGuid.PcdAndroidFastbootTcpPort|1234|UINT32|0x00000024\r
 \r
+  gEmbeddedTokenSpaceGuid.PcdAndroidBootDevicePath|L""|VOID*|0x00000057\r
 \r
 [PcdsFixedAtBuild.ARM]\r
   gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize|32|UINT8|0x00000010\r
index 16b368e..4a34e34 100644 (file)
@@ -52,6 +52,7 @@
   DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf\r
 \r
 \r
+  AndroidBootImgLib|EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.inf\r
   BaseLib|MdePkg/Library/BaseLib/BaseLib.inf\r
   BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf\r
   PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf\r
       TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf\r
   }\r
 \r
+  EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.inf\r
   EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.inf {\r
     <LibraryClasses>\r
       # It depends on BdsLib that depends on TimerLib\r
index 06da751..331caa5 100644 (file)
@@ -55,4 +55,17 @@ typedef struct {
  * and larger than boot header */\r
 #define IS_VALID_ANDROID_PAGE_SIZE(Val)   \\r
              (IS_POWER_OF_2(Val) && (Val > sizeof(ANDROID_BOOTIMG_HEADER)))\r
+\r
+EFI_STATUS\r
+AndroidBootImgGetImgSize (\r
+  IN  VOID    *BootImg,\r
+  OUT UINTN   *ImgSize\r
+  );\r
+\r
+EFI_STATUS\r
+AndroidBootImgBoot (\r
+  IN VOID                   *Buffer,\r
+  IN UINTN                   BufferSize\r
+  );\r
+\r
 #endif /* __ABOOTIMG_H__ */\r
diff --git a/EmbeddedPkg/Include/Protocol/AndroidBootImg.h b/EmbeddedPkg/Include/Protocol/AndroidBootImg.h
new file mode 100644 (file)
index 0000000..1c458d0
--- /dev/null
@@ -0,0 +1,47 @@
+/** @file\r
+\r
+  Copyright (c) 2017, Linaro. All rights reserved.<BR>\r
+\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __ANDROID_BOOTIMG_PROTOCOL_H__\r
+#define __ANDROID_BOOTIMG_PROTOCOL_H__\r
+\r
+//\r
+// Protocol interface structure\r
+//\r
+typedef struct _ANDROID_BOOTIMG_PROTOCOL    ANDROID_BOOTIMG_PROTOCOL;\r
+\r
+//\r
+// Function Prototypes\r
+//\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *ANDROID_BOOTIMG_APPEND_KERNEL_ARGS) (\r
+  IN CHAR16            *Args,\r
+  IN UINTN              Size\r
+  );\r
+\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *ANDROID_BOOTIMG_UPDATE_DTB) (\r
+  IN  EFI_PHYSICAL_ADDRESS    OrigDtbBase;\r
+  OUT EFI_PHYSICAL_ADDRESS   *NewDtbBase;\r
+  );\r
+\r
+struct _ANDROID_BOOTIMG_PROTOCOL {\r
+  ANDROID_BOOTIMG_APPEND_KERNEL_ARGS        AppendArgs;\r
+  ANDROID_BOOTIMG_UPDATE_DTB                UpdateDtb;\r
+};\r
+\r
+extern EFI_GUID gAndroidBootImgProtocolGuid;\r
+\r
+#endif /* __ANDROID_BOOTIMG_PROTOCOL_H__ */\r
diff --git a/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.c b/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.c
new file mode 100644 (file)
index 0000000..09c4d92
--- /dev/null
@@ -0,0 +1,463 @@
+/** @file\r
+\r
+  Copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>\r
+  Copyright (c) 2017, Linaro. All rights reserved.\r
+\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <libfdt.h>\r
+#include <Library/AndroidBootImgLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+\r
+#include <Protocol/AndroidBootImg.h>\r
+#include <Protocol/LoadedImage.h>\r
+\r
+#include <libfdt.h>\r
+\r
+#define FDT_ADDITIONAL_ENTRIES_SIZE 0x400\r
+\r
+typedef struct {\r
+  MEMMAP_DEVICE_PATH                      Node1;\r
+  EFI_DEVICE_PATH_PROTOCOL                End;\r
+} MEMORY_DEVICE_PATH;\r
+\r
+STATIC ANDROID_BOOTIMG_PROTOCOL                 *mAndroidBootImg;\r
+\r
+STATIC CONST MEMORY_DEVICE_PATH mMemoryDevicePathTemplate =\r
+{\r
+  {\r
+    {\r
+      HARDWARE_DEVICE_PATH,\r
+      HW_MEMMAP_DP,\r
+      {\r
+        (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),\r
+        (UINT8)((sizeof (MEMMAP_DEVICE_PATH)) >> 8),\r
+      },\r
+    }, // Header\r
+    0, // StartingAddress (set at runtime)\r
+    0  // EndingAddress   (set at runtime)\r
+  }, // Node1\r
+  {\r
+    END_DEVICE_PATH_TYPE,\r
+    END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
+    { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }\r
+  } // End\r
+};\r
+\r
+EFI_STATUS\r
+AndroidBootImgGetImgSize (\r
+  IN  VOID    *BootImg,\r
+  OUT UINTN   *ImgSize\r
+  )\r
+{\r
+  ANDROID_BOOTIMG_HEADER   *Header;\r
+\r
+  Header = (ANDROID_BOOTIMG_HEADER *) BootImg;\r
+\r
+  if (AsciiStrnCmp ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC,\r
+                    ANDROID_BOOT_MAGIC_LENGTH) != 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  /* The page size is not specified, but it should be power of 2 at least */\r
+  ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize));\r
+\r
+  /* Get real size of abootimg */\r
+  *ImgSize = ALIGN_VALUE (Header->KernelSize, Header->PageSize) +\r
+             ALIGN_VALUE (Header->RamdiskSize, Header->PageSize) +\r
+             ALIGN_VALUE (Header->SecondStageBootloaderSize, Header->PageSize) +\r
+             Header->PageSize;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+AndroidBootImgGetKernelInfo (\r
+  IN  VOID    *BootImg,\r
+  OUT VOID   **Kernel,\r
+  OUT UINTN   *KernelSize\r
+  )\r
+{\r
+  ANDROID_BOOTIMG_HEADER   *Header;\r
+\r
+  Header = (ANDROID_BOOTIMG_HEADER *) BootImg;\r
+\r
+  if (AsciiStrnCmp ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC,\r
+                    ANDROID_BOOT_MAGIC_LENGTH) != 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Header->KernelSize == 0) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize));\r
+\r
+  *KernelSize = Header->KernelSize;\r
+  *Kernel = BootImg + Header->PageSize;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+AndroidBootImgGetRamdiskInfo (\r
+  IN  VOID    *BootImg,\r
+  OUT VOID   **Ramdisk,\r
+  OUT UINTN   *RamdiskSize\r
+  )\r
+{\r
+  ANDROID_BOOTIMG_HEADER   *Header;\r
+\r
+  Header = (ANDROID_BOOTIMG_HEADER *)BootImg;\r
+\r
+  if (AsciiStrnCmp ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC,\r
+                    ANDROID_BOOT_MAGIC_LENGTH) != 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize));\r
+\r
+  *RamdiskSize = Header->RamdiskSize;\r
+\r
+  if (Header->RamdiskSize != 0) {\r
+    *Ramdisk = (VOID *)((INTN)BootImg\r
+                        + Header->PageSize\r
+                        + ALIGN_VALUE (Header->KernelSize, Header->PageSize));\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+AndroidBootImgGetSecondBootLoaderInfo (\r
+  IN  VOID    *BootImg,\r
+  OUT VOID   **Second,\r
+  OUT UINTN   *SecondSize\r
+  )\r
+{\r
+  ANDROID_BOOTIMG_HEADER   *Header;\r
+\r
+  Header = (ANDROID_BOOTIMG_HEADER *)BootImg;\r
+\r
+  if (AsciiStrnCmp ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC,\r
+                    ANDROID_BOOT_MAGIC_LENGTH) != 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize));\r
+\r
+  *SecondSize = Header->SecondStageBootloaderSize;\r
+\r
+  if (Header->SecondStageBootloaderSize != 0) {\r
+    *Second = (VOID *)((UINTN)BootImg\r
+                       + Header->PageSize\r
+                       + ALIGN_VALUE (Header->KernelSize, Header->PageSize)\r
+                       + ALIGN_VALUE (Header->RamdiskSize, Header->PageSize));\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+AndroidBootImgGetKernelArgs (\r
+  IN  VOID    *BootImg,\r
+  OUT CHAR8   *KernelArgs\r
+  )\r
+{\r
+  ANDROID_BOOTIMG_HEADER   *Header;\r
+\r
+  Header = (ANDROID_BOOTIMG_HEADER *) BootImg;\r
+  AsciiStrnCpyS (KernelArgs, ANDROID_BOOTIMG_KERNEL_ARGS_SIZE, Header->KernelArgs,\r
+    ANDROID_BOOTIMG_KERNEL_ARGS_SIZE);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+AndroidBootImgGetFdt (\r
+  IN  VOID                  *BootImg,\r
+  IN  VOID                 **FdtBase\r
+  )\r
+{\r
+  UINTN                      SecondLoaderSize;\r
+  EFI_STATUS                 Status;\r
+\r
+  /* Check whether FDT is located in second boot region as some vendor do so,\r
+   * because second loader is never used as far as I know. */\r
+  Status = AndroidBootImgGetSecondBootLoaderInfo (\r
+             BootImg,\r
+             FdtBase,\r
+             &SecondLoaderSize\r
+           );\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+AndroidBootImgUpdateArgs (\r
+  IN  VOID                  *BootImg,\r
+  OUT VOID                  *KernelArgs\r
+  )\r
+{\r
+  CHAR8                      ImageKernelArgs[ANDROID_BOOTIMG_KERNEL_ARGS_SIZE];\r
+  EFI_STATUS                 Status;\r
+\r
+  // Get kernel arguments from Android boot image\r
+  Status = AndroidBootImgGetKernelArgs (BootImg, ImageKernelArgs);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  AsciiStrToUnicodeStrS (ImageKernelArgs, KernelArgs,\r
+                         ANDROID_BOOTIMG_KERNEL_ARGS_SIZE >> 1);\r
+  // Append platform kernel arguments\r
+  if(mAndroidBootImg->AppendArgs) {\r
+    Status = mAndroidBootImg->AppendArgs (KernelArgs,\r
+                                ANDROID_BOOTIMG_KERNEL_ARGS_SIZE);\r
+  }\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+AndroidBootImgLocateFdt (\r
+  IN  VOID                  *BootImg,\r
+  IN  VOID                 **FdtBase\r
+  )\r
+{\r
+  INTN                       Err;\r
+  EFI_STATUS                 Status;\r
+\r
+  Status = EfiGetSystemConfigurationTable (&gFdtTableGuid, FdtBase);\r
+  if (!EFI_ERROR (Status)) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Status = AndroidBootImgGetFdt (BootImg, FdtBase);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  Err = fdt_check_header (*FdtBase);\r
+  if (Err != 0) {\r
+    DEBUG ((DEBUG_ERROR, "ERROR: Device Tree header not valid (Err:%d)\n",\r
+           Err));\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+INTN\r
+AndroidBootImgGetChosenNode (\r
+  IN  INTN   UpdatedFdtBase\r
+  )\r
+{\r
+  INTN                   ChosenNode;\r
+\r
+  ChosenNode = fdt_subnode_offset ((CONST VOID *)UpdatedFdtBase, 0, "chosen");\r
+  if (ChosenNode < 0) {\r
+    ChosenNode = fdt_add_subnode((VOID *)UpdatedFdtBase, 0, "chosen");\r
+      if (ChosenNode < 0) {\r
+        DEBUG ((DEBUG_ERROR, "Fail to find fdt node chosen!\n"));\r
+        return 0;\r
+    }\r
+  }\r
+  return ChosenNode;\r
+}\r
+\r
+EFI_STATUS\r
+AndroidBootImgSetProperty64 (\r
+  IN  INTN                   UpdatedFdtBase,\r
+  IN  INTN                   ChosenNode,\r
+  IN  CHAR8                 *PropertyName,\r
+  IN  UINT64                 Val\r
+  )\r
+{\r
+  INTN                      Err;\r
+  struct fdt_property      *Property;\r
+  int                       Len;\r
+\r
+  Property = fdt_get_property_w((VOID *)UpdatedFdtBase, ChosenNode,\r
+                            PropertyName, &Len);\r
+  if (NULL == Property && Len == -FDT_ERR_NOTFOUND) {\r
+    Val = cpu_to_fdt64(Val);\r
+    Err = fdt_appendprop ((VOID *)UpdatedFdtBase, ChosenNode,\r
+                          PropertyName, &Val, sizeof (UINT64));\r
+    if (Err) {\r
+      DEBUG ((DEBUG_ERROR, "fdt_appendprop() fail: %a\n", fdt_strerror (Err)));\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  } else if (Property != NULL) {\r
+    Err = fdt_setprop_u64((VOID *)UpdatedFdtBase, ChosenNode,\r
+                          PropertyName, Val);\r
+    if (Err) {\r
+      DEBUG ((DEBUG_ERROR, "fdt_setprop_u64() fail: %a\n", fdt_strerror (Err)));\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  } else {\r
+    DEBUG ((DEBUG_ERROR, "Failed to set fdt Property %a\n", PropertyName));\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+AndroidBootImgUpdateFdt (\r
+  IN  VOID                  *BootImg,\r
+  IN  VOID                  *FdtBase,\r
+  IN  VOID                  *RamdiskData,\r
+  IN  UINTN                  RamdiskSize\r
+  )\r
+{\r
+  INTN                       ChosenNode, Err, NewFdtSize;\r
+  EFI_STATUS                 Status;\r
+  EFI_PHYSICAL_ADDRESS       UpdatedFdtBase, NewFdtBase;\r
+\r
+  NewFdtSize = (UINTN)fdt_totalsize (FdtBase)\r
+               + FDT_ADDITIONAL_ENTRIES_SIZE;\r
+  Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData,\r
+                  EFI_SIZE_TO_PAGES (NewFdtSize), &UpdatedFdtBase);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_WARN, "Warning: Failed to reallocate FDT, err %d.\n",\r
+           Status));\r
+    return Status;\r
+  }\r
+\r
+  // Load the Original FDT tree into the new region\r
+  Err = fdt_open_into(FdtBase, (VOID*)(INTN)UpdatedFdtBase, NewFdtSize);\r
+  if (Err) {\r
+    DEBUG ((DEBUG_ERROR, "fdt_open_into(): %a\n", fdt_strerror (Err)));\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto Fdt_Exit;\r
+  }\r
+\r
+  ChosenNode = AndroidBootImgGetChosenNode(UpdatedFdtBase);\r
+  if (!ChosenNode) {\r
+    goto Fdt_Exit;\r
+  }\r
+\r
+  Status = AndroidBootImgSetProperty64 (UpdatedFdtBase, ChosenNode,\r
+                                        "linux,initrd-start",\r
+                                        (UINTN)RamdiskData);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Fdt_Exit;\r
+  }\r
+\r
+  Status = AndroidBootImgSetProperty64 (UpdatedFdtBase, ChosenNode,\r
+                                        "linux,initrd-end",\r
+                                        (UINTN)(RamdiskData + RamdiskSize));\r
+  if (EFI_ERROR (Status)) {\r
+    goto Fdt_Exit;\r
+  }\r
+\r
+  if (mAndroidBootImg->UpdateDtb) {\r
+    Status = mAndroidBootImg->UpdateDtb (UpdatedFdtBase, &NewFdtBase);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Fdt_Exit;\r
+    }\r
+  }\r
+\r
+  Status = gBS->InstallConfigurationTable (\r
+                  &gFdtTableGuid,\r
+                  (VOID *)(UINTN)NewFdtBase\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+Fdt_Exit:\r
+  gBS->FreePages (UpdatedFdtBase, EFI_SIZE_TO_PAGES (NewFdtSize));\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+AndroidBootImgBoot (\r
+  IN VOID                            *Buffer,\r
+  IN UINTN                            BufferSize\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  VOID                               *Kernel;\r
+  UINTN                               KernelSize;\r
+  MEMORY_DEVICE_PATH                  KernelDevicePath;\r
+  EFI_HANDLE                          ImageHandle;\r
+  VOID                               *NewKernelArg;\r
+  EFI_LOADED_IMAGE_PROTOCOL          *ImageInfo;\r
+  VOID                               *RamdiskData;\r
+  UINTN                               RamdiskSize;\r
+  IN  VOID                           *FdtBase;\r
+\r
+  Status = gBS->LocateProtocol (&gAndroidBootImgProtocolGuid, NULL,\r
+                                (VOID **) &mAndroidBootImg);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = AndroidBootImgGetKernelInfo (\r
+            Buffer,\r
+            &Kernel,\r
+            &KernelSize\r
+            );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  NewKernelArg = AllocateZeroPool (ANDROID_BOOTIMG_KERNEL_ARGS_SIZE);\r
+  if (NewKernelArg == NULL) {\r
+    DEBUG ((DEBUG_ERROR, "Fail to allocate memory\n"));\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = AndroidBootImgUpdateArgs (Buffer, NewKernelArg);\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (NewKernelArg);\r
+    return Status;\r
+  }\r
+\r
+  Status = AndroidBootImgGetRamdiskInfo (\r
+            Buffer,\r
+            &RamdiskData,\r
+            &RamdiskSize\r
+            );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = AndroidBootImgLocateFdt (Buffer, &FdtBase);\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (NewKernelArg);\r
+    return Status;\r
+  }\r
+\r
+  Status = AndroidBootImgUpdateFdt (Buffer, FdtBase, RamdiskData, RamdiskSize);\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (NewKernelArg);\r
+    return Status;\r
+  }\r
+\r
+  KernelDevicePath = mMemoryDevicePathTemplate;\r
+\r
+  KernelDevicePath.Node1.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Kernel;\r
+  KernelDevicePath.Node1.EndingAddress   = (EFI_PHYSICAL_ADDRESS)(UINTN) Kernel\r
+                                           + KernelSize;\r
+\r
+  Status = gBS->LoadImage (TRUE, gImageHandle,\r
+                           (EFI_DEVICE_PATH *)&KernelDevicePath,\r
+                           (VOID*)(UINTN)Kernel, KernelSize, &ImageHandle);\r
+\r
+  // Set kernel arguments\r
+  Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid,\r
+                                (VOID **) &ImageInfo);\r
+  ImageInfo->LoadOptions = NewKernelArg;\r
+  ImageInfo->LoadOptionsSize = StrLen (NewKernelArg) * sizeof (CHAR16);\r
+\r
+  // Before calling the image, enable the Watchdog Timer for  the 5 Minute period\r
+  gBS->SetWatchdogTimer (5 * 60, 0x10000, 0, NULL);\r
+  // Start the image\r
+  Status = gBS->StartImage (ImageHandle, NULL, NULL);\r
+  // Clear the Watchdog Timer if the image returns\r
+  gBS->SetWatchdogTimer (0, 0x10000, 0, NULL);\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.inf b/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.inf
new file mode 100644 (file)
index 0000000..c92bac0
--- /dev/null
@@ -0,0 +1,48 @@
+#/** @file\r
+#\r
+#  Copyright (c) 2013-2015, ARM Ltd. All rights reserved.<BR>\r
+#  Copyright (c) 2017, Linaro. All rights reserved.\r
+#\r
+#  This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution. The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+#**/\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010019\r
+  BASE_NAME                      = AndroidBootImgLib\r
+  FILE_GUID                      = ed3b8739-6fa7-4cb1-8aeb-2496f8fcaefa\r
+  MODULE_TYPE                    = BASE\r
+  VERSION_STRING                 = 1.0\r
+  LIBRARY_CLASS                  = AndroidBootImgLib\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = ARM AARCH64\r
+#\r
+\r
+[Sources]\r
+  AndroidBootImgLib.c\r
+\r
+[LibraryClasses]\r
+  DebugLib\r
+  FdtLib\r
+  PrintLib\r
+  UefiBootServicesTableLib\r
+  UefiLib\r
+\r
+[Packages]\r
+  EmbeddedPkg/EmbeddedPkg.dec\r
+  MdePkg/MdePkg.dec\r
+\r
+[Protocols]\r
+  gAndroidBootImgProtocolGuid\r
+\r
+[Guids]\r
+  gFdtTableGuid\r