[edk2,v6,2/2] EmbeddedPkg/AndroidBoot: boot android kernel from storage

Message ID 1502275163-3690-2-git-send-email-jun.nie@linaro.org
State Superseded
Headers show
Series
  • [edk2,v6,1/2] EmbeddedPkg/AndroidFastboot: split android boot header
Related show

Commit Message

Jun Nie Aug. 9, 2017, 10:39 a.m.
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>

---
 .../Application/AndroidBoot/AndroidBootApp.c       | 140 ++++++
 .../Application/AndroidBoot/AndroidBootApp.inf     |  64 +++
 EmbeddedPkg/EmbeddedPkg.dec                        |   2 +
 EmbeddedPkg/EmbeddedPkg.dsc                        |   2 +
 EmbeddedPkg/Include/Library/AndroidBootImgLib.h    |  13 +
 EmbeddedPkg/Include/Protocol/AndroidBootImg.h      |  47 ++
 .../Library/AndroidBootImgLib/AndroidBootImgLib.c  | 471 +++++++++++++++++++++
 .../AndroidBootImgLib/AndroidBootImgLib.inf        |  48 +++
 8 files changed, 787 insertions(+)
 create mode 100644 EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.c
 create mode 100644 EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.inf
 create mode 100644 EmbeddedPkg/Include/Protocol/AndroidBootImg.h
 create mode 100644 EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.c
 create mode 100644 EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.inf

-- 
1.9.1

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

Comments

Leif Lindholm Aug. 10, 2017, 11:13 a.m. | #1
On Wed, Aug 09, 2017 at 06:39:23PM +0800, Jun Nie wrote:
> 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>

> ---

>  .../Application/AndroidBoot/AndroidBootApp.c       | 140 ++++++

>  .../Application/AndroidBoot/AndroidBootApp.inf     |  64 +++

>  EmbeddedPkg/EmbeddedPkg.dec                        |   2 +

>  EmbeddedPkg/EmbeddedPkg.dsc                        |   2 +

>  EmbeddedPkg/Include/Library/AndroidBootImgLib.h    |  13 +

>  EmbeddedPkg/Include/Protocol/AndroidBootImg.h      |  47 ++

>  .../Library/AndroidBootImgLib/AndroidBootImgLib.c  | 471 +++++++++++++++++++++

>  .../AndroidBootImgLib/AndroidBootImgLib.inf        |  48 +++

>  8 files changed, 787 insertions(+)

>  create mode 100644 EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.c

>  create mode 100644 EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.inf

>  create mode 100644 EmbeddedPkg/Include/Protocol/AndroidBootImg.h

>  create mode 100644 EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.c

>  create mode 100644 EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.inf

> 


> diff --git a/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.c b/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.c

> new file mode 100644

> index 0000000..cb4fb67

> --- /dev/null

> +++ b/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.c

> @@ -0,0 +1,471 @@

> +/** @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 <libfdt.h>

> +#include <Library/AndroidBootImgLib.h>

> +#include <Library/PrintLib.h>

> +#include <Library/UefiBootServicesTableLib.h>

> +#include <Library/UefiLib.h>

> +

> +#include <Protocol/AndroidBootImg.h>

> +#include <Protocol/LoadedImage.h>

> +

> +#include <libfdt.h>

> +

> +#define FDT_ADDITIONAL_ENTRIES_SIZE 0x400

> +

> +typedef struct {

> +  MEMMAP_DEVICE_PATH                      Node1;

> +  EFI_DEVICE_PATH_PROTOCOL                End;

> +} MEMORY_DEVICE_PATH;

> +

> +STATIC ANDROID_BOOTIMG_PROTOCOL                 *mAndroidBootImg;

> +

> +STATIC CONST MEMORY_DEVICE_PATH mMemoryDevicePathTemplate =

> +{

> +  {

> +    {

> +      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

> +AndroidBootImgGetImgSize (

> +  IN  VOID    *BootImg,

> +  OUT UINTN   *ImgSize

> +  )

> +{

> +  ANDROID_BOOTIMG_HEADER   *Header;

> +

> +  Header = (ANDROID_BOOTIMG_HEADER *) BootImg;

> +

> +  if (AsciiStrnCmp ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC,

> +                    ANDROID_BOOT_MAGIC_LENGTH) != 0) {

> +    return EFI_INVALID_PARAMETER;

> +  }

> +

> +  /* The page size is not specified, but it should be power of 2 at least */

> +  ASSERT (IS_VALID_ANDROID_PAGE_SIZE (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

> +AndroidBootImgGetKernelInfo (

> +  IN  VOID    *BootImg,

> +  OUT VOID   **Kernel,

> +  OUT UINTN   *KernelSize

> +  )

> +{

> +  ANDROID_BOOTIMG_HEADER   *Header;

> +

> +  Header = (ANDROID_BOOTIMG_HEADER *) BootImg;

> +

> +  if (AsciiStrnCmp ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC,

> +                    ANDROID_BOOT_MAGIC_LENGTH) != 0) {

> +    return EFI_INVALID_PARAMETER;

> +  }

> +

> +  if (Header->KernelSize == 0) {

> +    return EFI_NOT_FOUND;

> +  }

> +

> +  ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize));

> +

> +  *KernelSize = Header->KernelSize;

> +  *Kernel = BootImg + Header->PageSize;

> +  return EFI_SUCCESS;

> +}

> +

> +EFI_STATUS

> +AndroidBootImgGetRamdiskInfo (

> +  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 ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC,

> +                    ANDROID_BOOT_MAGIC_LENGTH) != 0) {

> +    return EFI_INVALID_PARAMETER;

> +  }

> +

> +  ASSERT (IS_VALID_ANDROID_PAGE_SIZE (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

> +AndroidBootImgGetSecondBootLoaderInfo (

> +  IN  VOID    *BootImg,

> +  OUT VOID   **Second,

> +  OUT UINTN   *SecondSize

> +  )

> +{

> +  ANDROID_BOOTIMG_HEADER   *Header;

> +  UINTN                     BootImgBytePtr;

> +

> +  // Cast to UINT8 so we can do pointer arithmetic

> +  BootImgBytePtr = (UINTN) BootImg;


Why is this BootImgBytePtr kept around? It is completely redundant.

Using special pointers to avoid dealing with pointer arithmetic is an
antipattern, and although the actual pointer was removed here, the
same antipattern is followed.

Please change as I asked last time around - DELETE BootImgBytePtr
completely...

> +

> +  Header = (ANDROID_BOOTIMG_HEADER *) BootImg;

> +

> +  if (AsciiStrnCmp ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC,

> +                    ANDROID_BOOT_MAGIC_LENGTH) != 0) {

> +    return EFI_INVALID_PARAMETER;

> +  }

> +

> +  ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize));

> +

> +  *SecondSize = Header->SecondStageBootloaderSize;

> +

> +  if (Header->SecondStageBootloaderSize != 0) {

> +    *Second = (VOID *) (BootImgBytePtr


... and use (UINTN)BootImg here.

> +                 + Header->PageSize

> +                 + ALIGN_VALUE (Header->KernelSize, Header->PageSize)

> +                 + ALIGN_VALUE (Header->RamdiskSize, Header->PageSize));

> +  }

> +  return EFI_SUCCESS;

> +}


Now, before I noticed this I was just running some final sanity checks
and noticed this code is not 32-bit safe.

If you can also fold in the following:

<<<


>>>


we can go ahead and commit this patch.
Note that 1/2 has already been pushed, so no need to resend.

Regards,

Leif

> +

> +EFI_STATUS

> +AndroidBootImgGetKernelArgs (

> +  IN  VOID    *BootImg,

> +  OUT CHAR8   *KernelArgs

> +  )

> +{

> +  ANDROID_BOOTIMG_HEADER   *Header;

> +

> +  Header = (ANDROID_BOOTIMG_HEADER *) BootImg;

> +  AsciiStrnCpyS (KernelArgs, ANDROID_BOOTIMG_KERNEL_ARGS_SIZE, Header->KernelArgs,

> +    ANDROID_BOOTIMG_KERNEL_ARGS_SIZE);

> +

> +  return EFI_SUCCESS;

> +}

> +

> +EFI_STATUS

> +AndroidBootImgGetFdt (

> +  IN  VOID                  *BootImg,

> +  IN  VOID                 **FdtBase

> +  )

> +{

> +  UINTN                      SecondLoaderSize;

> +  EFI_STATUS                 Status;

> +

> +  /* Check whether FDT is located in second boot region as some vendor do so,

> +   * because second loader is never used as far as I know. */

> +  Status = AndroidBootImgGetSecondBootLoaderInfo (

> +          BootImg,

> +          FdtBase,

> +          &SecondLoaderSize

> +          );

> +  return Status;

> +}

> +

> +EFI_STATUS

> +AndroidBootImgUpdateArgs (

> +  IN  VOID                  *BootImg,

> +  OUT VOID                  *KernelArgs

> +  )

> +{

> +  CHAR8                      ImageKernelArgs[ANDROID_BOOTIMG_KERNEL_ARGS_SIZE];

> +  EFI_STATUS                 Status;

> +

> +  // Get kernel arguments from Android boot image

> +  Status = AndroidBootImgGetKernelArgs (BootImg, ImageKernelArgs);

> +  if (EFI_ERROR (Status)) {

> +    return Status;

> +  }

> +  AsciiStrToUnicodeStrS (ImageKernelArgs, KernelArgs,

> +                         ANDROID_BOOTIMG_KERNEL_ARGS_SIZE >> 1);

> +  // Append platform kernel arguments

> +  if(mAndroidBootImg->AppendArgs) {

> +    Status = mAndroidBootImg->AppendArgs (KernelArgs,

> +                                    ANDROID_BOOTIMG_KERNEL_ARGS_SIZE);

> +  }

> +  return Status;

> +}

> +

> +EFI_STATUS

> +AndroidBootImgLocateFdt (

> +  IN  VOID                  *BootImg,

> +  IN  VOID                 **FdtBase

> +  )

> +{

> +  INTN                       Err;

> +  EFI_STATUS                 Status;

> +

> +  Status = EfiGetSystemConfigurationTable (&gFdtTableGuid, FdtBase);

> +  if (!EFI_ERROR (Status)) {

> +    return EFI_SUCCESS;

> +  }

> +

> +  Status = AndroidBootImgGetFdt (BootImg, FdtBase);

> +  if (EFI_ERROR (Status)) {

> +    return Status;

> +  }

> +  Err = fdt_check_header (*FdtBase);

> +  if (Err != 0) {

> +    DEBUG ((DEBUG_ERROR, "ERROR: Device Tree header not valid (Err:%d)\n",

> +           Err));

> +    return EFI_INVALID_PARAMETER;

> +  }

> +  return EFI_SUCCESS;

> +}

> +

> +INTN

> +AndroidBootImgGetChosenNode (

> +  IN  EFI_PHYSICAL_ADDRESS   UpdatedFdtBase

> +  )

> +{

> +  IN  INTN                   ChosenNode;

> +

> +  ChosenNode = fdt_subnode_offset ((CONST VOID *)UpdatedFdtBase, 0, "chosen");

> +  if (ChosenNode < 0) {

> +    ChosenNode = fdt_add_subnode((VOID *)UpdatedFdtBase, 0, "chosen");

> +      if (ChosenNode < 0) {

> +        DEBUG ((DEBUG_ERROR, "Fail to find fdt node chosen!\n"));

> +        return 0;

> +    }

> +  }

> +  return ChosenNode;

> +}

> +

> +EFI_STATUS

> +AndroidBootImgSetProperty64 (

> +  IN  EFI_PHYSICAL_ADDRESS   UpdatedFdtBase,

> +  IN  INTN                   ChosenNode,

> +  IN  CHAR8                 *PropertyName,

> +  IN  UINT64                 Val

> +  )

> +{

> +  INTN                      Err;

> +  struct fdt_property      *Property;

> +  int                       Len;

> +

> +  Property = fdt_get_property_w((VOID *)UpdatedFdtBase, ChosenNode,

> +                            PropertyName, &Len);

> +  if (NULL == Property && Len == -FDT_ERR_NOTFOUND) {

> +    Val = cpu_to_fdt64(Val);

> +    Err = fdt_appendprop ((VOID *)UpdatedFdtBase, ChosenNode,

> +                          PropertyName, &Val, sizeof (UINT64));

> +    if (Err) {

> +      DEBUG ((DEBUG_ERROR, "fdt_appendprop() fail: %a\n", fdt_strerror (Err)));

> +      return EFI_INVALID_PARAMETER;

> +    }

> +  } else if (Property != NULL) {

> +    Err = fdt_setprop_u64((VOID *)UpdatedFdtBase, ChosenNode,

> +                          PropertyName, Val);

> +    if (Err) {

> +      DEBUG ((DEBUG_ERROR, "fdt_setprop_u64() fail: %a\n", fdt_strerror (Err)));

> +      return EFI_INVALID_PARAMETER;

> +    }

> +  } else {

> +    DEBUG ((DEBUG_ERROR, "Failed to set fdt Property %a\n", PropertyName));

> +    return EFI_INVALID_PARAMETER;

> +  }

> +  return EFI_SUCCESS;

> +}

> +

> +EFI_STATUS

> +AndroidBootImgUpdateFdt (

> +  IN  VOID                  *BootImg,

> +  IN  VOID                  *FdtBase,

> +  IN  VOID                  *RamdiskData,

> +  IN  UINTN                  RamdiskSize

> +  )

> +{

> +  INTN                       ChosenNode, Err, NewFdtSize;

> +  EFI_STATUS                 Status;

> +  EFI_PHYSICAL_ADDRESS       UpdatedFdtBase, NewFdtBase;

> +

> +  NewFdtSize = (UINTN)fdt_totalsize (FdtBase)

> +               + FDT_ADDITIONAL_ENTRIES_SIZE;

> +  Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData,

> +                  EFI_SIZE_TO_PAGES (NewFdtSize), &UpdatedFdtBase);

> +  if (EFI_ERROR (Status)) {

> +    DEBUG ((DEBUG_WARN, "Warning: Failed to reallocate FDT, err %d.\n",

> +           Status));

> +    return Status;

> +  }

> +

> +  // Load the Original FDT tree into the new region

> +  Err = fdt_open_into(FdtBase, (VOID*)UpdatedFdtBase, NewFdtSize);

> +  if (Err) {

> +    DEBUG ((DEBUG_ERROR, "fdt_open_into(): %a\n", fdt_strerror (Err)));

> +    Status = EFI_INVALID_PARAMETER;

> +    goto Fdt_Exit;

> +  }

> +

> +  ChosenNode = AndroidBootImgGetChosenNode(UpdatedFdtBase);

> +  if (!ChosenNode) {

> +    goto Fdt_Exit;

> +  }

> +

> +  Status = AndroidBootImgSetProperty64 (UpdatedFdtBase, ChosenNode,

> +                                        "linux,initrd-start",

> +                                        (UINT64)RamdiskData);

> +  if (EFI_ERROR (Status)) {

> +    goto Fdt_Exit;

> +  }

> +

> +  Status = AndroidBootImgSetProperty64 (UpdatedFdtBase, ChosenNode,

> +                                        "linux,initrd-end",

> +                                        (UINT64)(RamdiskData + RamdiskSize));

> +  if (EFI_ERROR (Status)) {

> +    goto Fdt_Exit;

> +  }

> +

> +  if (mAndroidBootImg->UpdateDtb) {

> +    Status = mAndroidBootImg->UpdateDtb (UpdatedFdtBase, &NewFdtBase);

> +    if (EFI_ERROR (Status)) {

> +      goto Fdt_Exit;

> +    }

> +  }

> +

> +  Status = gBS->InstallConfigurationTable (

> +                  &gFdtTableGuid,

> +                  (VOID *)(UINTN)NewFdtBase

> +                  );

> +  if (!EFI_ERROR (Status)) {

> +    return EFI_SUCCESS;

> +  }

> +

> +Fdt_Exit:

> +  gBS->FreePages (UpdatedFdtBase, EFI_SIZE_TO_PAGES (NewFdtSize));

> +  return Status;

> +}

> +

> +EFI_STATUS

> +AndroidBootImgBoot (

> +  IN VOID                            *Buffer,

> +  IN UINTN                            BufferSize

> +  )

> +{

> +  EFI_STATUS                          Status;

> +  VOID                               *Kernel;

> +  UINTN                               KernelSize;

> +  MEMORY_DEVICE_PATH                  KernelDevicePath;

> +  EFI_HANDLE                          ImageHandle;

> +  VOID                               *NewKernelArg;

> +  EFI_LOADED_IMAGE_PROTOCOL          *ImageInfo;

> +  VOID                               *RamdiskData;

> +  UINTN                               RamdiskSize;

> +  IN  VOID                           *FdtBase;

> +

> +  Status = gBS->LocateProtocol (&gAndroidBootImgProtocolGuid, NULL,

> +                                (VOID **) &mAndroidBootImg);

> +  if (EFI_ERROR (Status)) {

> +    return Status;

> +  }

> +

> +  Status = AndroidBootImgGetKernelInfo (

> +            Buffer,

> +            &Kernel,

> +            &KernelSize

> +            );

> +  if (EFI_ERROR (Status)) {

> +    return Status;

> +  }

> +

> +  NewKernelArg = AllocateZeroPool (ANDROID_BOOTIMG_KERNEL_ARGS_SIZE);

> +  if (NewKernelArg == NULL) {

> +    DEBUG ((DEBUG_ERROR, "Fail to allocate memory\n"));

> +    return EFI_OUT_OF_RESOURCES;

> +  }

> +

> +  Status = AndroidBootImgUpdateArgs (Buffer, NewKernelArg);

> +  if (EFI_ERROR (Status)) {

> +    FreePool (NewKernelArg);

> +    return Status;

> +  }

> +

> +  Status = AndroidBootImgGetRamdiskInfo (

> +            Buffer,

> +            &RamdiskData,

> +            &RamdiskSize

> +            );

> +  if (EFI_ERROR (Status)) {

> +    return Status;

> +  }

> +

> +  Status = AndroidBootImgLocateFdt (Buffer, &FdtBase);

> +  if (EFI_ERROR (Status)) {

> +    FreePool (NewKernelArg);

> +    return Status;

> +  }

> +

> +  Status = AndroidBootImgUpdateFdt (Buffer, FdtBase, RamdiskData, RamdiskSize);

> +  if (EFI_ERROR (Status)) {

> +    FreePool (NewKernelArg);

> +    return Status;

> +  }

> +

> +  KernelDevicePath = mMemoryDevicePathTemplate;

> +

> +  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, 0x10000, 0, NULL);

> +  // Start the image

> +  Status = gBS->StartImage (ImageHandle, NULL, NULL);

> +  // Clear the Watchdog Timer if the image returns

> +  gBS->SetWatchdogTimer (0, 0x10000, 0, NULL);

> +  return EFI_SUCCESS;

> +}

> diff --git a/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.inf b/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.inf

> new file mode 100644

> index 0000000..c92bac0

> --- /dev/null

> +++ b/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.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                      = AndroidBootImgLib

> +  FILE_GUID                      = ed3b8739-6fa7-4cb1-8aeb-2496f8fcaefa

> +  MODULE_TYPE                    = BASE

> +  VERSION_STRING                 = 1.0

> +  LIBRARY_CLASS                  = AndroidBootImgLib

> +

> +#

> +# The following information is for reference only and not required by the build tools.

> +#

> +#  VALID_ARCHITECTURES           = ARM AARCH64

> +#

> +

> +[Sources]

> +  AndroidBootImgLib.c

> +

> +[LibraryClasses]

> +  DebugLib

> +  FdtLib

> +  PrintLib

> +  UefiBootServicesTableLib

> +  UefiLib

> +

> +[Packages]

> +  EmbeddedPkg/EmbeddedPkg.dec

> +  MdePkg/MdePkg.dec

> +

> +[Protocols]

> +  gAndroidBootImgProtocolGuid

> +

> +[Guids]

> +  gFdtTableGuid

> -- 

> 1.9.1

> 

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-develdiff --git a/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.c b/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.c
index cb4fb6740a..bf33c64d25 100644
--- a/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.c
+++ b/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.c
@@ -259,7 +259,7 @@ AndroidBootImgLocateFdt (
 
 INTN
 AndroidBootImgGetChosenNode (
-  IN  EFI_PHYSICAL_ADDRESS   UpdatedFdtBase
+  IN  UINTN   UpdatedFdtBase
   )
 {
   IN  INTN                   ChosenNode;
@@ -277,10 +277,10 @@ AndroidBootImgGetChosenNode (
 
 EFI_STATUS
 AndroidBootImgSetProperty64 (
-  IN  EFI_PHYSICAL_ADDRESS   UpdatedFdtBase,
-  IN  INTN                   ChosenNode,
-  IN  CHAR8                 *PropertyName,
-  IN  UINT64                 Val
+  IN  UINTN   UpdatedFdtBase,
+  IN  INTN    ChosenNode,
+  IN  CHAR8   *PropertyName,
+  IN  UINT64  Val
   )
 {
   INTN                      Err;
@@ -334,7 +334,7 @@ AndroidBootImgUpdateFdt (
   }
 
   // Load the Original FDT tree into the new region
-  Err = fdt_open_into(FdtBase, (VOID*)UpdatedFdtBase, NewFdtSize);
+  Err = fdt_open_into(FdtBase, (VOID*)(UINTN)UpdatedFdtBase, NewFdtSize);
   if (Err) {
     DEBUG ((DEBUG_ERROR, "fdt_open_into(): %a\n", fdt_strerror (Err)));
     Status = EFI_INVALID_PARAMETER;
@@ -348,14 +348,14 @@ AndroidBootImgUpdateFdt (
 
   Status = AndroidBootImgSetProperty64 (UpdatedFdtBase, ChosenNode,
                                         "linux,initrd-start",
-                                        (UINT64)RamdiskData);
+                                        (UINTN)RamdiskData);
   if (EFI_ERROR (Status)) {
     goto Fdt_Exit;
   }
 
   Status = AndroidBootImgSetProperty64 (UpdatedFdtBase, ChosenNode,
                                         "linux,initrd-end",
-                                        (UINT64)(RamdiskData + RamdiskSize));
+                                        (UINTN)(RamdiskData + RamdiskSize));
   if (EFI_ERROR (Status)) {
     goto Fdt_Exit;
   }

Patch

diff --git a/EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.c b/EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.c
new file mode 100644
index 0000000..977167d
--- /dev/null
+++ b/EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.c
@@ -0,0 +1,140 @@ 
+/** @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/AndroidBootImgLib.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>
+
+/* Validate the node is media hard drive type */
+EFI_STATUS
+ValidateAndroidMediaDevicePath (
+  IN EFI_DEVICE_PATH                  *DevicePath
+  )
+{
+  EFI_DEVICE_PATH_PROTOCOL            *Node, *NextNode;
+
+  NextNode = DevicePath;
+  while (NextNode != NULL) {
+    Node = NextNode;
+    if (IS_DEVICE_PATH_NODE (Node, MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP)) {
+      return EFI_SUCCESS;
+    }
+    NextNode = NextDevicePathNode (Node);
+  }
+  return EFI_INVALID_PARAMETER;
+}
+
+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_BLOCK_IO_PROTOCOL               *BlockIo;
+  UINT32                              MediaId, BlockSize;
+  VOID                                *Buffer;
+  EFI_HANDLE                          Handle;
+  UINTN                               BootImgSize;
+
+  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);
+
+  Status = ValidateAndroidMediaDevicePath (DevicePath);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  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 ((DEBUG_ERROR, "Failed to get BlockIo: %r\n", Status));
+    return Status;
+  }
+
+  MediaId = BlockIo->Media->MediaId;
+  BlockSize = BlockIo->Media->BlockSize;
+  Buffer = AllocatePages (EFI_SIZE_TO_PAGES (sizeof(ANDROID_BOOTIMG_HEADER)));
+  if (Buffer == NULL) {
+    return EFI_BUFFER_TOO_SMALL;
+  }
+  /* Load header of boot.img */
+  Status = BlockIo->ReadBlocks (
+                      BlockIo,
+                      MediaId,
+                      0,
+                      BlockSize,
+                      Buffer
+                      );
+  Status = AndroidBootImgGetImgSize (Buffer, &BootImgSize);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed to get AndroidBootImg Size: %r\n", Status));
+    return Status;
+  }
+  BootImgSize = ALIGN_VALUE (BootImgSize, BlockSize);
+  FreePages (Buffer, EFI_SIZE_TO_PAGES (sizeof(ANDROID_BOOTIMG_HEADER)));
+
+  /* Both PartitionStart and PartitionSize are counted as block size. */
+  Buffer = AllocatePages (EFI_SIZE_TO_PAGES (BootImgSize));
+  if (Buffer == NULL) {
+    return EFI_BUFFER_TOO_SMALL;
+  }
+
+  /* Load header of boot.img */
+  Status = BlockIo->ReadBlocks (
+                      BlockIo,
+                      MediaId,
+                      0,
+                      BootImgSize,
+                      Buffer
+                      );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed to read blocks: %r\n", Status));
+    goto EXIT;
+  }
+
+  Status = AndroidBootImgBoot (Buffer, BootImgSize);
+
+EXIT:
+  return Status;
+}
diff --git a/EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.inf b/EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.inf
new file mode 100644
index 0000000..f1ee0bd
--- /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]
+  AndroidBootImgLib
+  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/EmbeddedPkg.dec b/EmbeddedPkg/EmbeddedPkg.dec
index 4cd528a..8ad2a84 100644
--- a/EmbeddedPkg/EmbeddedPkg.dec
+++ b/EmbeddedPkg/EmbeddedPkg.dec
@@ -80,6 +80,7 @@ 
   gAndroidFastbootPlatformProtocolGuid =  { 0x524685a0, 0x89a0, 0x11e3, {0x9d, 0x4d, 0xbf, 0xa9, 0xf6, 0xa4, 0x03, 0x08}}
   gUsbDeviceProtocolGuid =  { 0x021bd2ca, 0x51d2, 0x11e3, {0x8e, 0x56, 0xb7, 0x54, 0x17, 0xc7,  0x0b, 0x44 }}
   gPlatformGpioProtocolGuid = { 0x52ce9845, 0x5af4, 0x43e2, {0xba, 0xfd, 0x23, 0x08, 0x12, 0x54, 0x7a, 0xc2 }}
+  gAndroidBootImgProtocolGuid = { 0x9859bb19, 0x407c, 0x4f8b, {0xbc, 0xe1, 0xf8, 0xda, 0x65, 0x65, 0xf4, 0xa5 }}
 
 [PcdsFeatureFlag.common]
   gEmbeddedTokenSpaceGuid.PcdEmbeddedMacBoot|FALSE|BOOLEAN|0x00000001
@@ -181,6 +182,7 @@ 
   gEmbeddedTokenSpaceGuid.PcdAndroidFastbootUsbProductId|0xbeef|UINT32|0x00000023
   gEmbeddedTokenSpaceGuid.PcdAndroidFastbootTcpPort|1234|UINT32|0x00000024
 
+  gEmbeddedTokenSpaceGuid.PcdAndroidBootDevicePath|L""|VOID*|0x00000057
 
 [PcdsFixedAtBuild.ARM]
   gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize|32|UINT8|0x00000010
diff --git a/EmbeddedPkg/EmbeddedPkg.dsc b/EmbeddedPkg/EmbeddedPkg.dsc
index 16b368e..4a34e34 100644
--- a/EmbeddedPkg/EmbeddedPkg.dsc
+++ b/EmbeddedPkg/EmbeddedPkg.dsc
@@ -52,6 +52,7 @@ 
   DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
 
 
+  AndroidBootImgLib|EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.inf
   BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
   BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
   PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf
