Add an android kernel loader that could load kernel from storage
device. This patch is from Haojian's code. The minor change
is that alternative dtb is searched in second loader binary of
Android bootimage if dtb is not found after Linux kernel.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jun Nie <jun....@linaro.org>
---
 .../Application/AndroidBoot/AndroidBootApp.c       | 129 ++++++++
 .../Application/AndroidBoot/AndroidBootApp.inf     |  64 ++++
 EmbeddedPkg/Include/Library/AbootimgLib.h          |  65 ++++
 EmbeddedPkg/Include/Protocol/Abootimg.h            |  47 +++
 EmbeddedPkg/Library/AbootimgLib/AbootimgLib.c      | 350 +++++++++++++++++++++
 EmbeddedPkg/Library/AbootimgLib/AbootimgLib.inf    |  48 +++
 6 files changed, 703 insertions(+)
 create mode 100644 EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.c
 create mode 100644 EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.inf
 create mode 100644 EmbeddedPkg/Include/Library/AbootimgLib.h
 create mode 100644 EmbeddedPkg/Include/Protocol/Abootimg.h
 create mode 100644 EmbeddedPkg/Library/AbootimgLib/AbootimgLib.c
 create mode 100644 EmbeddedPkg/Library/AbootimgLib/AbootimgLib.inf

diff --git a/EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.c 
b/EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.c
new file mode 100644
index 0000000..9ed931b
--- /dev/null
+++ b/EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.c
@@ -0,0 +1,129 @@
+/** @file
+
+  Copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>
+  Copyright (c) 2017, Linaro. 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/AbootimgLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BdsLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include <Protocol/BlockIo.h>
+#include <Protocol/DevicePathFromText.h>
+
+#define IS_DEVICE_PATH_NODE(node,type,subtype) (((node)->Type == (type)) && 
((node)->SubType == (subtype)))
+
+#define ALIGN(x, a)        (((x) + ((a) - 1)) & ~((a) - 1))
+
+EFI_STATUS
+EFIAPI
+AndroidBootAppEntryPoint (
+  IN EFI_HANDLE                            ImageHandle,
+  IN EFI_SYSTEM_TABLE                      *SystemTable
+  )
+{
+  EFI_STATUS                          Status;
+  CHAR16                              *BootPathStr;
+  EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL  *EfiDevicePathFromTextProtocol;
+  EFI_DEVICE_PATH                     *DevicePath;
+  EFI_DEVICE_PATH_PROTOCOL            *Node, *NextNode;
+  EFI_BLOCK_IO_PROTOCOL               *BlockIo;
+  UINT32                              MediaId, BlockSize;
+  VOID                                *Buffer;
+  EFI_HANDLE                          Handle;
+  UINTN                               Size;
+
+  BootPathStr = (CHAR16 *)PcdGetPtr (PcdAndroidBootDevicePath);
+  ASSERT (BootPathStr != NULL);
+  Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, 
(VOID **)&EfiDevicePathFromTextProtocol);
+  ASSERT_EFI_ERROR(Status);
+  DevicePath = (EFI_DEVICE_PATH 
*)EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (BootPathStr);
+  ASSERT (DevicePath != NULL);
+
+  /* Find DevicePath node of Partition */
+  NextNode = DevicePath;
+  while (1) {
+    Node = NextNode;
+    if (IS_DEVICE_PATH_NODE (Node, MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP)) {
+      break;
+    }
+    NextNode = NextDevicePathNode (Node);
+  }
+
+  Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &DevicePath, 
&Handle);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = gBS->OpenProtocol (
+                  Handle,
+                  &gEfiBlockIoProtocolGuid,
+                  (VOID **) &BlockIo,
+                  gImageHandle,
+                  NULL,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "Failed to get BlockIo: %r\n", Status));
+    return Status;
+  }
+
+  MediaId = BlockIo->Media->MediaId;
+  BlockSize = BlockIo->Media->BlockSize;
+  Buffer = AllocatePages (1);
+  if (Buffer == NULL) {
+    return EFI_BUFFER_TOO_SMALL;
+  }
+  /* Load header of boot.img */
+  Status = BlockIo->ReadBlocks (
+                      BlockIo,
+                      MediaId,
+                      0,
+                      BlockSize,
+                      Buffer
+                      );
+  Status = AbootimgGetImgSize (Buffer, &Size);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "Failed to get Abootimg Size: %r\n", Status));
+    return Status;
+  }
+  Size = ALIGN (Size, BlockSize);
+  FreePages (Buffer, 1);
+
+  /* Both PartitionStart and PartitionSize are counted as block size. */
+  Buffer = AllocatePages (EFI_SIZE_TO_PAGES (Size));
+  if (Buffer == NULL) {
+    return EFI_BUFFER_TOO_SMALL;
+  }
+
+  /* Load header of boot.img */
+  Status = BlockIo->ReadBlocks (
+                      BlockIo,
+                      MediaId,
+                      0,
+                      Size,
+                      Buffer
+                      );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "Failed to read blocks: %r\n", Status));
+    goto EXIT;
+  }
+
+  Status = AbootimgBoot (Buffer, Size);
+
+EXIT:
+  return Status;
+}
diff --git a/EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.inf 
b/EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.inf
new file mode 100644
index 0000000..8f6c8186
--- /dev/null
+++ b/EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.inf
@@ -0,0 +1,64 @@
+#/** @file
+#
+#  Copyright (c) 2013-2015, ARM Ltd. All rights reserved.<BR>
+#  Copyright (c) 2017, Linaro. 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                    = 0x00010019
+  BASE_NAME                      = AndroidBootApp
+  FILE_GUID                      = 3a738b36-b9c5-4763-abbd-6cbd4b25f9ff
+  MODULE_TYPE                    = UEFI_APPLICATION
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = AndroidBootAppEntryPoint
+
+[Sources.common]
+  AndroidBootApp.c
+
+[LibraryClasses]
+  AbootimgLib
+  BaseLib
+  BaseMemoryLib
+  BdsLib
+  DebugLib
+  DevicePathLib
+  DxeServicesTableLib
+  FdtLib
+  MemoryAllocationLib
+  PcdLib
+  PrintLib
+  UefiApplicationEntryPoint
+  UefiBootServicesTableLib
+  UefiLib
+  UefiRuntimeServicesTableLib
+
+[Protocols]
+  gAndroidFastbootPlatformProtocolGuid
+  gEfiBlockIoProtocolGuid
+  gEfiDevicePathFromTextProtocolGuid
+  gEfiSimpleTextOutProtocolGuid
+  gEfiSimpleTextInProtocolGuid
+
+[Packages]
+  EmbeddedPkg/EmbeddedPkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  MdePkg/MdePkg.dec
+
+[Packages.ARM, Packages.AARCH64]
+  ArmPkg/ArmPkg.dec
+  ArmPlatformPkg/ArmPlatformPkg.dec
+
+[Guids]
+  gFdtTableGuid
+
+[Pcd]
+  gEmbeddedTokenSpaceGuid.PcdAndroidBootDevicePath
diff --git a/EmbeddedPkg/Include/Library/AbootimgLib.h 
b/EmbeddedPkg/Include/Library/AbootimgLib.h
new file mode 100644
index 0000000..c0372d4
--- /dev/null
+++ b/EmbeddedPkg/Include/Library/AbootimgLib.h
@@ -0,0 +1,65 @@
+/** @file
+
+  Copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>
+  Copyright (c) 2017, Linaro.
+
+  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 __ABOOTIMG_H__
+#define __ABOOTIMG_H__
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <Uefi/UefiBaseType.h>
+#include <Uefi/UefiSpec.h>
+
+#define BOOTIMG_KERNEL_ARGS_SIZE          512
+
+#define BOOT_MAGIC                        "ANDROID!"
+#define BOOT_MAGIC_LENGTH                 (sizeof (BOOT_MAGIC) - 1)
+
+/* It's the value of arm64 efi stub kernel */
+#define KERNEL_IMAGE_STEXT_OFFSET         0x12C
+#define KERNEL_IMAGE_RAW_SIZE_OFFSET      0x130
+
+#define FDT_SIZE_OFFSET                   0x4
+
+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;
+
+EFI_STATUS
+AbootimgGetImgSize (
+  IN  VOID    *BootImg,
+  OUT UINTN   *ImgSize
+  );
+
+EFI_STATUS
+AbootimgBoot (
+  IN VOID                   *Buffer,
+  IN UINTN                   BufferSize
+  );
+
+#endif /* __ABOOTIMG_H__ */
diff --git a/EmbeddedPkg/Include/Protocol/Abootimg.h 
b/EmbeddedPkg/Include/Protocol/Abootimg.h
new file mode 100644
index 0000000..c85dad2
--- /dev/null
+++ b/EmbeddedPkg/Include/Protocol/Abootimg.h
@@ -0,0 +1,47 @@
+/** @file
+
+  Copyright (c) 2017, Linaro. 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 __ABOOTIMG_PROTOCOL_H__
+#define __ABOOTIMG_PROTOCOL_H__
+
+//
+// Protocol interface structure
+//
+typedef struct _ABOOTIMG_PROTOCOL    ABOOTIMG_PROTOCOL;
+
+//
+// Function Prototypes
+//
+typedef
+EFI_STATUS
+(EFIAPI *ABOOTIMG_APPEND_KERNEL_ARGS) (
+  IN CHAR16            *Args,
+  IN UINTN              Size
+  );
+
+typedef
+EFI_STATUS
+(EFIAPI *ABOOTIMG_UPDATE_DTB) (
+  IN  EFI_PHYSICAL_ADDRESS    OrigDtbBase;
+  OUT EFI_PHYSICAL_ADDRESS   *NewDtbBase;
+  );
+
+struct _ABOOTIMG_PROTOCOL {
+  ABOOTIMG_APPEND_KERNEL_ARGS        AppendArgs;
+  ABOOTIMG_UPDATE_DTB                UpdateDtb;
+};
+
+extern EFI_GUID gAbootimgProtocolGuid;
+
+#endif /* __ABOOTIMG_PROTOCOL_H__ */
diff --git a/EmbeddedPkg/Library/AbootimgLib/AbootimgLib.c 
b/EmbeddedPkg/Library/AbootimgLib/AbootimgLib.c
new file mode 100644
index 0000000..ea30a01
--- /dev/null
+++ b/EmbeddedPkg/Library/AbootimgLib/AbootimgLib.c
@@ -0,0 +1,350 @@
+/** @file
+
+  Copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>
+  Copyright (c) 2017, Linaro. 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/AbootimgLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Protocol/Abootimg.h>
+#include <Protocol/LoadedImage.h>
+
+#include <libfdt.h>
+
+// 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))
+
+typedef struct {
+  MEMMAP_DEVICE_PATH                      Node1;
+  EFI_DEVICE_PATH_PROTOCOL                End;
+} MEMORY_DEVICE_PATH;
+
+STATIC ABOOTIMG_PROTOCOL                 *mAbootimg;
+
+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
+AbootimgGetImgSize (
+  IN  VOID    *BootImg,
+  OUT UINTN   *ImgSize
+  )
+{
+  ANDROID_BOOTIMG_HEADER   *Header;
+
+  Header = (ANDROID_BOOTIMG_HEADER *) BootImg;
+
+  if (AsciiStrnCmp (Header->BootMagic, BOOT_MAGIC, BOOT_MAGIC_LENGTH) != 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ASSERT (IS_POWER_OF_2 (Header->PageSize));
+
+  /* Get real size of abootimg */
+  *ImgSize = ALIGN_VALUE (Header->KernelSize, Header->PageSize) +
+             ALIGN_VALUE (Header->RamdiskSize, Header->PageSize) +
+             ALIGN_VALUE (Header->SecondStageBootloaderSize, Header->PageSize) 
+
+             Header->PageSize;
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+AbootimgGetKernelInfo (
+  IN  VOID    *BootImg,
+  OUT VOID   **Kernel,
+  OUT UINTN   *KernelSize
+  )
+{
+  ANDROID_BOOTIMG_HEADER   *Header;
+
+  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 = BootImg + Header->PageSize;
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+AbootimgGetRamdiskInfo (
+  IN  VOID    *BootImg,
+  OUT VOID   **Ramdisk,
+  OUT UINTN   *RamdiskSize
+  )
+{
+  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;
+  }
+
+  ASSERT (IS_POWER_OF_2 (Header->PageSize));
+
+  *RamdiskSize = Header->RamdiskSize;
+
+  if (Header->RamdiskSize != 0) {
+    *Ramdisk = (VOID *) (BootImgBytePtr
+                 + Header->PageSize
+                 + ALIGN_VALUE (Header->KernelSize, Header->PageSize));
+  }
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+AbootimgGetSecondBootLoaderInfo (
+  IN  VOID    *BootImg,
+  OUT VOID   **Second,
+  OUT UINTN   *SecondSize
+  )
+{
+  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;
+  }
+
+  ASSERT (IS_POWER_OF_2 (Header->PageSize));
+
+  *SecondSize = Header->SecondStageBootloaderSize;
+
+  if (Header->SecondStageBootloaderSize != 0) {
+    *Second = (VOID *) (BootImgBytePtr
+                 + Header->PageSize
+                 + ALIGN_VALUE (Header->KernelSize, Header->PageSize)
+                 + ALIGN_VALUE (Header->RamdiskSize, Header->PageSize));
+  }
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+AbootimgGetKernelArgs (
+  IN  VOID    *BootImg,
+  OUT CHAR8   *KernelArgs
+  )
+{
+  ANDROID_BOOTIMG_HEADER   *Header;
+
+  Header = (ANDROID_BOOTIMG_HEADER *) BootImg;
+  AsciiStrnCpyS (KernelArgs, BOOTIMG_KERNEL_ARGS_SIZE, Header->KernelArgs,
+    BOOTIMG_KERNEL_ARGS_SIZE);
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+AbootimgInstallFdt (
+  IN  VOID                  *BootImg,
+  IN  EFI_PHYSICAL_ADDRESS   FdtBase,
+  OUT VOID                  *KernelArgs
+  )
+{
+  VOID                      *Ramdisk;
+  UINTN                      RamdiskSize;
+  CHAR8                      ImgKernelArgs[BOOTIMG_KERNEL_ARGS_SIZE];
+  INTN                       err;
+  EFI_STATUS                 Status;
+  EFI_PHYSICAL_ADDRESS       NewFdtBase;
+
+  Status = gBS->LocateProtocol (&gAbootimgProtocolGuid, NULL, (VOID **) 
&mAbootimg);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = AbootimgGetRamdiskInfo (
+            BootImg,
+            &Ramdisk,
+            &RamdiskSize
+            );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  Status = AbootimgGetKernelArgs (
+            BootImg,
+            ImgKernelArgs
+            );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  // Get kernel arguments from Android boot image
+  AsciiStrToUnicodeStrS (ImgKernelArgs, KernelArgs, BOOTIMG_KERNEL_ARGS_SIZE 
>> 1);
+  // Set the ramdisk in command line arguments
+  UnicodeSPrint (
+    (CHAR16 *)KernelArgs + StrLen (KernelArgs), BOOTIMG_KERNEL_ARGS_SIZE,
+    L" initrd=0x%x,0x%x",
+    (UINTN)Ramdisk, (UINTN)RamdiskSize
+    );
+
+  // Append platform kernel arguments
+  Status = mAbootimg->AppendArgs (KernelArgs, BOOTIMG_KERNEL_ARGS_SIZE);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = mAbootimg->UpdateDtb (FdtBase, &NewFdtBase);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Sanity checks on the new FDT blob.
+  //
+  err = fdt_check_header ((VOID*)(UINTN)NewFdtBase);
+  if (err != 0) {
+    Print (L"ERROR: Device Tree header not valid (err:%d)\n", err);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = gBS->InstallConfigurationTable (
+                  &gFdtTableGuid,
+                  (VOID *)(UINTN)NewFdtBase
+                  );
+  return Status;
+}
+
+EFI_STATUS
+AbootimgBoot (
+  IN VOID                            *Buffer,
+  IN UINTN                            BufferSize
+  )
+{
+  EFI_STATUS                          Status;
+  VOID                               *Kernel;
+  UINTN                               KernelSize;
+  VOID                               *SecondLoader;
+  UINTN                               SecondLoaderSize;
+  MEMORY_DEVICE_PATH                  KernelDevicePath;
+  EFI_HANDLE                          ImageHandle;
+  EFI_PHYSICAL_ADDRESS                FdtBase;
+  VOID                               *NewKernelArg;
+  EFI_LOADED_IMAGE_PROTOCOL          *ImageInfo;
+  INTN                                Err;
+
+  Status = AbootimgGetKernelInfo (
+            Buffer,
+            &Kernel,
+            &KernelSize
+            );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  /* For flatten image, Fdt is attached at the end of kernel.
+     Get real kernel size.
+   */
+  KernelSize = *(UINT32 *)((EFI_PHYSICAL_ADDRESS)(UINTN)Kernel + 
KERNEL_IMAGE_STEXT_OFFSET) +
+               *(UINT32 *)((EFI_PHYSICAL_ADDRESS)(UINTN)Kernel + 
KERNEL_IMAGE_RAW_SIZE_OFFSET);
+
+  NewKernelArg = AllocateZeroPool (BOOTIMG_KERNEL_ARGS_SIZE);
+  if (NewKernelArg == NULL) {
+    DEBUG ((DEBUG_ERROR, "Fail to allocate memory\n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  /* FDT is at the end of kernel image */
+  FdtBase = (EFI_PHYSICAL_ADDRESS)(UINTN)Kernel + KernelSize;
+  //
+  // Sanity checks on the original FDT blob.
+  //
+  Err = fdt_check_header ((VOID*)(UINTN)FdtBase);
+  if (Err != 0) {
+    /* Check whether FDT is located in second boot loader */
+    Status = AbootimgGetSecondBootLoaderInfo (
+            Buffer,
+            &SecondLoader,
+            &SecondLoaderSize
+            );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    Err = fdt_check_header ((VOID*)(UINTN)SecondLoader);
+    if (Err != 0) {
+      DEBUG ((DEBUG_ERROR, "ERROR: Device Tree header not valid (Err:%d)\n", 
Err));
+      return EFI_INVALID_PARAMETER;
+    }
+    FdtBase = (EFI_PHYSICAL_ADDRESS)SecondLoader;
+  }
+
+  Status = AbootimgInstallFdt (Buffer, FdtBase, NewKernelArg);
+  if (EFI_ERROR (Status)) {
+    FreePool (NewKernelArg);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  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;
+
+  Status = gBS->LoadImage (TRUE, gImageHandle, (EFI_DEVICE_PATH 
*)&KernelDevicePath, (VOID*)(UINTN)Kernel, KernelSize, &ImageHandle);
+
+  // Set kernel arguments
+  Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, 
(VOID **) &ImageInfo);
+  ImageInfo->LoadOptions = NewKernelArg;
+  ImageInfo->LoadOptionsSize = StrLen (NewKernelArg) * sizeof (CHAR16);
+
+  // 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 EFI_SUCCESS;
+}
diff --git a/EmbeddedPkg/Library/AbootimgLib/AbootimgLib.inf 
b/EmbeddedPkg/Library/AbootimgLib/AbootimgLib.inf
new file mode 100644
index 0000000..461dcb8
--- /dev/null
+++ b/EmbeddedPkg/Library/AbootimgLib/AbootimgLib.inf
@@ -0,0 +1,48 @@
+#/** @file
+#
+#  Copyright (c) 2013-2015, ARM Ltd. All rights reserved.<BR>
+#  Copyright (c) 2017, Linaro. 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                    = 0x00010019
+  BASE_NAME                      = AbootimgLib
+  FILE_GUID                      = ed3b8739-6fa7-4cb1-8aeb-2496f8fcaefa
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = AbootimgLib
+
+#
+# The following information is for reference only and not required by the 
build tools.
+#
+#  VALID_ARCHITECTURES           = ARM AARCH64
+#
+
+[Sources]
+  AbootimgLib.c
+
+[LibraryClasses]
+  DebugLib
+  FdtLib
+  PrintLib
+  UefiBootServicesTableLib
+  UefiLib
+
+[Packages]
+  MdePkg/MdePkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+
+[Protocols]
+  gAbootimgProtocolGuid
+
+[Guids]
+  gFdtTableGuid
-- 
1.9.1

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to