public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Jun Nie <jun.nie@linaro.org>
To: Leif Lindholm <leif.lindholm@linaro.org>
Cc: haojian.zhuang@linaro.org, ard.biesheuvel@linaro.org,
	edk2-devel@lists.01.org, linaro-uefi@lists.linaro.org,
	shawn.guo@linaro.org, jason.liu@linaro.org
Subject: Re: [PATCH v3 1/2] EmbeddedPkg/AndroidBoot: boot android kernel from storage
Date: Fri, 28 Jul 2017 22:18:49 +0800	[thread overview]
Message-ID: <96dd3ea5-b99e-5b12-ed47-160310156ab9@linaro.org> (raw)
In-Reply-To: <20170728130643.GP1501@bivouac.eciton.net>

On 2017年07月28日 21:06, Leif Lindholm wrote:
> On Fri, Jul 28, 2017 at 05:47:46PM +0800, Jun Nie wrote:
>> On 2017年07月27日 22:09, Leif Lindholm wrote:
>>> On Thu, Jul 27, 2017 at 06:07:19PM +0800, Jun Nie wrote:
>>>> Add an android kernel loader that could load kernel from storage
>>>> device. This patch is from Haojian's code as below link. The minor
>>>> change is that alternative dtb is searched in second loader binary
>>>> of Android bootimage if dtb is not found after Linux kernel.
>>>> https://patches.linaro.org/patch/94683/
>>>>
>>>> This android boot image BDS add addtitional cmdline/dtb/ramfs
>>>> support besides kernel that is introduced by Android boot header.
>>>
>>> Getting there. A few more comments below.
>>>
>>>> Contributed-under: TianoCore Contribution Agreement 1.0
>>>> Signed-off-by: Jun Nie <jun.nie@linaro.org>
>>>> ---
>>>>   ArmPkg/Include/Library/BdsLib.h                    |   3 +
>>>>   ArmPkg/Library/BdsLib/BdsFilePath.c                |   3 -
>>>>   .../Application/AndroidBoot/AndroidBootApp.c       | 127 +++++++
>>>>   .../Application/AndroidBoot/AndroidBootApp.inf     |  64 ++++
>>>>   .../Application/AndroidFastboot/AndroidBootImg.c   |  35 +-
>>>>   .../AndroidFastboot/AndroidFastbootApp.h           |   1 +
>>>>   .../AndroidFastboot/Arm/BootAndroidBootImg.c       |   2 +-
>>>>   EmbeddedPkg/Include/Library/AndroidBootImgLib.h    |  67 ++++
>>>>   EmbeddedPkg/Include/Protocol/AndroidBootImg.h      |  47 +++
>>>>   .../Library/AndroidBootImgLib/AndroidBootImgLib.c  | 419 +++++++++++++++++++++
>>>>   .../AndroidBootImgLib/AndroidBootImgLib.inf        |  48 +++
>>>>   11 files changed, 782 insertions(+), 34 deletions(-)
>>>>   create mode 100644 EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.c
>>>>   create mode 100644 EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.inf
>>>>   create mode 100644 EmbeddedPkg/Include/Library/AndroidBootImgLib.h
>>>>   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/Application/AndroidBoot/AndroidBootApp.c b/EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.c
>>>> new file mode 100644
>>>> index 0000000..2de1d8a
>>>> --- /dev/null
>>>> +++ b/EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.c
>>>> @@ -0,0 +1,127 @@
>>>> +/** @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>
>>>> +
>>>> +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) {
>>>
>>> Should this not be while (NextNode != NULL), with some check that the
>>> node was found before progressing?
>>
>> (NextNode != NULL) is valid check.
>> The code check node before progressing as below, doesn't it?
> 
> My point is that if you never match the "if (IS_DEVICE_PATH_NODE "
> condition, this loop will never terminate.
> 
> And if we update the loop condition to fix that, we end up calling
> LocateDevicePath with a known bad parameter.

Yeah, besides the check in while(), I should add check before while loop.
> 
>>>
>>>> +    Node = NextNode;
>>>> +    if (IS_DEVICE_PATH_NODE (Node, MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP)) {
>>>> +      break;
>>>> +    }
>>>> +    NextNode = NextDevicePathNode (Node);
>>>> +  }
>>>> +
>>>> +  Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid,
>>>> +                                  &DevicePath, &Handle);
>>>
>>> And should this not use &Node rather than &DevicePath?
>> I suppose we should return error if no MEDIA_HARDDRIVE_DP node is found. I
>> ever did test and found original DevicePath should be used here as a full
>> device path, otherwise the boot image cannot be found.
> 
> So does this mean that the section that initializes "Node" to a
> MEDIA_HARDDRIVE_DP is only there to validate DevicePath?
> If so, I think it should be split out into a static helper function,
> called ValidateDevicePath or similar, with a description of what
> condition it is trying to verify.

Yes, I think it is a validation. Will split it to a helper function.
> 
>>>
>>>> +  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 (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 = AbootimgGetImgSize (Buffer, &Size);
>>>
>>> AndroidBootImgGetImageSize.
>>
>> Will do.
>>>
>>> (The "img" would normally be expected to be expanded to "Image", but
>>> it appears "boot.img" is basically the official name for this format.)
>>>
>>>> +  if (EFI_ERROR (Status)) {
>>>> +    DEBUG ((EFI_D_ERROR, "Failed to get Abootimg Size: %r\n", Status));
>>>> +    return Status;
>>>> +  }
>>>> +  Size = ALIGN_VALUE (Size, 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 (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);
>>>
>>> AndroidBootImgBoot.
>>
>> Will do.
>>>
>>>> +
>>>> +EXIT:
>>>> +  return Status;
>>>> +}
> 
> 
>>>> diff --git a/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.c b/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.c
>>>> new file mode 100644
>>>> index 0000000..72c6322
>>>> --- /dev/null
>>>> +++ b/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.c
>>>> @@ -0,0 +1,419 @@
>>>> +/** @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 ABOOTIMG_PROTOCOL                 *mAbootimg;
>>>
>>> mAndroidBootImg.
>>
>> Will do.
>>>
>>>> +
>>>> +STATIC CONST MEMORY_DEVICE_PATH MemoryDevicePathTemplate =
>>>
>>> Should also have an 'm'-prefix.
>>
>> Will do. But what 'm' prefix stand for?
>>>
>>>> +{
>>>> +  {
>>>> +    {
>>>> +      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 (
>>>
>>> AndroidBootImgGetImageSize.
>>
>> Will do.
>>>
>>>> +  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
>>>> +AbootimgGetKernelInfo (
>>>
>>> AndroidBootImgGetKernelInfo.
>>
>> Will do.
>>>
>>>> +  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
>>>> +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 ((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
>>>> +AbootimgGetSecondBootLoaderInfo (
>>>
>>> AndroidBootImg...
>>
>> Will do.
>>>
>>>> +  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 ((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
>>>> +AbootimgGetKernelArgs (
>>>
>>> AndroidBootImg...
>>
>> Will do.
>>>
>>>> +  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
>>>> +AbootimgGetFdt (
>>>
>>> AndroidBootImg...
>>
>> Will do.
>>>
>>>> +  IN  VOID                  *BootImg,
>>>> +  IN  VOID                  **FdtBase
>>>> +  )
>>>> +{
>>>> +  UINTN                      SecondLoaderSize;
>>>> +  EFI_STATUS                 Status;
>>>> +
>>>> +  /* Check whether FDT is located in second boot loader as some vendor do so,
>>>
>>> It would be more correct to say "second boot loader region" than
>>> "second boot loader".
>>>
>>>> +   * because second loader is never used as far as I know. */
>>>> +  Status = AbootimgGetSecondBootLoaderInfo (
>>>> +          BootImg,
>>>> +          FdtBase,
>>>> +          &SecondLoaderSize
>>>> +          );
>>>> +  return Status;
>>>> +}
>>>> +
>>>> +EFI_STATUS
>>>> +AbootimgUpdateArgsFdt (
>>>
>>> AndroidBootImgUpdateKernelArgs
>>> (The arguments always come through Fdt, so I do not feel that needs to
>>> be explicitly pointed out.)
>> Command line come from Android boot image cmdline field, not from fdt in
>> most cases, if not all. I will split argument update function too.
>>>
>>> General comment: this function needs to be broken down into several
>>> smaller helper functions:
>>> - extract kernel arguments from boot.img
>>> - extract ramdisk information from boot.img
>>> - locate FDT
>>> - update FDT
>>
>> Will do.
>>>
>>>> +  IN  VOID                  *BootImg,
>>>> +  OUT VOID                  *KernelArgs
>>>> +  )
>>>> +{
>>>> +  VOID                      *Ramdisk;
>>>
>>> RamdiskData?
>> Yes, Ramdisk data start address.
>>>
>>>> +  UINT64                     Ramdisk64, RamdiskEnd64;
>>>
>>> RamdiskStart, RamDiskEnd?
>>
>> Yes, will do.
>>>
>>>> +  UINTN                      RamdiskSize;
>>>> +  CHAR8                      ImgKernelArgs[ANDROID_BOOTIMG_KERNEL_ARGS_SIZE];
>>>
>>> ImageKernelArgs
>>> or
>>> BootImgKernelArgs
>>
>> Will do.
>>>
>>>> +  INTN                       Err, NewFdtSize, chosen_node;
>>>
>>> ChosenNode
>>
>> Will do. I had thought fdt library related code shall follow the library
>> coding style :)
> 
> Yes, this is a tricky area.
> I'm considering putting together a wrapper library for common DT
> operations to abstract this away. But for now, I prefer keeping to
> TianoCore coding style everywhere except as is needed to call libfdt.
> 
>>>
>>>> +  EFI_STATUS                 Status;
>>>> +  EFI_PHYSICAL_ADDRESS       FdtBase, UpdatedFdtBase, NewFdtBase;
>>>> +  struct fdt_property       *prop;
>>>
>>> *Property.
>>
>> Will do.
>>>
>>>> +  int                        len;
>>>
>>> INTN Len;
>>
>> Will do.
>>>
>>>> +
>>>> +  Status = gBS->LocateProtocol (&gAndroidBootImgProtocolGuid, NULL,
>>>> +                                (VOID **) &mAbootimg);
>>>> +  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,
>>>> +                         ANDROID_BOOTIMG_KERNEL_ARGS_SIZE >> 1);
>>>> +  // Append platform kernel arguments
>>>> +  if(mAbootimg->AppendArgs) {
>>>> +    Status = mAbootimg->AppendArgs (KernelArgs,
>>>> +                                    ANDROID_BOOTIMG_KERNEL_ARGS_SIZE);
>>>> +    if (EFI_ERROR (Status)) {
>>>> +      return Status;
>>>> +    }
>>>> +  }
>>>> +
>>>> +  Status = EfiGetSystemConfigurationTable (&gFdtTableGuid, (VOID **)&FdtBase);
>>>> +  if (!EFI_ERROR (Status)) {
>>>
>>> Should this not be
>>>    if (EFI_ERROR (Status) && Status != EFI_NOT_FOUND)
>>> ?
>>
>> I mean, if fdt is found, we shall return to avoid installing another fdt.
> 
> An FDT presented to you by firmware is just the hardware description.
> Any command line or initrd updates that are required will still need
> to happen in order to boot. So the same manipulations that happen to
> the DT embedded in boot.img need to happen to one presented via a
> configuration table.
> 
>> But actually, I expect fdt is tied with kernel in Android boot image in
>> standard Android boot image usage cases.
>> Though it is agreed to decouple fdt and kernel in community in 2013,
>> Android boot image format has been decided several years before that :) .
>>
>> We can make change in future if Android boot image usage case changes.
>> Maybe I can add a warning message to highlight the new case.
> 
> No.
> 
> We can tolerate booting broken existing images, but we should not
> design to intentionally break things ourselves.
> 
> I guess as this is an application, you could even add a command-line
> option to let you override an existing registered DT with one embedded
> in boot.img.
> 
> But ignoring an existing registered DT is not an option.