@@ -272,6 +273,7 @@ 
       TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf
   }
 
+  EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.inf
   EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.inf {
     <LibraryClasses>
       # It depends on BdsLib that depends on TimerLib
diff --git a/EmbeddedPkg/Include/Library/AndroidBootImgLib.h b/EmbeddedPkg/Include/Library/AndroidBootImgLib.h
index 06da751..331caa5 100644
--- a/EmbeddedPkg/Include/Library/AndroidBootImgLib.h
+++ b/EmbeddedPkg/Include/Library/AndroidBootImgLib.h
@@ -55,4 +55,17 @@  typedef struct {
  * and larger than boot header */
 #define IS_VALID_ANDROID_PAGE_SIZE(Val)   \
              (IS_POWER_OF_2(Val) && (Val > sizeof(ANDROID_BOOTIMG_HEADER)))
+
+EFI_STATUS
+AndroidBootImgGetImgSize (
+  IN  VOID    *BootImg,
+  OUT UINTN   *ImgSize
+  );
+
+EFI_STATUS
+AndroidBootImgBoot (
+  IN VOID                   *Buffer,
+  IN UINTN                   BufferSize
+  );
+
 #endif /* __ABOOTIMG_H__ */
diff --git a/EmbeddedPkg/Include/Protocol/AndroidBootImg.h b/EmbeddedPkg/Include/Protocol/AndroidBootImg.h
new file mode 100644
index 0000000..1c458d0
--- /dev/null
+++ b/EmbeddedPkg/Include/Protocol/AndroidBootImg.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 __ANDROID_BOOTIMG_PROTOCOL_H__
+#define __ANDROID_BOOTIMG_PROTOCOL_H__
+
+//
+// Protocol interface structure
+//
+typedef struct _ANDROID_BOOTIMG_PROTOCOL    ANDROID_BOOTIMG_PROTOCOL;
+
+//
+// Function Prototypes
+//
+typedef
+EFI_STATUS
+(EFIAPI *ANDROID_BOOTIMG_APPEND_KERNEL_ARGS) (
+  IN CHAR16            *Args,
+  IN UINTN              Size
+  );
+
+typedef
+EFI_STATUS
+(EFIAPI *ANDROID_BOOTIMG_UPDATE_DTB) (
+  IN  EFI_PHYSICAL_ADDRESS    OrigDtbBase;
+  OUT EFI_PHYSICAL_ADDRESS   *NewDtbBase;
+  );
+
+struct _ANDROID_BOOTIMG_PROTOCOL {
+  ANDROID_BOOTIMG_APPEND_KERNEL_ARGS        AppendArgs;
+  ANDROID_BOOTIMG_UPDATE_DTB                UpdateDtb;
+};
+
+extern EFI_GUID gAndroidBootImgProtocolGuid;
+
+#endif /* __ANDROID_BOOTIMG_PROTOCOL_H__ */
diff --git a/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.c b/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.c
new file mode 100644
index 0000000..cb4fb67
--- /dev/null
+++ b/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.c
@@ -0,0 +1,471 @@ 
+/** @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 <libfdt.h>
+#include <Library/AndroidBootImgLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Protocol/AndroidBootImg.h>
+#include <Protocol/LoadedImage.h>
+
+#include <libfdt.h>
+
+#define FDT_ADDITIONAL_ENTRIES_SIZE 0x400
+
+typedef struct {
+  MEMMAP_DEVICE_PATH                      Node1;
+  EFI_DEVICE_PATH_PROTOCOL                End;
+} MEMORY_DEVICE_PATH;
+
+STATIC ANDROID_BOOTIMG_PROTOCOL                 *mAndroidBootImg;
+
+STATIC CONST MEMORY_DEVICE_PATH mMemoryDevicePathTemplate =
+{
+  {
+    {
+      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
+AndroidBootImgGetImgSize (
+  IN  VOID    *BootImg,
+  OUT UINTN   *ImgSize
+  )
+{
+  ANDROID_BOOTIMG_HEADER   *Header;
+
+  Header = (ANDROID_BOOTIMG_HEADER *) BootImg;
+
+  if (AsciiStrnCmp ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC,
+                    ANDROID_BOOT_MAGIC_LENGTH) != 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  /* The page size is not specified, but it should be power of 2 at least */
+  ASSERT (IS_VALID_ANDROID_PAGE_SIZE (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
+AndroidBootImgGetKernelInfo (
+  IN  VOID    *BootImg,
+  OUT VOID   **Kernel,
+  OUT UINTN   *KernelSize
+  )
+{
+  ANDROID_BOOTIMG_HEADER   *Header;
+
+  Header = (ANDROID_BOOTIMG_HEADER *) BootImg;
+
+  if (AsciiStrnCmp ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC,
+                    ANDROID_BOOT_MAGIC_LENGTH) != 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Header->KernelSize == 0) {
+    return EFI_NOT_FOUND;
+  }
+
+  ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize));
+
+  *KernelSize = Header->KernelSize;
+  *Kernel = BootImg + Header->PageSize;
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+AndroidBootImgGetRamdiskInfo (
+  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 ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC,
+                    ANDROID_BOOT_MAGIC_LENGTH) != 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ASSERT (IS_VALID_ANDROID_PAGE_SIZE (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
+AndroidBootImgGetSecondBootLoaderInfo (
+  IN  VOID    *BootImg,
+  OUT VOID   **Second,
+  OUT UINTN   *SecondSize
+  )
+{
+  ANDROID_BOOTIMG_HEADER   *Header;
+  UINTN                     BootImgBytePtr;
+
+  // Cast to UINT8 so we can do pointer arithmetic
+  BootImgBytePtr = (UINTN) BootImg;
+
+  Header = (ANDROID_BOOTIMG_HEADER *) BootImg;
+
+  if (AsciiStrnCmp ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC,
+                    ANDROID_BOOT_MAGIC_LENGTH) != 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ASSERT (IS_VALID_ANDROID_PAGE_SIZE (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
+AndroidBootImgGetKernelArgs (
+  IN  VOID    *BootImg,
+  OUT CHAR8   *KernelArgs
+  )
+{
+  ANDROID_BOOTIMG_HEADER   *Header;
+
+  Header = (ANDROID_BOOTIMG_HEADER *) BootImg;
+  AsciiStrnCpyS (KernelArgs, ANDROID_BOOTIMG_KERNEL_ARGS_SIZE, Header->KernelArgs,
+    ANDROID_BOOTIMG_KERNEL_ARGS_SIZE);
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+AndroidBootImgGetFdt (
+  IN  VOID                  *BootImg,
+  IN  VOID                 **FdtBase
+  )
+{
+  UINTN                      SecondLoaderSize;
+  EFI_STATUS                 Status;
+
+  /* Check whether FDT is located in second boot region as some vendor do so,
+   * because second loader is never used as far as I know. */
+  Status = AndroidBootImgGetSecondBootLoaderInfo (
+          BootImg,
+          FdtBase,
+          &SecondLoaderSize
+          );
+  return Status;
+}
+
+EFI_STATUS
+AndroidBootImgUpdateArgs (
+  IN  VOID                  *BootImg,
+  OUT VOID                  *KernelArgs
+  )
+{
+  CHAR8                      ImageKernelArgs[ANDROID_BOOTIMG_KERNEL_ARGS_SIZE];
+  EFI_STATUS                 Status;
+
+  // Get kernel arguments from Android boot image
+  Status = AndroidBootImgGetKernelArgs (BootImg, ImageKernelArgs);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  AsciiStrToUnicodeStrS (ImageKernelArgs, KernelArgs,
+                         ANDROID_BOOTIMG_KERNEL_ARGS_SIZE >> 1);
+  // Append platform kernel arguments
+  if(mAndroidBootImg->AppendArgs) {
+    Status = mAndroidBootImg->AppendArgs (KernelArgs,
+                                    ANDROID_BOOTIMG_KERNEL_ARGS_SIZE);
+  }
+  return Status;
+}
+
+EFI_STATUS
+AndroidBootImgLocateFdt (
+  IN  VOID                  *BootImg,
+  IN  VOID                 **FdtBase
+  )
+{
+  INTN                       Err;
+  EFI_STATUS                 Status;
+
+  Status = EfiGetSystemConfigurationTable (&gFdtTableGuid, FdtBase);
+  if (!EFI_ERROR (Status)) {
+    return EFI_SUCCESS;
+  }
+
+  Status = AndroidBootImgGetFdt (BootImg, FdtBase);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  Err = fdt_check_header (*FdtBase);
+  if (Err != 0) {
+    DEBUG ((DEBUG_ERROR, "ERROR: Device Tree header not valid (Err:%d)\n",
+           Err));
+    return EFI_INVALID_PARAMETER;
+  }
+  return EFI_SUCCESS;
+}
+
+INTN
+AndroidBootImgGetChosenNode (
+  IN  EFI_PHYSICAL_ADDRESS   UpdatedFdtBase
+  )
+{
+  IN  INTN                   ChosenNode;
+
+  ChosenNode = fdt_subnode_offset ((CONST VOID *)UpdatedFdtBase, 0, "chosen");
+  if (ChosenNode < 0) {
+    ChosenNode = fdt_add_subnode((VOID *)UpdatedFdtBase, 0, "chosen");
+      if (ChosenNode < 0) {
+        DEBUG ((DEBUG_ERROR, "Fail to find fdt node chosen!\n"));
+        return 0;
+    }
+  }
+  return ChosenNode;
+}
+
+EFI_STATUS
+AndroidBootImgSetProperty64 (
+  IN  EFI_PHYSICAL_ADDRESS   UpdatedFdtBase,
+  IN  INTN                   ChosenNode,
+  IN  CHAR8                 *PropertyName,
+  IN  UINT64                 Val
+  )
+{
+  INTN                      Err;
+  struct fdt_property      *Property;
+  int                       Len;
+
+  Property = fdt_get_property_w((VOID *)UpdatedFdtBase, ChosenNode,
+                            PropertyName, &Len);
+  if (NULL == Property && Len == -FDT_ERR_NOTFOUND) {
+    Val = cpu_to_fdt64(Val);
+    Err = fdt_appendprop ((VOID *)UpdatedFdtBase, ChosenNode,
+                          PropertyName, &Val, sizeof (UINT64));
+    if (Err) {
+      DEBUG ((DEBUG_ERROR, "fdt_appendprop() fail: %a\n", fdt_strerror (Err)));
+      return EFI_INVALID_PARAMETER;
+    }
+  } else if (Property != NULL) {
+    Err = fdt_setprop_u64((VOID *)UpdatedFdtBase, ChosenNode,
+                          PropertyName, Val);
+    if (Err) {
+      DEBUG ((DEBUG_ERROR, "fdt_setprop_u64() fail: %a\n", fdt_strerror (Err)));
+      return EFI_INVALID_PARAMETER;
+    }
+  } else {
+    DEBUG ((DEBUG_ERROR, "Failed to set fdt Property %a\n", PropertyName));
+    return EFI_INVALID_PARAMETER;
+  }
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+AndroidBootImgUpdateFdt (
+  IN  VOID                  *BootImg,
+  IN  VOID                  *FdtBase,
+  IN  VOID                  *RamdiskData,
+  IN  UINTN                  RamdiskSize
+  )
+{
+  INTN                       ChosenNode, Err, NewFdtSize;
+  EFI_STATUS                 Status;
+  EFI_PHYSICAL_ADDRESS       UpdatedFdtBase, NewFdtBase;
+
+  NewFdtSize = (UINTN)fdt_totalsize (FdtBase)
+               + FDT_ADDITIONAL_ENTRIES_SIZE;
+  Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData,
+                  EFI_SIZE_TO_PAGES (NewFdtSize), &UpdatedFdtBase);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_WARN, "Warning: Failed to reallocate FDT, err %d.\n",
+           Status));
+    return Status;
+  }
+
+  // Load the Original FDT tree into the new region
+  Err = fdt_open_into(FdtBase, (VOID*)UpdatedFdtBase, NewFdtSize);
+  if (Err) {
+    DEBUG ((DEBUG_ERROR, "fdt_open_into(): %a\n", fdt_strerror (Err)));
+    Status = EFI_INVALID_PARAMETER;
+    goto Fdt_Exit;
+  }
+
+  ChosenNode = AndroidBootImgGetChosenNode(UpdatedFdtBase);
+  if (!ChosenNode) {
+    goto Fdt_Exit;
+  }
+
+  Status = AndroidBootImgSetProperty64 (UpdatedFdtBase, ChosenNode,
+                                        "linux,initrd-start",
+                                        (UINT64)RamdiskData);
+  if (EFI_ERROR (Status)) {
+    goto Fdt_Exit;
+  }
+
+  Status = AndroidBootImgSetProperty64 (UpdatedFdtBase, ChosenNode,
+                                        "linux,initrd-end",
+                                        (UINT64)(RamdiskData + RamdiskSize));
+  if (EFI_ERROR (Status)) {
+    goto Fdt_Exit;
+  }
+
+  if (mAndroidBootImg->UpdateDtb) {
+    Status = mAndroidBootImg->UpdateDtb (UpdatedFdtBase, &NewFdtBase);
+    if (EFI_ERROR (Status)) {
+      goto Fdt_Exit;
+    }
+  }
+
+  Status = gBS->InstallConfigurationTable (
+                  &gFdtTableGuid,
+                  (VOID *)(UINTN)NewFdtBase
+                  );
+  if (!EFI_ERROR (Status)) {
+    return EFI_SUCCESS;
+  }
+
+Fdt_Exit:
+  gBS->FreePages (UpdatedFdtBase, EFI_SIZE_TO_PAGES (NewFdtSize));
+  return Status;
+}
+
+EFI_STATUS
+AndroidBootImgBoot (
+  IN VOID                            *Buffer,
+  IN UINTN                            BufferSize
+  )
+{
+  EFI_STATUS                          Status;
+  VOID                               *Kernel;
+  UINTN                               KernelSize;
+  MEMORY_DEVICE_PATH                  KernelDevicePath;
+  EFI_HANDLE                          ImageHandle;
+  VOID                               *NewKernelArg;
+  EFI_LOADED_IMAGE_PROTOCOL          *ImageInfo;
+  VOID                               *RamdiskData;
+  UINTN                               RamdiskSize;
+  IN  VOID                           *FdtBase;
+
+  Status = gBS->LocateProtocol (&gAndroidBootImgProtocolGuid, NULL,
+                                (VOID **) &mAndroidBootImg);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = AndroidBootImgGetKernelInfo (
+            Buffer,
+            &Kernel,
+            &KernelSize
+            );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  NewKernelArg = AllocateZeroPool (ANDROID_BOOTIMG_KERNEL_ARGS_SIZE);
+  if (NewKernelArg == NULL) {
+    DEBUG ((DEBUG_ERROR, "Fail to allocate memory\n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Status = AndroidBootImgUpdateArgs (Buffer, NewKernelArg);
+  if (EFI_ERROR (Status)) {
+    FreePool (NewKernelArg);
+    return Status;
+  }
+
+  Status = AndroidBootImgGetRamdiskInfo (
+            Buffer,
+            &RamdiskData,
+            &RamdiskSize
+            );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = AndroidBootImgLocateFdt (Buffer, &FdtBase);
+  if (EFI_ERROR (Status)) {
+    FreePool (NewKernelArg);
+    return Status;
+  }
+
+  Status = AndroidBootImgUpdateFdt (Buffer, FdtBase, RamdiskData, RamdiskSize);
+  if (EFI_ERROR (Status)) {
+    FreePool (NewKernelArg);
+    return Status;
+  }
+
+  KernelDevicePath = mMemoryDevicePathTemplate;
+
+  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, 0x10000, 0, NULL);
+  // Start the image
+  Status = gBS->StartImage (ImageHandle, NULL, NULL);
+  // Clear the Watchdog Timer if the image returns
+  gBS->SetWatchdogTimer (0, 0x10000, 0, NULL);
+  return EFI_SUCCESS;
+}
diff --git a/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.inf b/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.inf
new file mode 100644
index 0000000..c92bac0
--- /dev/null
+++ b/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.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                      = AndroidBootImgLib
+  FILE_GUID                      = ed3b8739-6fa7-4cb1-8aeb-2496f8fcaefa
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = AndroidBootImgLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = ARM AARCH64
+#
+
+[Sources]
+  AndroidBootImgLib.c
+
+[LibraryClasses]
+  DebugLib
+  FdtLib
+  PrintLib
+  UefiBootServicesTableLib
+  UefiLib
+
+[Packages]
+  EmbeddedPkg/EmbeddedPkg.dec
+  MdePkg/MdePkg.dec
+
+[Protocols]
+  gAndroidBootImgProtocolGuid
+
+[Guids]
+  gFdtTableGuid