So you suggest to override existing registered fdt data with the one in 
boot.img. How to add a command-line, in kernel argument that is embedded 
in boot.img? It is a bit strange if so.
I prefer to override existing registered fdt data directly in current 
Android boot image usage.
> 
>>>> +    return Status;
>>>> +  }
>>>> +
>>>> +  Status = AbootimgGetFdt (BootImg, (VOID **)&FdtBase);
>>>> +  if (EFI_ERROR (Status)) {
>>>> +    return Status;
>>>> +  }
>>>> +  Err = fdt_check_header ((VOID*)(UINTN)FdtBase);
>>>> +  if (Err != 0) {
>>>> +    DEBUG ((DEBUG_ERROR, "ERROR: Device Tree header not valid (Err:%d)\n",
>>>> +           Err));
>>>> +    return EFI_INVALID_PARAMETER;
>>>> +  }
>>>> +
>>>> +  Status = AbootimgGetRamdiskInfo (
>>>> +            BootImg,
>>>> +            &Ramdisk,
>>>> +            &RamdiskSize
>>>> +            );
>>>> +  if (EFI_ERROR (Status)) {
>>>> +    return Status;
>>>> +  }
>>>> +
>>>> +  NewFdtSize = (UINTN)fdt_totalsize ((VOID*)(UINTN)(FdtBase))
>>>> +               + FDT_ADDITIONAL_ENTRIES_SIZE;
>>>> +  Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData,
>>>> +                  EFI_SIZE_TO_PAGES (NewFdtSize), &UpdatedFdtBase);
>>>> +  if (EFI_ERROR (Status)) {
>>>> +    DEBUG ((EFI_D_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((VOID*)FdtBase, (VOID*)UpdatedFdtBase, NewFdtSize);
>>>> +  if (Err) {
>>>> +    DEBUG ((EFI_D_ERROR, "fdt_open_into(): %a\n", fdt_strerror (Err)));
>>>> +    Status = EFI_INVALID_PARAMETER;
>>>> +    goto Fdt_Exit;
>>>> +  }
>>>> +
>>>> +  Ramdisk64 = cpu_to_fdt64((UINT64)Ramdisk);
>>>> +  RamdiskEnd64 = cpu_to_fdt64((UINT64)(Ramdisk + RamdiskSize));
>>>> +
>>>> +  chosen_node = fdt_subnode_offset ((const void *)UpdatedFdtBase, 0, "chosen");
>>>> +  if (chosen_node < 0) {
>>>> +    chosen_node = fdt_add_subnode((void *)UpdatedFdtBase, 0, "chosen");
>>>> +      if (chosen_node < 0) {
>>>> +        DEBUG ((EFI_D_ERROR, "Failed to find chosen node in fdt!\n"));
>>>> +        goto Fdt_Exit;
>>>> +    }
>>>> +  }
>>>> +  prop = fdt_get_property_w((void *)UpdatedFdtBase, chosen_node,
>>>> +                            "linux,initrd-start", &len);
>>>> +  if (NULL == prop && len == -FDT_ERR_NOTFOUND) {
>>>> +    fdt_appendprop ((void *)UpdatedFdtBase, chosen_node,
>>>> +                    "linux,initrd-start", &Ramdisk64, sizeof (UINT64));
>>>> +  } else if (prop != NULL) {
>>>> +    fdt_setprop_u64((void *)UpdatedFdtBase, chosen_node,
>>>> +                    "linux,initrd-start", (uint64_t)Ramdisk64);
>>>> +  } else {
>>>> +    DEBUG ((EFI_D_ERROR, "Failed to append fdt prop initrd-start\n",
>>>> +           fdt_strerror (Err)));
>>>> +    Status = EFI_INVALID_PARAMETER;
>>>> +    goto Fdt_Exit;
>>>> +  }
>>>> +
>>>> +  prop = fdt_get_property_w((void *)UpdatedFdtBase, chosen_node,
>>>> +                            "linux,initrd-end", &len);
>>>> +  if (NULL == prop && len == -FDT_ERR_NOTFOUND) {
>>>> +    fdt_appendprop ((void *)UpdatedFdtBase, chosen_node,
>>>> +                    "linux,initrd-end", &RamdiskEnd64, sizeof (UINT64));
>>>> +  } else if (prop != NULL) {
>>>> +    fdt_setprop_u64((void *)UpdatedFdtBase, chosen_node,
>>>> +                    "linux,initrd-end", (uint64_t)RamdiskEnd64);
>>>> +  } else {
>>>> +    DEBUG ((EFI_D_ERROR, "Failed to append fdt prop initrd-end\n",
>>>> +           fdt_strerror (Err)));
>>>> +    Status = EFI_INVALID_PARAMETER;
>>>> +    goto Fdt_Exit;
>>>> +  }
>>>> +
>>>> +  if ( mAbootimg->UpdateDtb) {
>>>> +    Status = mAbootimg->UpdateDtb (UpdatedFdtBase, &NewFdtBase);
>>>> +    if (EFI_ERROR (Status)) {
>>>> +      goto Fdt_Exit;
>>>> +    }
>>>> +  }
>>>> +
>>>> +  //
>>>> +  // Sanity checks on the new FDT blob.
>>>> +  //
>>>> +  Err = fdt_check_header ((VOID*)(UINTN)NewFdtBase);
>>>
>>> I don't think this test is needed. The state of the FDT is completely
>>> under our control at this point. The only thing it could uncover would
>>> be a stray pointer, or a bug in libfdt.
>>
>> Yes. We should check just after Fdt is read from boot image.
> 
> Or existing in configuration table.
> (As is already done.)
> 
> /
>      Leif
> 
>>>
>>>> +  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
>>>> +                  );
>>>> +  if (EFI_ERROR (Status)) {
>>>> +    goto Fdt_Exit;
>>>> +  }
>>>> +  return Status;
>>>
>>> This is preference only, but I think
>>>    if (!EFI_ERROR (Status)) {
>>>      return EFI_SUCCESS;
>>>    }
>>> would be more clear.
>>
>> Will do.
>>>
>>>> +
>>>> +Fdt_Exit:
>>>> +  gBS->FreePages (UpdatedFdtBase, EFI_SIZE_TO_PAGES (NewFdtSize));
>>>> +  return Status;
>>>> +}
>>>> +
>>>> +EFI_STATUS
>>>> +AbootimgBoot (
>>>
>>> AndroidBootImgBoot
>>
>> Will do.
>>>
>>>> +  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;
>>>> +
>>>> +  Status = AbootimgGetKernelInfo (
>>>> +            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 = AbootimgUpdateArgsFdt (Buffer, NewKernelArg);
>>>> +  if (EFI_ERROR (Status)) {
>>>> +    FreePool (NewKernelArg);
>>>> +    return EFI_INVALID_PARAMETER;
>>>
>>> return Status?
>>>
>> Will do.
>>> /
>>>      Leif
>>>
>>>> +  }
>>>> +
>>>> +  KernelDevicePath = MemoryDevicePathTemplate;
>>>> +
>>>> +  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;
>>>> +}



  reply	other threads:[~2017-07-28 14:16 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-07-27 10:07 [PATCH v3 1/2] EmbeddedPkg/AndroidBoot: boot android kernel from storage Jun Nie
2017-07-27 10:07 ` [PATCH v3 2/2] EmbeddedPkg: add Android boot device path and guid Jun Nie
2017-07-27 14:10   ` Leif Lindholm
2017-07-27 14:09 ` [PATCH v3 1/2] EmbeddedPkg/AndroidBoot: boot android kernel from storage Leif Lindholm
2017-07-28  9:47   ` Jun Nie
2017-07-28 13:06     ` Leif Lindholm
2017-07-28 14:18       ` Jun Nie [this message]
2017-07-28 14:52         ` Leif Lindholm
2017-07-30 14:22           ` Jun Nie
2017-07-30 17:10             ` Leif Lindholm

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=96dd3ea5-b99e-5b12-ed47-160310156ab9@linaro.org \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox