diff mbox series

[Linaro-uefi,v4,5/5] Platforms/Hisilicon/HiKey: add fastboot driver

Message ID 1487170499-22374-6-git-send-email-haojian.zhuang@linaro.org
State New
Headers show
Series add drivers for Android Fastboot App on HiKey | expand

Commit Message

Haojian Zhuang Feb. 15, 2017, 2:54 p.m. UTC
Support HiKey Fastboot driver for Fastboot App.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
---
 Platforms/Hisilicon/HiKey/HiKey.dec                |   1 +
 .../HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.c      | 672 +++++++++++++++++++++
 .../HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.inf    |  61 ++
 .../Hisilicon/HiKey/Include/Guid/HiKeyVariable.h   |  24 +
 4 files changed, 758 insertions(+)
 create mode 100644 Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.c
 create mode 100644 Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.inf
 create mode 100644 Platforms/Hisilicon/HiKey/Include/Guid/HiKeyVariable.h

Comments

Leif Lindholm March 1, 2017, 3:13 p.m. UTC | #1
On Wed, Feb 15, 2017 at 10:54:59PM +0800, Haojian Zhuang wrote:
> Support HiKey Fastboot driver for Fastboot App.
> 

I asked a few questions on v3, which I received no replies to.
Here I asked:
---
Question: I notice this version deletes the SPARSE_HEADER support,
which was one of the main differences compared to VEXpress driver.
Is this something you plan to introduce in future?
---

> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
> ---
>  Platforms/Hisilicon/HiKey/HiKey.dec                |   1 +
>  .../HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.c      | 672 +++++++++++++++++++++
>  .../HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.inf    |  61 ++
>  .../Hisilicon/HiKey/Include/Guid/HiKeyVariable.h   |  24 +
>  4 files changed, 758 insertions(+)
>  create mode 100644 Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.c
>  create mode 100644 Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.inf
>  create mode 100644 Platforms/Hisilicon/HiKey/Include/Guid/HiKeyVariable.h
> 
> diff --git a/Platforms/Hisilicon/HiKey/HiKey.dec b/Platforms/Hisilicon/HiKey/HiKey.dec
> index 537138e..17c6484 100644
> --- a/Platforms/Hisilicon/HiKey/HiKey.dec
> +++ b/Platforms/Hisilicon/HiKey/HiKey.dec
> @@ -30,6 +30,7 @@
>  
>  [Guids.common]
>    gHiKeyTokenSpaceGuid          =  { 0x91148425, 0xcdd2, 0x4830, { 0x8b, 0xd0, 0xc6, 0x1c, 0x6d, 0xea, 0x36, 0x21 } }
> +  gHiKeyVariableGuid            =  { 0x66b8d063, 0x1daa, 0x4c60, { 0xb9, 0xf2, 0x55, 0x0d, 0x7e, 0xe1, 0x2f, 0x38 } }
>  
>  [PcdsFixedAtBuild.common]
>    gHiKeyTokenSpaceGuid.PcdAndroidFastbootNvmDevicePath|L""|VOID*|0x00000001
> diff --git a/Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.c b/Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.c
> new file mode 100644
> index 0000000..2597f7a
> --- /dev/null
> +++ b/Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.c
> @@ -0,0 +1,672 @@
> +/** @file
> +
> +  Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
> +  Copyright (c) 2015-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.
> +
> +**/
> +
> +/*
> +  Implementation of the Android Fastboot Platform protocol, to be used by the
> +  Fastboot UEFI application, for Hisilicon HiKey platform.
> +*/
> +
> +#include <Protocol/AndroidFastbootPlatform.h>
> +#include <Protocol/BlockIo.h>
> +#include <Protocol/DiskIo.h>
> +#include <Protocol/EraseBlock.h>
> +#include <Protocol/SimpleTextOut.h>
> +
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiRuntimeServicesTableLib.h>
> +#include <Library/PrintLib.h>
> +#include <Library/TimerLib.h>
> +
> +#include <Guid/HiKeyVariable.h>
> +
> +#define FLASH_DEVICE_PATH_SIZE(DevPath) ( GetDevicePathSize (DevPath) - \
> +                                            sizeof (EFI_DEVICE_PATH_PROTOCOL))
> +
> +#define PARTITION_NAME_MAX_LENGTH 72/2
> +
> +#define IS_ALPHA(Char) (((Char) <= L'z' && (Char) >= L'a') || \
> +                        ((Char) <= L'Z' && (Char) >= L'Z'))
> +#define IS_HEXCHAR(Char) (((Char) <= L'9' && (Char) >= L'0') || \
> +                          IS_ALPHA(Char))
> +
> +#define SERIAL_NUMBER_LENGTH                     16
> +#define BOOT_DEVICE_LENGTH                       16
> +
> +#define HIKEY_ERASE_SIZE                         (16 * 1024 * 1024)
> +#define HIKEY_ERASE_BLOCKS                       (HIKEY_ERASE_SIZE / EFI_PAGE_SIZE)
> +#define PARTITION_TYPE_STRING                    "partition-type"
> +#define PARTITION_SIZE_STRING                    "partition-size"
> +// length of a 12-byte hex string
> +#define PARTITION_SIZE_LENGTH                    12
> +#define PARTITION_NAME_LENGTH                    36 // CHAR16

And here I asked:
---
Where does this limit come from? Specification?
---

> +
> +/*
> + * struct entry_head {
> + *   unsigned char        magic[8];   // "ENTRYHDR"
> + *   unsigned char        name[8];    // "primary"/"second"
> + *   unsigned int         start_lba;
> + *   unsigned int         count_lba;
> + *   unsigned int         flag;
> + * }
> + *
> + * ptable:
> + *   ------------------------------------------------------
> + *   | head (primary) | content | head (second) | content |
> + *   ------------------------------------------------------
> + */
> +
> +#define HIKEY_PTABLE_HEAD_MAGIC_LEN              8
> +#define HIKEY_PTABLE_HEAD_NAME_LEN               8
> +#define HIKEY_PTABLE_HEAD_SIZE                   28
> +#define HIKEY_PTABLE_CONTENT_OFFSET              512
> +
> +
> +typedef struct _FASTBOOT_PARTITION_LIST {
> +  LIST_ENTRY  Link;
> +  CHAR16      PartitionName[PARTITION_NAME_MAX_LENGTH];
> +  EFI_HANDLE  PartitionHandle;
> +  EFI_LBA     Lba;
> +} FASTBOOT_PARTITION_LIST;
> +
> +STATIC LIST_ENTRY mPartitionListHead;
> +
> +/*
> +  Helper to free the partition list
> +*/
> +STATIC
> +VOID
> +FreePartitionList (
> +  VOID
> +  )
> +{
> +  FASTBOOT_PARTITION_LIST *Entry;
> +  FASTBOOT_PARTITION_LIST *NextEntry;
> +
> +  Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&mPartitionListHead);
> +  while (!IsNull (&mPartitionListHead, &Entry->Link)) {
> +    NextEntry = (FASTBOOT_PARTITION_LIST *) GetNextNode (&mPartitionListHead, &Entry->Link);
> +
> +    RemoveEntryList (&Entry->Link);
> +    FreePool (Entry);
> +
> +    Entry = NextEntry;
> +  }
> +}
> +/*
> +  Read the PartitionName fields from the GPT partition entries, putting them
> +  into an allocated array that should later be freed.
> +*/
> +STATIC
> +EFI_STATUS
> +ReadPartitionEntries (
> +  IN  EFI_BLOCK_IO_PROTOCOL *BlockIo,
> +  OUT EFI_PARTITION_ENTRY  **PartitionEntries
> +  )
> +{
> +  UINTN                       EntrySize;
> +  UINTN                       NumEntries;
> +  UINTN                       BufferSize;
> +  UINT32                      MediaId;
> +  EFI_PARTITION_TABLE_HEADER *GptHeader;
> +  EFI_STATUS                  Status;
> +
> +  MediaId = BlockIo->Media->MediaId;
> +
> +  //
> +  // Read size of Partition entry and number of entries from GPT header
> +  //
> +
> +  GptHeader = AllocatePool (BlockIo->Media->BlockSize);
> +  if (GptHeader == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  Status = BlockIo->ReadBlocks (BlockIo, MediaId, 1, BlockIo->Media->BlockSize, GptHeader);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  // Check there is a GPT on the media
> +  if (GptHeader->Header.Signature != EFI_PTAB_HEADER_ID ||
> +      GptHeader->MyLBA != 1) {
> +    DEBUG ((DEBUG_ERROR,
> +      "Fastboot platform: No GPT on flash. "
> +      "Fastboot on HiKey does not support MBR.\n"
> +      ));
> +    return EFI_DEVICE_ERROR;
> +  }
> +
> +  EntrySize = GptHeader->SizeOfPartitionEntry;
> +  NumEntries = GptHeader->NumberOfPartitionEntries;
> +
> +  FreePool (GptHeader);
> +
> +  ASSERT (EntrySize != 0);
> +  ASSERT (NumEntries != 0);
> +
> +  BufferSize = ALIGN_VALUE (EntrySize * NumEntries, BlockIo->Media->BlockSize);
> +  *PartitionEntries = AllocatePool (BufferSize);
> +  if (PartitionEntries == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  Status = BlockIo->ReadBlocks (BlockIo, MediaId, 2, BufferSize, (VOID *) *PartitionEntries);
> +  if (EFI_ERROR (Status)) {
> +    FreePool (PartitionEntries);
> +    return Status;
> +  }
> +
> +  return Status;
> +}
> +
> +
> +STATIC
> +EFI_STATUS
> +CreateGptPartitionEntry (
> +  IN EFI_HANDLE                      *AllHandles,
> +  IN UINTN                            LoopIndex,
> +  IN HARDDRIVE_DEVICE_PATH           *PartitionNode,
> +  IN EFI_PARTITION_ENTRY             *PartitionEntries
> +  )
> +{
> +  FASTBOOT_PARTITION_LIST            *Entry;
> +
> +  // Create entry
> +  Entry = AllocatePool (sizeof (FASTBOOT_PARTITION_LIST));
> +  if (Entry == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  // Copy handle and partition name
> +  Entry->PartitionHandle = AllHandles[LoopIndex];
> +  StrnCpy (
> +    Entry->PartitionName,
> +    PartitionEntries[PartitionNode->PartitionNumber - 1].PartitionName, // Partition numbers start from 1.
> +    PARTITION_NAME_MAX_LENGTH
> +    );
> +  Entry->Lba = PartitionEntries[PartitionNode->PartitionNumber - 1].StartingLBA;
> +  InsertTailList (&mPartitionListHead, &Entry->Link);
> +
> +  // Print a debug message if the partition label is empty or looks like
> +  // garbage.
> +  if (!IS_ALPHA (Entry->PartitionName[0])) {
> +    DEBUG ((DEBUG_WARN,
> +      "Warning: Partition %d doesn't seem to have a GPT partition label. "
> +      "You won't be able to flash it with Fastboot.\n",
> +      PartitionNode->PartitionNumber
> +      ));
> +  }
> +  return EFI_SUCCESS;
> +}
> +
> +STATIC
> +EFI_STATUS
> +CreatePartitionEntry (
> +  IN  EFI_HANDLE                     *AllHandles,
> +  IN  UINTN                           LoopIndex,
> +  IN  EFI_DEVICE_PATH_PROTOCOL       *FlashDevicePath,
> +  IN  EFI_DEVICE_PATH_PROTOCOL       *DevicePath,
> +  IN  EFI_PARTITION_ENTRY            *PartitionEntries
> +  )
> +{
> +  EFI_DEVICE_PATH_PROTOCOL           *NextNode;
> +  FASTBOOT_PARTITION_LIST            *Entry;
> +  HARDDRIVE_DEVICE_PATH              *PartitionNode;
> +
> +  // Fill out if it isn't a sub-device of the flash device
> +  if (CompareMem (DevicePath, FlashDevicePath, FLASH_DEVICE_PATH_SIZE (FlashDevicePath))) {
> +    return EFI_SUCCESS;
> +  }
> +  // Device path starts with path of flash device. Check it isn't the flash
> +  // device itself.
> +  NextNode = NextDevicePathNode (DevicePath);
> +  if (IsDevicePathEndType (NextNode)) {
> +    // Create entry
> +    Entry = AllocatePool (sizeof (FASTBOOT_PARTITION_LIST));
> +    if (Entry == NULL) {
> +      return EFI_OUT_OF_RESOURCES;
> +    }
> +
> +    // Copy handle and partition name
> +    Entry->PartitionHandle = AllHandles[LoopIndex];
> +    StrCpy (Entry->PartitionName, L"ptable");
> +    InsertTailList (&mPartitionListHead, &Entry->Link);
> +    return EFI_SUCCESS;
> +  }
> +
> +  // Assert that this device path node represents a partition.
> +  ASSERT (NextNode->Type == MEDIA_DEVICE_PATH &&
> +          NextNode->SubType == MEDIA_HARDDRIVE_DP);
> +
> +  PartitionNode = (HARDDRIVE_DEVICE_PATH *) NextNode;
> +
> +  // Assert that the partition type is GPT. ReadPartitionEntries checks for
> +  // presence of a GPT, so we should never find MBR partitions.
> +  // ("MBRType" is a misnomer - this field is actually called "Partition
> +  //  Format")
> +  ASSERT (PartitionNode->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER);
> +
> +  // The firmware may install a handle for "partition 0", representing the
> +  // whole device. Ignore it.
> +  if (PartitionNode->PartitionNumber == 0) {
> +    return EFI_SUCCESS;
> +  }
> +  return CreateGptPartitionEntry (AllHandles, LoopIndex, PartitionNode, PartitionEntries);
> +}
> +
> +/*
> +  Initialise: Open the Android NVM device and find the partitions on it. Save them in
> +  a list along with the "PartitionName" fields for their GPT entries.
> +  We will use these partition names as the key in
> +  HiKeyFastbootPlatformFlashPartition.
> +*/
> +STATIC
> +EFI_STATUS
> +HiKeyFastbootPlatformInit (
> +  VOID
> +  )
> +{
> +  EFI_STATUS                          Status;
> +  EFI_DEVICE_PATH_PROTOCOL           *FlashDevicePath;
> +  EFI_DEVICE_PATH_PROTOCOL           *FlashDevicePathDup;
> +  EFI_DEVICE_PATH_PROTOCOL           *DevicePath;
> +  UINTN                               NumHandles;
> +  EFI_HANDLE                         *AllHandles;
> +  UINTN                               LoopIndex;
> +  EFI_HANDLE                          FlashHandle;
> +  EFI_BLOCK_IO_PROTOCOL              *FlashBlockIo;
> +  EFI_PARTITION_ENTRY                *PartitionEntries;
> +
> +  InitializeListHead (&mPartitionListHead);
> +
> +  //
> +  // Get EFI_HANDLES for all the partitions on the block devices pointed to by
> +  // PcdFastbootFlashDevicePath, also saving their GPT partition labels.
> +  // There's no way to find all of a device's children, so we get every handle
> +  // in the system supporting EFI_BLOCK_IO_PROTOCOL and then filter out ones
> +  // that don't represent partitions on the flash device.
> +  //
> +
> +  FlashDevicePath = ConvertTextToDevicePath ((CHAR16*)FixedPcdGetPtr (PcdAndroidFastbootNvmDevicePath));
> +
> +  //
> +  // Open the Disk IO protocol on the flash device - this will be used to read
> +  // partition names out of the GPT entries
> +  //
> +  // Create another device path pointer because LocateDevicePath will modify it.
> +  FlashDevicePathDup = FlashDevicePath;
> +  Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &FlashDevicePathDup, &FlashHandle);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "Warning: Couldn't locate Android NVM device (status: %r)\n", Status));
> +    // Failing to locate partitions should not prevent to do other Android FastBoot actions
> +    return EFI_SUCCESS;
> +  }
> +
> +  Status = gBS->OpenProtocol (
> +                  FlashHandle,
> +                  &gEfiBlockIoProtocolGuid,
> +                  (VOID **) &FlashBlockIo,
> +                  gImageHandle,
> +                  NULL,
> +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "Fastboot platform: Couldn't open Android NVM device (status: %r)\n", Status));
> +    return EFI_DEVICE_ERROR;
> +  }
> +
> +  // Read the GPT partition entry array into memory so we can get the partition names
> +  Status = ReadPartitionEntries (FlashBlockIo, &PartitionEntries);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "Warning: Failed to read partitions from Android NVM device (status: %r)\n", Status));
> +    // Failing to locate partitions should not prevent to do other Android FastBoot actions
> +    return EFI_SUCCESS;
> +  }
> +
> +  // Get every Block IO protocol instance installed in the system
> +  Status = gBS->LocateHandleBuffer (
> +                  ByProtocol,
> +                  &gEfiBlockIoProtocolGuid,
> +                  NULL,
> +                  &NumHandles,
> +                  &AllHandles
> +                  );
> +  ASSERT_EFI_ERROR (Status);
> +
> +  // Filter out handles that aren't children of the flash device
> +  for (LoopIndex = 0; LoopIndex < NumHandles; LoopIndex++) {
> +    // Get the device path for the handle
> +    Status = gBS->OpenProtocol (
> +                    AllHandles[LoopIndex],
> +                    &gEfiDevicePathProtocolGuid,
> +                    (VOID **) &DevicePath,
> +                    gImageHandle,
> +                    NULL,
> +                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
> +                    );
> +    ASSERT_EFI_ERROR (Status);
> +
> +    Status = CreatePartitionEntry (
> +               AllHandles,
> +               LoopIndex,
> +               FlashDevicePath,
> +               DevicePath,
> +               PartitionEntries
> +               );
> +    if (EFI_ERROR (Status)) {
> +      FreePartitionList ();
> +      goto Exit;
> +    }
> +  }
> +
> +Exit:
> +  FreePool (PartitionEntries);
> +  FreePool (FlashDevicePath);
> +  FreePool (AllHandles);
> +  return Status;
> +
> +}
> +
> +STATIC
> +VOID
> +HiKeyFastbootPlatformUnInit (
> +  VOID
> +  )
> +{
> +  FreePartitionList ();
> +}
> +
> +STATIC
> +VOID *
> +WritePartition (
> +  IN VOID                    *Image,
> +  IN UINTN                   Size,
> +  IN EFI_DISK_IO_PROTOCOL    *DiskIo,
> +  IN EFI_BLOCK_IO_PROTOCOL   *BlockIo,
> +  IN CHAR8                   *Name
> +  )
> +{
> +  UINT32                     EntrySize, EntryOffset;
> +  EFI_STATUS                 Status;
> +  VOID                       *Buffer;
> +
> +  Buffer = Image;
> +  // not a string with terminated '\0'
> +  if (AsciiStrnCmp (Buffer, "ENTRYHDR", HIKEY_PTABLE_HEAD_MAGIC_LEN) != 0) {
> +    DEBUG ((DEBUG_ERROR, "unknown ptable image\n"));
> +    return NULL;
> +  }
> +  Buffer += HIKEY_PTABLE_HEAD_MAGIC_LEN;
> +  // not a string with terminated '\0'
> +  if (AsciiStrnCmp (Buffer, Name, HIKEY_PTABLE_HEAD_NAME_LEN) != 0) {
> +    DEBUG ((DEBUG_ERROR, "unknown ptable image\n"));
> +    return NULL;
> +  }
> +  Buffer += HIKEY_PTABLE_HEAD_NAME_LEN;
> +  EntryOffset = *(UINT32 *)Buffer * BlockIo->Media->BlockSize;
> +  Buffer += sizeof (UINT32);
> +  EntrySize = *(UINT32 *)Buffer * BlockIo->Media->BlockSize;
> +  if ((EntrySize + HIKEY_PTABLE_CONTENT_OFFSET) > Size) {
> +    DEBUG ((DEBUG_ERROR, "Entry size doesn't match\n"));
> +    return NULL;
> +  }
> +  Buffer = Image + HIKEY_PTABLE_CONTENT_OFFSET;
> +  Status = DiskIo->WriteDisk (DiskIo, BlockIo->Media->MediaId, EntryOffset, EntrySize, Buffer);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "Can't flush partition table\n"));
> +    return NULL;
> +  }
> +  Buffer += EntrySize;
> +  return Buffer;
> +}
> +
> +STATIC
> +EFI_STATUS
> +HiKeyFastbootPlatformFlashPartition (
> +  IN CHAR8  *PartitionName,
> +  IN UINTN   Size,
> +  IN VOID   *Image
> +  )
> +{
> +  EFI_STATUS               Status;
> +  EFI_BLOCK_IO_PROTOCOL   *BlockIo;
> +  EFI_DISK_IO_PROTOCOL    *DiskIo;
> +  UINT32                   MediaId;
> +  UINTN                    PartitionSize;
> +  FASTBOOT_PARTITION_LIST *Entry;
> +  CHAR16                   PartitionNameUnicode[PARTITION_NAME_LENGTH];
> +  BOOLEAN                  PartitionFound;
> +  VOID                    *Buffer;
> +
> +
> +  AsciiStrToUnicodeStr (PartitionName, PartitionNameUnicode);
> +
> +  PartitionFound = FALSE;
> +  Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&(mPartitionListHead));
> +  while (!IsNull (&mPartitionListHead, &Entry->Link)) {
> +    // Search the partition list for the partition named by PartitionName
> +    if (StrCmp (Entry->PartitionName, PartitionNameUnicode) == 0) {
> +      PartitionFound = TRUE;
> +      break;
> +    }
> +
> +   Entry = (FASTBOOT_PARTITION_LIST *) GetNextNode (&mPartitionListHead, &(Entry)->Link);
> +  }
> +  if (!PartitionFound) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  Status = gBS->OpenProtocol (
> +                  Entry->PartitionHandle,
> +                  &gEfiBlockIoProtocolGuid,
> +                  (VOID **) &BlockIo,
> +                  gImageHandle,
> +                  NULL,
> +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "Fastboot platform: couldn't open Block IO for flash: %r\n", Status));
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  // Check image will fit on device
> +  // LastBlock counts from 0
> +  PartitionSize = (BlockIo->Media->LastBlock + 1) * BlockIo->Media->BlockSize;
> +  if (PartitionSize < Size) {
> +    DEBUG ((DEBUG_ERROR, "Partition not big enough.\n"));
> +    DEBUG ((DEBUG_ERROR, "Partition Size:\t%ld\nImage Size:\t%ld\n", PartitionSize, Size));
> +
> +    return EFI_VOLUME_FULL;
> +  }
> +
> +  MediaId = BlockIo->Media->MediaId;
> +
> +  Status = gBS->OpenProtocol (
> +                  Entry->PartitionHandle,
> +                  &gEfiDiskIoProtocolGuid,
> +                  (VOID **) &DiskIo,
> +                  gImageHandle,
> +                  NULL,
> +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
> +                  );
> +  ASSERT_EFI_ERROR (Status);
> +
> +  if (AsciiStrCmp (PartitionName, "ptable") == 0) {
> +    Buffer = WritePartition (Image, Size, DiskIo, BlockIo, "primary");
> +    if (Buffer == NULL) {
> +      return EFI_DEVICE_ERROR;
> +    }
> +    if (Size >= (2 * PartitionSize)) {
> +      Buffer = WritePartition (Buffer, Size, DiskIo, BlockIo, "second");
> +      if (Buffer == NULL) {
> +        return EFI_DEVICE_ERROR;
> +      }
> +    }

Yes, this bit looks a lot better now.

> +  } else {
> +    Status = DiskIo->WriteDisk (DiskIo, MediaId, 0, Size, Image);
> +  }
> +
> +  BlockIo->FlushBlocks(BlockIo);
> +  // wait DMA finished
> +  MicroSecondDelay (50000);
> +
> +  return Status;
> +}
> +
> +STATIC
> +EFI_STATUS
> +HiKeyFastbootPlatformErasePartition (
> +  IN CHAR8 *PartitionName
> +  )
> +{
> +  return EFI_SUCCESS;
> +}
> +
> +STATIC
> +EFI_STATUS
> +HiKeyFastbootPlatformGetVar (
> +  IN  CHAR8   *Name,
> +  OUT CHAR8   *Value
> +  )
> +{
> +  EFI_STATUS               Status;
> +  EFI_BLOCK_IO_PROTOCOL   *BlockIo;
> +  UINT64                   PartitionSize;
> +  FASTBOOT_PARTITION_LIST *Entry;
> +  CHAR16                   PartitionNameUnicode[PARTITION_NAME_LENGTH];
> +  BOOLEAN                  PartitionFound;
> +  CHAR16                   DataUnicode[SERIAL_NUMBER_LENGTH + 1]; // terminated '\0'
> +  UINTN                    VariableSize;
> +  CHAR8                    PartTypeStr[] = "partition-type";
> +  CHAR8                    PartSizeStr[] = "partition-size";
> +
> +  if (!AsciiStrCmp (Name, "max-download-size")) {
> +    AsciiStrCpy (Value, FixedPcdGetPtr (PcdArmFastbootFlashLimit));
> +  } else if (!AsciiStrCmp (Name, "product")) {
> +    AsciiStrCpy (Value, FixedPcdGetPtr (PcdFirmwareVendor));
> +  } else if (!AsciiStrCmp (Name, "serialno")) {
> +    VariableSize = (SERIAL_NUMBER_LENGTH + 1) * sizeof (CHAR16);
> +    Status = gRT->GetVariable (
> +                    (CHAR16 *)L"SerialNo",
> +                    &gHiKeyVariableGuid,
> +                    NULL,
> +                    &VariableSize,
> +                    &DataUnicode
> +                    );
> +    if (EFI_ERROR (Status)) {
> +      *Value = '\0';
> +      return EFI_NOT_FOUND;
> +    }
> +    DataUnicode[SERIAL_NUMBER_LENGTH * sizeof(CHAR16)] = '\0';
> +    UnicodeStrToAsciiStr (DataUnicode, Value);
> +  } else if (!AsciiStrnCmp (Name, PartSizeStr, AsciiStrLen (PartSizeStr))) {
> +    // skip ':', then copy
> +    AsciiStrToUnicodeStr ((Name + AsciiStrLen (PartSizeStr) + 1), PartitionNameUnicode);
> +    PartitionFound = FALSE;
> +    Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&(mPartitionListHead));
> +    while (!IsNull (&mPartitionListHead, &Entry->Link)) {
> +      // Search the partition list for the partition named by PartitionName
> +      if (StrCmp (Entry->PartitionName, PartitionNameUnicode) == 0) {
> +        PartitionFound = TRUE;
> +        break;
> +      }
> +
> +     Entry = (FASTBOOT_PARTITION_LIST *) GetNextNode (&mPartitionListHead, &(Entry)->Link);
> +    }
> +    if (!PartitionFound) {
> +      *Value = '\0';
> +      return EFI_NOT_FOUND;
> +    }
> +
> +    Status = gBS->OpenProtocol (
> +                    Entry->PartitionHandle,
> +                    &gEfiBlockIoProtocolGuid,
> +                    (VOID **) &BlockIo,
> +                    gImageHandle,
> +                    NULL,
> +                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
> +                    );
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((DEBUG_ERROR, "Fastboot platform: couldn't open Block IO for flash: %r\n", Status));
> +      *Value = '\0';
> +      return EFI_NOT_FOUND;
> +    }
> +
> +    // LastBlock counts from 0
> +    PartitionSize = (BlockIo->Media->LastBlock + 1) * BlockIo->Media->BlockSize;
> +    DEBUG ((DEBUG_INFO, "Fastboot platform: check for partition-size:%a 0x%llx\n", Name, PartitionSize));
> +    AsciiSPrint (Value, PARTITION_SIZE_LENGTH, "0x%llx", PartitionSize);
> +  } else if ( !AsciiStrnCmp (Name, PartTypeStr, AsciiStrLen (PartTypeStr))) {
> +    DEBUG ((DEBUG_INFO, "Fastboot platform: check for partition-type:%a\n", Name + AsciiStrLen (PartTypeStr)));
> +    // skip ':'
> +    if (!AsciiStrCmp ((Name + AsciiStrLen (PartTypeStr) + 1) , "system") ||
> +        !AsciiStrCmp ((Name + AsciiStrLen (PartTypeStr) + 1) , "userdata") ||
> +        !AsciiStrCmp ((Name + AsciiStrLen (PartTypeStr) + 1) , "cache")) {
> +      AsciiStrCpy (Value, "ext4");
> +    } else {
> +      AsciiStrCpy (Value, "raw");
> +    }
> +  } else {
> +    *Value = '\0';
> +  }
> +  return EFI_SUCCESS;
> +}
> +
> +STATIC
> +EFI_STATUS
> +HiKeyFastbootPlatformOemCommand (
> +  IN  CHAR8   *Command
> +  )
> +{
> +  if (AsciiStrCmp (Command, "Demonstrate") == 0) {
> +    DEBUG ((DEBUG_ERROR, "ARM OEM Fastboot command 'Demonstrate' received.\n"));
> +    return EFI_SUCCESS;
> +  } else {
> +    DEBUG ((DEBUG_ERROR,
> +      "HiKey: Unrecognised Fastboot OEM command: %s\n",
> +      Command
> +      ));
> +    return EFI_NOT_FOUND;
> +  }
> +}
> +
> +FASTBOOT_PLATFORM_PROTOCOL mPlatformProtocol = {
> +  HiKeyFastbootPlatformInit,
> +  HiKeyFastbootPlatformUnInit,
> +  HiKeyFastbootPlatformFlashPartition,
> +  HiKeyFastbootPlatformErasePartition,
> +  HiKeyFastbootPlatformGetVar,
> +  HiKeyFastbootPlatformOemCommand
> +};
> +
> +EFI_STATUS
> +EFIAPI
> +HiKeyFastbootPlatformEntryPoint (
> +  IN EFI_HANDLE                            ImageHandle,
> +  IN EFI_SYSTEM_TABLE                      *SystemTable
> +  )
> +{
> +  return gBS->InstallProtocolInterface (
> +                &ImageHandle,
> +                &gAndroidFastbootPlatformProtocolGuid,
> +                EFI_NATIVE_INTERFACE,
> +                &mPlatformProtocol
> +                );
> +}
> diff --git a/Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.inf b/Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.inf
> new file mode 100644
> index 0000000..353c6c3
> --- /dev/null
> +++ b/Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.inf
> @@ -0,0 +1,61 @@
> +#/** @file
> +#
> +#  Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
> +#  Copyright (c) 2015-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                      = HiKeyFastbootDxe
> +  FILE_GUID                      = 8e335c38-c4e1-494e-8011-37a858d9763d
> +  MODULE_TYPE                    = UEFI_DRIVER
> +  VERSION_STRING                 = 1.0
> +  ENTRY_POINT                    = HiKeyFastbootPlatformEntryPoint
> +
> +[Sources.common]
> +  HiKeyFastbootDxe.c
> +
> +[LibraryClasses]
> +  BaseLib
> +  BaseMemoryLib
> +  DebugLib
> +  DevicePathLib
> +  MemoryAllocationLib
> +  PcdLib
> +  UefiBootServicesTableLib
> +  UefiRuntimeServicesTableLib
> +  UefiDriverEntryPoint
> +  TimerLib

Comment unaddressed from v3:
---
Please insert TimerLib alphabetically.
---

> +
> +[Protocols]
> +  gAndroidFastbootPlatformProtocolGuid
> +  gEfiBlockIoProtocolGuid
> +  gEfiDiskIoProtocolGuid
> +  gEfiSimpleTextOutProtocolGuid
> +  gEfiEraseBlockProtocolGuid

Comment unaddressed from v3:
---
Please sort alphabetically.
---

> +
> +[Packages]
> +  EmbeddedPkg/EmbeddedPkg.dec
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  ArmPlatformPkg/ArmPlatformPkg.dec
> +  ArmPlatformPkg/ArmVExpressPkg/ArmVExpressPkg.dec
> +  ArmPkg/ArmPkg.dec
> +  OpenPlatformPkg/Platforms/Hisilicon/HiKey/HiKey.dec

Comment unaddressed from v3:
---
Please sort alphabetically.
---

> +
> +[Guids]
> +  gHiKeyVariableGuid
> +
> +[Pcd]
> +  gArmPlatformTokenSpaceGuid.PcdFirmwareVendor
> +  gHiKeyTokenSpaceGuid.PcdAndroidFastbootNvmDevicePath
> +  gHiKeyTokenSpaceGuid.PcdArmFastbootFlashLimit
> diff --git a/Platforms/Hisilicon/HiKey/Include/Guid/HiKeyVariable.h b/Platforms/Hisilicon/HiKey/Include/Guid/HiKeyVariable.h
> new file mode 100644
> index 0000000..56d5a0e
> --- /dev/null
> +++ b/Platforms/Hisilicon/HiKey/Include/Guid/HiKeyVariable.h
> @@ -0,0 +1,24 @@
> +/** @file
> +*
> +*  Copyright (c) 2013-2014, ARM Limited. All rights reserved.
> +*  Copyright (c) 2015-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.
> +*
> +**/
> +
> +#ifndef __HIKEY_VARIABLE_H__
> +#define __HIKEY_VARIABLE_H__
> +
> +#define HIKEY_VARIABLE_GUID \
> +  { 0x66b8d063, 0x1daa, 0x4c60, { 0xb9, 0xf2, 0x55, 0x0d, 0x7e, 0xe1, 0x2f, 0x38 } }
> +
> +extern EFI_GUID gHiKeyVariableGuid;
> +
> +#endif /* __HIKEY_VARIABLE_H__ */
> -- 
> 2.7.4
>
Haojian Zhuang March 2, 2017, 1:32 a.m. UTC | #2
On 2017/3/1 23:13, Leif Lindholm wrote:
> On Wed, Feb 15, 2017 at 10:54:59PM +0800, Haojian Zhuang wrote:
>> Support HiKey Fastboot driver for Fastboot App.
>>
>
> I asked a few questions on v3, which I received no replies to.
> Here I asked:
> ---
> Question: I notice this version deletes the SPARSE_HEADER support,
> which was one of the main differences compared to VEXpress driver.
> Is this something you plan to introduce in future?
> ---

It'll be appended in future. There are two reasons that I remove it
from this patch set.
1. There's some issue to download latest system.img into HiKey.
2. SPARSE_HEADER should be common case. It's better to parse it in
AndroidFastboot App instead.

>
>> Contributed-under: TianoCore Contribution Agreement 1.0
>> Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
>> ---
>>  Platforms/Hisilicon/HiKey/HiKey.dec                |   1 +
>>  .../HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.c      | 672 +++++++++++++++++++++
>>  .../HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.inf    |  61 ++
>>  .../Hisilicon/HiKey/Include/Guid/HiKeyVariable.h   |  24 +
>>  4 files changed, 758 insertions(+)
>>  create mode 100644 Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.c
>>  create mode 100644 Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.inf
>>  create mode 100644 Platforms/Hisilicon/HiKey/Include/Guid/HiKeyVariable.h
>>
>> diff --git a/Platforms/Hisilicon/HiKey/HiKey.dec b/Platforms/Hisilicon/HiKey/HiKey.dec
>> index 537138e..17c6484 100644
>> --- a/Platforms/Hisilicon/HiKey/HiKey.dec
>> +++ b/Platforms/Hisilicon/HiKey/HiKey.dec
>> @@ -30,6 +30,7 @@
>>
>>  [Guids.common]
>>    gHiKeyTokenSpaceGuid          =  { 0x91148425, 0xcdd2, 0x4830, { 0x8b, 0xd0, 0xc6, 0x1c, 0x6d, 0xea, 0x36, 0x21 } }
>> +  gHiKeyVariableGuid            =  { 0x66b8d063, 0x1daa, 0x4c60, { 0xb9, 0xf2, 0x55, 0x0d, 0x7e, 0xe1, 0x2f, 0x38 } }
>>
>>  [PcdsFixedAtBuild.common]
>>    gHiKeyTokenSpaceGuid.PcdAndroidFastbootNvmDevicePath|L""|VOID*|0x00000001
>> diff --git a/Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.c b/Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.c
>> new file mode 100644
>> index 0000000..2597f7a
>> --- /dev/null
>> +++ b/Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.c
>> @@ -0,0 +1,672 @@
>> +/** @file
>> +
>> +  Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
>> +  Copyright (c) 2015-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.
>> +
>> +**/
>> +
>> +/*
>> +  Implementation of the Android Fastboot Platform protocol, to be used by the
>> +  Fastboot UEFI application, for Hisilicon HiKey platform.
>> +*/
>> +
>> +#include <Protocol/AndroidFastbootPlatform.h>
>> +#include <Protocol/BlockIo.h>
>> +#include <Protocol/DiskIo.h>
>> +#include <Protocol/EraseBlock.h>
>> +#include <Protocol/SimpleTextOut.h>
>> +
>> +#include <Library/BaseLib.h>
>> +#include <Library/BaseMemoryLib.h>
>> +#include <Library/DebugLib.h>
>> +#include <Library/DevicePathLib.h>
>> +#include <Library/MemoryAllocationLib.h>
>> +#include <Library/UefiBootServicesTableLib.h>
>> +#include <Library/UefiRuntimeServicesTableLib.h>
>> +#include <Library/PrintLib.h>
>> +#include <Library/TimerLib.h>
>> +
>> +#include <Guid/HiKeyVariable.h>
>> +
>> +#define FLASH_DEVICE_PATH_SIZE(DevPath) ( GetDevicePathSize (DevPath) - \
>> +                                            sizeof (EFI_DEVICE_PATH_PROTOCOL))
>> +
>> +#define PARTITION_NAME_MAX_LENGTH 72/2
>> +
>> +#define IS_ALPHA(Char) (((Char) <= L'z' && (Char) >= L'a') || \
>> +                        ((Char) <= L'Z' && (Char) >= L'Z'))
>> +#define IS_HEXCHAR(Char) (((Char) <= L'9' && (Char) >= L'0') || \
>> +                          IS_ALPHA(Char))
>> +
>> +#define SERIAL_NUMBER_LENGTH                     16
>> +#define BOOT_DEVICE_LENGTH                       16
>> +
>> +#define HIKEY_ERASE_SIZE                         (16 * 1024 * 1024)
>> +#define HIKEY_ERASE_BLOCKS                       (HIKEY_ERASE_SIZE / EFI_PAGE_SIZE)
>> +#define PARTITION_TYPE_STRING                    "partition-type"
>> +#define PARTITION_SIZE_STRING                    "partition-size"
>> +// length of a 12-byte hex string
>> +#define PARTITION_SIZE_LENGTH                    12
>> +#define PARTITION_NAME_LENGTH                    36 // CHAR16
>
> And here I asked:
> ---
> Where does this limit come from? Specification?
> ---

Yes, it's from GPT spec.
>
>> +
>> +/*
>> + * struct entry_head {
>> + *   unsigned char        magic[8];   // "ENTRYHDR"
>> + *   unsigned char        name[8];    // "primary"/"second"
>> + *   unsigned int         start_lba;
>> + *   unsigned int         count_lba;
>> + *   unsigned int         flag;
>> + * }
>> + *
>> + * ptable:
>> + *   ------------------------------------------------------
>> + *   | head (primary) | content | head (second) | content |
>> + *   ------------------------------------------------------
>> + */
>> +
>> +#define HIKEY_PTABLE_HEAD_MAGIC_LEN              8
>> +#define HIKEY_PTABLE_HEAD_NAME_LEN               8
>> +#define HIKEY_PTABLE_HEAD_SIZE                   28
>> +#define HIKEY_PTABLE_CONTENT_OFFSET              512
>> +
>> +
>> +typedef struct _FASTBOOT_PARTITION_LIST {
>> +  LIST_ENTRY  Link;
>> +  CHAR16      PartitionName[PARTITION_NAME_MAX_LENGTH];
>> +  EFI_HANDLE  PartitionHandle;
>> +  EFI_LBA     Lba;
>> +} FASTBOOT_PARTITION_LIST;
>> +
>> +STATIC LIST_ENTRY mPartitionListHead;
>> +
>> +/*
>> +  Helper to free the partition list
>> +*/
>> +STATIC
>> +VOID
>> +FreePartitionList (
>> +  VOID
>> +  )
>> +{
>> +  FASTBOOT_PARTITION_LIST *Entry;
>> +  FASTBOOT_PARTITION_LIST *NextEntry;
>> +
>> +  Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&mPartitionListHead);
>> +  while (!IsNull (&mPartitionListHead, &Entry->Link)) {
>> +    NextEntry = (FASTBOOT_PARTITION_LIST *) GetNextNode (&mPartitionListHead, &Entry->Link);
>> +
>> +    RemoveEntryList (&Entry->Link);
>> +    FreePool (Entry);
>> +
>> +    Entry = NextEntry;
>> +  }
>> +}
>> +/*
>> +  Read the PartitionName fields from the GPT partition entries, putting them
>> +  into an allocated array that should later be freed.
>> +*/
>> +STATIC
>> +EFI_STATUS
>> +ReadPartitionEntries (
>> +  IN  EFI_BLOCK_IO_PROTOCOL *BlockIo,
>> +  OUT EFI_PARTITION_ENTRY  **PartitionEntries
>> +  )
>> +{
>> +  UINTN                       EntrySize;
>> +  UINTN                       NumEntries;
>> +  UINTN                       BufferSize;
>> +  UINT32                      MediaId;
>> +  EFI_PARTITION_TABLE_HEADER *GptHeader;
>> +  EFI_STATUS                  Status;
>> +
>> +  MediaId = BlockIo->Media->MediaId;
>> +
>> +  //
>> +  // Read size of Partition entry and number of entries from GPT header
>> +  //
>> +
>> +  GptHeader = AllocatePool (BlockIo->Media->BlockSize);
>> +  if (GptHeader == NULL) {
>> +    return EFI_OUT_OF_RESOURCES;
>> +  }
>> +
>> +  Status = BlockIo->ReadBlocks (BlockIo, MediaId, 1, BlockIo->Media->BlockSize, GptHeader);
>> +  if (EFI_ERROR (Status)) {
>> +    return Status;
>> +  }
>> +
>> +  // Check there is a GPT on the media
>> +  if (GptHeader->Header.Signature != EFI_PTAB_HEADER_ID ||
>> +      GptHeader->MyLBA != 1) {
>> +    DEBUG ((DEBUG_ERROR,
>> +      "Fastboot platform: No GPT on flash. "
>> +      "Fastboot on HiKey does not support MBR.\n"
>> +      ));
>> +    return EFI_DEVICE_ERROR;
>> +  }
>> +
>> +  EntrySize = GptHeader->SizeOfPartitionEntry;
>> +  NumEntries = GptHeader->NumberOfPartitionEntries;
>> +
>> +  FreePool (GptHeader);
>> +
>> +  ASSERT (EntrySize != 0);
>> +  ASSERT (NumEntries != 0);
>> +
>> +  BufferSize = ALIGN_VALUE (EntrySize * NumEntries, BlockIo->Media->BlockSize);
>> +  *PartitionEntries = AllocatePool (BufferSize);
>> +  if (PartitionEntries == NULL) {
>> +    return EFI_OUT_OF_RESOURCES;
>> +  }
>> +
>> +  Status = BlockIo->ReadBlocks (BlockIo, MediaId, 2, BufferSize, (VOID *) *PartitionEntries);
>> +  if (EFI_ERROR (Status)) {
>> +    FreePool (PartitionEntries);
>> +    return Status;
>> +  }
>> +
>> +  return Status;
>> +}
>> +
>> +
>> +STATIC
>> +EFI_STATUS
>> +CreateGptPartitionEntry (
>> +  IN EFI_HANDLE                      *AllHandles,
>> +  IN UINTN                            LoopIndex,
>> +  IN HARDDRIVE_DEVICE_PATH           *PartitionNode,
>> +  IN EFI_PARTITION_ENTRY             *PartitionEntries
>> +  )
>> +{
>> +  FASTBOOT_PARTITION_LIST            *Entry;
>> +
>> +  // Create entry
>> +  Entry = AllocatePool (sizeof (FASTBOOT_PARTITION_LIST));
>> +  if (Entry == NULL) {
>> +    return EFI_OUT_OF_RESOURCES;
>> +  }
>> +
>> +  // Copy handle and partition name
>> +  Entry->PartitionHandle = AllHandles[LoopIndex];
>> +  StrnCpy (
>> +    Entry->PartitionName,
>> +    PartitionEntries[PartitionNode->PartitionNumber - 1].PartitionName, // Partition numbers start from 1.
>> +    PARTITION_NAME_MAX_LENGTH
>> +    );
>> +  Entry->Lba = PartitionEntries[PartitionNode->PartitionNumber - 1].StartingLBA;
>> +  InsertTailList (&mPartitionListHead, &Entry->Link);
>> +
>> +  // Print a debug message if the partition label is empty or looks like
>> +  // garbage.
>> +  if (!IS_ALPHA (Entry->PartitionName[0])) {
>> +    DEBUG ((DEBUG_WARN,
>> +      "Warning: Partition %d doesn't seem to have a GPT partition label. "
>> +      "You won't be able to flash it with Fastboot.\n",
>> +      PartitionNode->PartitionNumber
>> +      ));
>> +  }
>> +  return EFI_SUCCESS;
>> +}
>> +
>> +STATIC
>> +EFI_STATUS
>> +CreatePartitionEntry (
>> +  IN  EFI_HANDLE                     *AllHandles,
>> +  IN  UINTN                           LoopIndex,
>> +  IN  EFI_DEVICE_PATH_PROTOCOL       *FlashDevicePath,
>> +  IN  EFI_DEVICE_PATH_PROTOCOL       *DevicePath,
>> +  IN  EFI_PARTITION_ENTRY            *PartitionEntries
>> +  )
>> +{
>> +  EFI_DEVICE_PATH_PROTOCOL           *NextNode;
>> +  FASTBOOT_PARTITION_LIST            *Entry;
>> +  HARDDRIVE_DEVICE_PATH              *PartitionNode;
>> +
>> +  // Fill out if it isn't a sub-device of the flash device
>> +  if (CompareMem (DevicePath, FlashDevicePath, FLASH_DEVICE_PATH_SIZE (FlashDevicePath))) {
>> +    return EFI_SUCCESS;
>> +  }
>> +  // Device path starts with path of flash device. Check it isn't the flash
>> +  // device itself.
>> +  NextNode = NextDevicePathNode (DevicePath);
>> +  if (IsDevicePathEndType (NextNode)) {
>> +    // Create entry
>> +    Entry = AllocatePool (sizeof (FASTBOOT_PARTITION_LIST));
>> +    if (Entry == NULL) {
>> +      return EFI_OUT_OF_RESOURCES;
>> +    }
>> +
>> +    // Copy handle and partition name
>> +    Entry->PartitionHandle = AllHandles[LoopIndex];
>> +    StrCpy (Entry->PartitionName, L"ptable");
>> +    InsertTailList (&mPartitionListHead, &Entry->Link);
>> +    return EFI_SUCCESS;
>> +  }
>> +
>> +  // Assert that this device path node represents a partition.
>> +  ASSERT (NextNode->Type == MEDIA_DEVICE_PATH &&
>> +          NextNode->SubType == MEDIA_HARDDRIVE_DP);
>> +
>> +  PartitionNode = (HARDDRIVE_DEVICE_PATH *) NextNode;
>> +
>> +  // Assert that the partition type is GPT. ReadPartitionEntries checks for
>> +  // presence of a GPT, so we should never find MBR partitions.
>> +  // ("MBRType" is a misnomer - this field is actually called "Partition
>> +  //  Format")
>> +  ASSERT (PartitionNode->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER);
>> +
>> +  // The firmware may install a handle for "partition 0", representing the
>> +  // whole device. Ignore it.
>> +  if (PartitionNode->PartitionNumber == 0) {
>> +    return EFI_SUCCESS;
>> +  }
>> +  return CreateGptPartitionEntry (AllHandles, LoopIndex, PartitionNode, PartitionEntries);
>> +}
>> +
>> +/*
>> +  Initialise: Open the Android NVM device and find the partitions on it. Save them in
>> +  a list along with the "PartitionName" fields for their GPT entries.
>> +  We will use these partition names as the key in
>> +  HiKeyFastbootPlatformFlashPartition.
>> +*/
>> +STATIC
>> +EFI_STATUS
>> +HiKeyFastbootPlatformInit (
>> +  VOID
>> +  )
>> +{
>> +  EFI_STATUS                          Status;
>> +  EFI_DEVICE_PATH_PROTOCOL           *FlashDevicePath;
>> +  EFI_DEVICE_PATH_PROTOCOL           *FlashDevicePathDup;
>> +  EFI_DEVICE_PATH_PROTOCOL           *DevicePath;
>> +  UINTN                               NumHandles;
>> +  EFI_HANDLE                         *AllHandles;
>> +  UINTN                               LoopIndex;
>> +  EFI_HANDLE                          FlashHandle;
>> +  EFI_BLOCK_IO_PROTOCOL              *FlashBlockIo;
>> +  EFI_PARTITION_ENTRY                *PartitionEntries;
>> +
>> +  InitializeListHead (&mPartitionListHead);
>> +
>> +  //
>> +  // Get EFI_HANDLES for all the partitions on the block devices pointed to by
>> +  // PcdFastbootFlashDevicePath, also saving their GPT partition labels.
>> +  // There's no way to find all of a device's children, so we get every handle
>> +  // in the system supporting EFI_BLOCK_IO_PROTOCOL and then filter out ones
>> +  // that don't represent partitions on the flash device.
>> +  //
>> +
>> +  FlashDevicePath = ConvertTextToDevicePath ((CHAR16*)FixedPcdGetPtr (PcdAndroidFastbootNvmDevicePath));
>> +
>> +  //
>> +  // Open the Disk IO protocol on the flash device - this will be used to read
>> +  // partition names out of the GPT entries
>> +  //
>> +  // Create another device path pointer because LocateDevicePath will modify it.
>> +  FlashDevicePathDup = FlashDevicePath;
>> +  Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &FlashDevicePathDup, &FlashHandle);
>> +  if (EFI_ERROR (Status)) {
>> +    DEBUG ((DEBUG_ERROR, "Warning: Couldn't locate Android NVM device (status: %r)\n", Status));
>> +    // Failing to locate partitions should not prevent to do other Android FastBoot actions
>> +    return EFI_SUCCESS;
>> +  }
>> +
>> +  Status = gBS->OpenProtocol (
>> +                  FlashHandle,
>> +                  &gEfiBlockIoProtocolGuid,
>> +                  (VOID **) &FlashBlockIo,
>> +                  gImageHandle,
>> +                  NULL,
>> +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
>> +                  );
>> +  if (EFI_ERROR (Status)) {
>> +    DEBUG ((DEBUG_ERROR, "Fastboot platform: Couldn't open Android NVM device (status: %r)\n", Status));
>> +    return EFI_DEVICE_ERROR;
>> +  }
>> +
>> +  // Read the GPT partition entry array into memory so we can get the partition names
>> +  Status = ReadPartitionEntries (FlashBlockIo, &PartitionEntries);
>> +  if (EFI_ERROR (Status)) {
>> +    DEBUG ((DEBUG_ERROR, "Warning: Failed to read partitions from Android NVM device (status: %r)\n", Status));
>> +    // Failing to locate partitions should not prevent to do other Android FastBoot actions
>> +    return EFI_SUCCESS;
>> +  }
>> +
>> +  // Get every Block IO protocol instance installed in the system
>> +  Status = gBS->LocateHandleBuffer (
>> +                  ByProtocol,
>> +                  &gEfiBlockIoProtocolGuid,
>> +                  NULL,
>> +                  &NumHandles,
>> +                  &AllHandles
>> +                  );
>> +  ASSERT_EFI_ERROR (Status);
>> +
>> +  // Filter out handles that aren't children of the flash device
>> +  for (LoopIndex = 0; LoopIndex < NumHandles; LoopIndex++) {
>> +    // Get the device path for the handle
>> +    Status = gBS->OpenProtocol (
>> +                    AllHandles[LoopIndex],
>> +                    &gEfiDevicePathProtocolGuid,
>> +                    (VOID **) &DevicePath,
>> +                    gImageHandle,
>> +                    NULL,
>> +                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
>> +                    );
>> +    ASSERT_EFI_ERROR (Status);
>> +
>> +    Status = CreatePartitionEntry (
>> +               AllHandles,
>> +               LoopIndex,
>> +               FlashDevicePath,
>> +               DevicePath,
>> +               PartitionEntries
>> +               );
>> +    if (EFI_ERROR (Status)) {
>> +      FreePartitionList ();
>> +      goto Exit;
>> +    }
>> +  }
>> +
>> +Exit:
>> +  FreePool (PartitionEntries);
>> +  FreePool (FlashDevicePath);
>> +  FreePool (AllHandles);
>> +  return Status;
>> +
>> +}
>> +
>> +STATIC
>> +VOID
>> +HiKeyFastbootPlatformUnInit (
>> +  VOID
>> +  )
>> +{
>> +  FreePartitionList ();
>> +}
>> +
>> +STATIC
>> +VOID *
>> +WritePartition (
>> +  IN VOID                    *Image,
>> +  IN UINTN                   Size,
>> +  IN EFI_DISK_IO_PROTOCOL    *DiskIo,
>> +  IN EFI_BLOCK_IO_PROTOCOL   *BlockIo,
>> +  IN CHAR8                   *Name
>> +  )
>> +{
>> +  UINT32                     EntrySize, EntryOffset;
>> +  EFI_STATUS                 Status;
>> +  VOID                       *Buffer;
>> +
>> +  Buffer = Image;
>> +  // not a string with terminated '\0'
>> +  if (AsciiStrnCmp (Buffer, "ENTRYHDR", HIKEY_PTABLE_HEAD_MAGIC_LEN) != 0) {
>> +    DEBUG ((DEBUG_ERROR, "unknown ptable image\n"));
>> +    return NULL;
>> +  }
>> +  Buffer += HIKEY_PTABLE_HEAD_MAGIC_LEN;
>> +  // not a string with terminated '\0'
>> +  if (AsciiStrnCmp (Buffer, Name, HIKEY_PTABLE_HEAD_NAME_LEN) != 0) {
>> +    DEBUG ((DEBUG_ERROR, "unknown ptable image\n"));
>> +    return NULL;
>> +  }
>> +  Buffer += HIKEY_PTABLE_HEAD_NAME_LEN;
>> +  EntryOffset = *(UINT32 *)Buffer * BlockIo->Media->BlockSize;
>> +  Buffer += sizeof (UINT32);
>> +  EntrySize = *(UINT32 *)Buffer * BlockIo->Media->BlockSize;
>> +  if ((EntrySize + HIKEY_PTABLE_CONTENT_OFFSET) > Size) {
>> +    DEBUG ((DEBUG_ERROR, "Entry size doesn't match\n"));
>> +    return NULL;
>> +  }
>> +  Buffer = Image + HIKEY_PTABLE_CONTENT_OFFSET;
>> +  Status = DiskIo->WriteDisk (DiskIo, BlockIo->Media->MediaId, EntryOffset, EntrySize, Buffer);
>> +  if (EFI_ERROR (Status)) {
>> +    DEBUG ((DEBUG_ERROR, "Can't flush partition table\n"));
>> +    return NULL;
>> +  }
>> +  Buffer += EntrySize;
>> +  return Buffer;
>> +}
>> +
>> +STATIC
>> +EFI_STATUS
>> +HiKeyFastbootPlatformFlashPartition (
>> +  IN CHAR8  *PartitionName,
>> +  IN UINTN   Size,
>> +  IN VOID   *Image
>> +  )
>> +{
>> +  EFI_STATUS               Status;
>> +  EFI_BLOCK_IO_PROTOCOL   *BlockIo;
>> +  EFI_DISK_IO_PROTOCOL    *DiskIo;
>> +  UINT32                   MediaId;
>> +  UINTN                    PartitionSize;
>> +  FASTBOOT_PARTITION_LIST *Entry;
>> +  CHAR16                   PartitionNameUnicode[PARTITION_NAME_LENGTH];
>> +  BOOLEAN                  PartitionFound;
>> +  VOID                    *Buffer;
>> +
>> +
>> +  AsciiStrToUnicodeStr (PartitionName, PartitionNameUnicode);
>> +
>> +  PartitionFound = FALSE;
>> +  Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&(mPartitionListHead));
>> +  while (!IsNull (&mPartitionListHead, &Entry->Link)) {
>> +    // Search the partition list for the partition named by PartitionName
>> +    if (StrCmp (Entry->PartitionName, PartitionNameUnicode) == 0) {
>> +      PartitionFound = TRUE;
>> +      break;
>> +    }
>> +
>> +   Entry = (FASTBOOT_PARTITION_LIST *) GetNextNode (&mPartitionListHead, &(Entry)->Link);
>> +  }
>> +  if (!PartitionFound) {
>> +    return EFI_NOT_FOUND;
>> +  }
>> +
>> +  Status = gBS->OpenProtocol (
>> +                  Entry->PartitionHandle,
>> +                  &gEfiBlockIoProtocolGuid,
>> +                  (VOID **) &BlockIo,
>> +                  gImageHandle,
>> +                  NULL,
>> +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
>> +                  );
>> +  if (EFI_ERROR (Status)) {
>> +    DEBUG ((DEBUG_ERROR, "Fastboot platform: couldn't open Block IO for flash: %r\n", Status));
>> +    return EFI_NOT_FOUND;
>> +  }
>> +
>> +  // Check image will fit on device
>> +  // LastBlock counts from 0
>> +  PartitionSize = (BlockIo->Media->LastBlock + 1) * BlockIo->Media->BlockSize;
>> +  if (PartitionSize < Size) {
>> +    DEBUG ((DEBUG_ERROR, "Partition not big enough.\n"));
>> +    DEBUG ((DEBUG_ERROR, "Partition Size:\t%ld\nImage Size:\t%ld\n", PartitionSize, Size));
>> +
>> +    return EFI_VOLUME_FULL;
>> +  }
>> +
>> +  MediaId = BlockIo->Media->MediaId;
>> +
>> +  Status = gBS->OpenProtocol (
>> +                  Entry->PartitionHandle,
>> +                  &gEfiDiskIoProtocolGuid,
>> +                  (VOID **) &DiskIo,
>> +                  gImageHandle,
>> +                  NULL,
>> +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
>> +                  );
>> +  ASSERT_EFI_ERROR (Status);
>> +
>> +  if (AsciiStrCmp (PartitionName, "ptable") == 0) {
>> +    Buffer = WritePartition (Image, Size, DiskIo, BlockIo, "primary");
>> +    if (Buffer == NULL) {
>> +      return EFI_DEVICE_ERROR;
>> +    }
>> +    if (Size >= (2 * PartitionSize)) {
>> +      Buffer = WritePartition (Buffer, Size, DiskIo, BlockIo, "second");
>> +      if (Buffer == NULL) {
>> +        return EFI_DEVICE_ERROR;
>> +      }
>> +    }
>
> Yes, this bit looks a lot better now.
>
>> +  } else {
>> +    Status = DiskIo->WriteDisk (DiskIo, MediaId, 0, Size, Image);
>> +  }
>> +
>> +  BlockIo->FlushBlocks(BlockIo);
>> +  // wait DMA finished
>> +  MicroSecondDelay (50000);
>> +
>> +  return Status;
>> +}
>> +
>> +STATIC
>> +EFI_STATUS
>> +HiKeyFastbootPlatformErasePartition (
>> +  IN CHAR8 *PartitionName
>> +  )
>> +{
>> +  return EFI_SUCCESS;
>> +}
>> +
>> +STATIC
>> +EFI_STATUS
>> +HiKeyFastbootPlatformGetVar (
>> +  IN  CHAR8   *Name,
>> +  OUT CHAR8   *Value
>> +  )
>> +{
>> +  EFI_STATUS               Status;
>> +  EFI_BLOCK_IO_PROTOCOL   *BlockIo;
>> +  UINT64                   PartitionSize;
>> +  FASTBOOT_PARTITION_LIST *Entry;
>> +  CHAR16                   PartitionNameUnicode[PARTITION_NAME_LENGTH];
>> +  BOOLEAN                  PartitionFound;
>> +  CHAR16                   DataUnicode[SERIAL_NUMBER_LENGTH + 1]; // terminated '\0'
>> +  UINTN                    VariableSize;
>> +  CHAR8                    PartTypeStr[] = "partition-type";
>> +  CHAR8                    PartSizeStr[] = "partition-size";
>> +
>> +  if (!AsciiStrCmp (Name, "max-download-size")) {
>> +    AsciiStrCpy (Value, FixedPcdGetPtr (PcdArmFastbootFlashLimit));
>> +  } else if (!AsciiStrCmp (Name, "product")) {
>> +    AsciiStrCpy (Value, FixedPcdGetPtr (PcdFirmwareVendor));
>> +  } else if (!AsciiStrCmp (Name, "serialno")) {
>> +    VariableSize = (SERIAL_NUMBER_LENGTH + 1) * sizeof (CHAR16);
>> +    Status = gRT->GetVariable (
>> +                    (CHAR16 *)L"SerialNo",
>> +                    &gHiKeyVariableGuid,
>> +                    NULL,
>> +                    &VariableSize,
>> +                    &DataUnicode
>> +                    );
>> +    if (EFI_ERROR (Status)) {
>> +      *Value = '\0';
>> +      return EFI_NOT_FOUND;
>> +    }
>> +    DataUnicode[SERIAL_NUMBER_LENGTH * sizeof(CHAR16)] = '\0';
>> +    UnicodeStrToAsciiStr (DataUnicode, Value);
>> +  } else if (!AsciiStrnCmp (Name, PartSizeStr, AsciiStrLen (PartSizeStr))) {
>> +    // skip ':', then copy
>> +    AsciiStrToUnicodeStr ((Name + AsciiStrLen (PartSizeStr) + 1), PartitionNameUnicode);
>> +    PartitionFound = FALSE;
>> +    Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&(mPartitionListHead));
>> +    while (!IsNull (&mPartitionListHead, &Entry->Link)) {
>> +      // Search the partition list for the partition named by PartitionName
>> +      if (StrCmp (Entry->PartitionName, PartitionNameUnicode) == 0) {
>> +        PartitionFound = TRUE;
>> +        break;
>> +      }
>> +
>> +     Entry = (FASTBOOT_PARTITION_LIST *) GetNextNode (&mPartitionListHead, &(Entry)->Link);
>> +    }
>> +    if (!PartitionFound) {
>> +      *Value = '\0';
>> +      return EFI_NOT_FOUND;
>> +    }
>> +
>> +    Status = gBS->OpenProtocol (
>> +                    Entry->PartitionHandle,
>> +                    &gEfiBlockIoProtocolGuid,
>> +                    (VOID **) &BlockIo,
>> +                    gImageHandle,
>> +                    NULL,
>> +                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
>> +                    );
>> +    if (EFI_ERROR (Status)) {
>> +      DEBUG ((DEBUG_ERROR, "Fastboot platform: couldn't open Block IO for flash: %r\n", Status));
>> +      *Value = '\0';
>> +      return EFI_NOT_FOUND;
>> +    }
>> +
>> +    // LastBlock counts from 0
>> +    PartitionSize = (BlockIo->Media->LastBlock + 1) * BlockIo->Media->BlockSize;
>> +    DEBUG ((DEBUG_INFO, "Fastboot platform: check for partition-size:%a 0x%llx\n", Name, PartitionSize));
>> +    AsciiSPrint (Value, PARTITION_SIZE_LENGTH, "0x%llx", PartitionSize);
>> +  } else if ( !AsciiStrnCmp (Name, PartTypeStr, AsciiStrLen (PartTypeStr))) {
>> +    DEBUG ((DEBUG_INFO, "Fastboot platform: check for partition-type:%a\n", Name + AsciiStrLen (PartTypeStr)));
>> +    // skip ':'
>> +    if (!AsciiStrCmp ((Name + AsciiStrLen (PartTypeStr) + 1) , "system") ||
>> +        !AsciiStrCmp ((Name + AsciiStrLen (PartTypeStr) + 1) , "userdata") ||
>> +        !AsciiStrCmp ((Name + AsciiStrLen (PartTypeStr) + 1) , "cache")) {
>> +      AsciiStrCpy (Value, "ext4");
>> +    } else {
>> +      AsciiStrCpy (Value, "raw");
>> +    }
>> +  } else {
>> +    *Value = '\0';
>> +  }
>> +  return EFI_SUCCESS;
>> +}
>> +
>> +STATIC
>> +EFI_STATUS
>> +HiKeyFastbootPlatformOemCommand (
>> +  IN  CHAR8   *Command
>> +  )
>> +{
>> +  if (AsciiStrCmp (Command, "Demonstrate") == 0) {
>> +    DEBUG ((DEBUG_ERROR, "ARM OEM Fastboot command 'Demonstrate' received.\n"));
>> +    return EFI_SUCCESS;
>> +  } else {
>> +    DEBUG ((DEBUG_ERROR,
>> +      "HiKey: Unrecognised Fastboot OEM command: %s\n",
>> +      Command
>> +      ));
>> +    return EFI_NOT_FOUND;
>> +  }
>> +}
>> +
>> +FASTBOOT_PLATFORM_PROTOCOL mPlatformProtocol = {
>> +  HiKeyFastbootPlatformInit,
>> +  HiKeyFastbootPlatformUnInit,
>> +  HiKeyFastbootPlatformFlashPartition,
>> +  HiKeyFastbootPlatformErasePartition,
>> +  HiKeyFastbootPlatformGetVar,
>> +  HiKeyFastbootPlatformOemCommand
>> +};
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +HiKeyFastbootPlatformEntryPoint (
>> +  IN EFI_HANDLE                            ImageHandle,
>> +  IN EFI_SYSTEM_TABLE                      *SystemTable
>> +  )
>> +{
>> +  return gBS->InstallProtocolInterface (
>> +                &ImageHandle,
>> +                &gAndroidFastbootPlatformProtocolGuid,
>> +                EFI_NATIVE_INTERFACE,
>> +                &mPlatformProtocol
>> +                );
>> +}
>> diff --git a/Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.inf b/Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.inf
>> new file mode 100644
>> index 0000000..353c6c3
>> --- /dev/null
>> +++ b/Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.inf
>> @@ -0,0 +1,61 @@
>> +#/** @file
>> +#
>> +#  Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
>> +#  Copyright (c) 2015-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                      = HiKeyFastbootDxe
>> +  FILE_GUID                      = 8e335c38-c4e1-494e-8011-37a858d9763d
>> +  MODULE_TYPE                    = UEFI_DRIVER
>> +  VERSION_STRING                 = 1.0
>> +  ENTRY_POINT                    = HiKeyFastbootPlatformEntryPoint
>> +
>> +[Sources.common]
>> +  HiKeyFastbootDxe.c
>> +
>> +[LibraryClasses]
>> +  BaseLib
>> +  BaseMemoryLib
>> +  DebugLib
>> +  DevicePathLib
>> +  MemoryAllocationLib
>> +  PcdLib
>> +  UefiBootServicesTableLib
>> +  UefiRuntimeServicesTableLib
>> +  UefiDriverEntryPoint
>> +  TimerLib
>
> Comment unaddressed from v3:
> ---
> Please insert TimerLib alphabetically.
> ---

OK
>
>> +
>> +[Protocols]
>> +  gAndroidFastbootPlatformProtocolGuid
>> +  gEfiBlockIoProtocolGuid
>> +  gEfiDiskIoProtocolGuid
>> +  gEfiSimpleTextOutProtocolGuid
>> +  gEfiEraseBlockProtocolGuid
>
> Comment unaddressed from v3:
> ---
> Please sort alphabetically.
> ---
OK
>
>> +
>> +[Packages]
>> +  EmbeddedPkg/EmbeddedPkg.dec
>> +  MdePkg/MdePkg.dec
>> +  MdeModulePkg/MdeModulePkg.dec
>> +  ArmPlatformPkg/ArmPlatformPkg.dec
>> +  ArmPlatformPkg/ArmVExpressPkg/ArmVExpressPkg.dec
>> +  ArmPkg/ArmPkg.dec
>> +  OpenPlatformPkg/Platforms/Hisilicon/HiKey/HiKey.dec
>
> Comment unaddressed from v3:
> ---
> Please sort alphabetically.
> ---
>
>> +
>> +[Guids]
>> +  gHiKeyVariableGuid
>> +
>> +[Pcd]
>> +  gArmPlatformTokenSpaceGuid.PcdFirmwareVendor
>> +  gHiKeyTokenSpaceGuid.PcdAndroidFastbootNvmDevicePath
>> +  gHiKeyTokenSpaceGuid.PcdArmFastbootFlashLimit
>> diff --git a/Platforms/Hisilicon/HiKey/Include/Guid/HiKeyVariable.h b/Platforms/Hisilicon/HiKey/Include/Guid/HiKeyVariable.h
>> new file mode 100644
>> index 0000000..56d5a0e
>> --- /dev/null
>> +++ b/Platforms/Hisilicon/HiKey/Include/Guid/HiKeyVariable.h
>> @@ -0,0 +1,24 @@
>> +/** @file
>> +*
>> +*  Copyright (c) 2013-2014, ARM Limited. All rights reserved.
>> +*  Copyright (c) 2015-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.
>> +*
>> +**/
>> +
>> +#ifndef __HIKEY_VARIABLE_H__
>> +#define __HIKEY_VARIABLE_H__
>> +
>> +#define HIKEY_VARIABLE_GUID \
>> +  { 0x66b8d063, 0x1daa, 0x4c60, { 0xb9, 0xf2, 0x55, 0x0d, 0x7e, 0xe1, 0x2f, 0x38 } }
>> +
>> +extern EFI_GUID gHiKeyVariableGuid;
>> +
>> +#endif /* __HIKEY_VARIABLE_H__ */
>> --
>> 2.7.4
>>
Leif Lindholm March 7, 2017, 10:04 a.m. UTC | #3
On Thu, Mar 02, 2017 at 09:32:29AM +0800, Haojian Zhuang wrote:
> On 2017/3/1 23:13, Leif Lindholm wrote:
> >On Wed, Feb 15, 2017 at 10:54:59PM +0800, Haojian Zhuang wrote:
> >>Support HiKey Fastboot driver for Fastboot App.
> >>
> >
> >I asked a few questions on v3, which I received no replies to.
> >Here I asked:
> >---
> >Question: I notice this version deletes the SPARSE_HEADER support,
> >which was one of the main differences compared to VEXpress driver.
> >Is this something you plan to introduce in future?
> >---
> 
> It'll be appended in future. There are two reasons that I remove it
> from this patch set.
> 1. There's some issue to download latest system.img into HiKey.
> 2. SPARSE_HEADER should be common case. It's better to parse it in
> AndroidFastboot App instead.

OK.
I would be quite keen to look into merging these versions back
together in the future, but it's fine for now.

> >
> >>Contributed-under: TianoCore Contribution Agreement 1.0
> >>Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
> >>---
> >> Platforms/Hisilicon/HiKey/HiKey.dec                |   1 +
> >> .../HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.c      | 672 +++++++++++++++++++++
> >> .../HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.inf    |  61 ++
> >> .../Hisilicon/HiKey/Include/Guid/HiKeyVariable.h   |  24 +
> >> 4 files changed, 758 insertions(+)
> >> create mode 100644 Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.c
> >> create mode 100644 Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.inf
> >> create mode 100644 Platforms/Hisilicon/HiKey/Include/Guid/HiKeyVariable.h
> >>
> >>diff --git a/Platforms/Hisilicon/HiKey/HiKey.dec b/Platforms/Hisilicon/HiKey/HiKey.dec
> >>index 537138e..17c6484 100644
> >>--- a/Platforms/Hisilicon/HiKey/HiKey.dec
> >>+++ b/Platforms/Hisilicon/HiKey/HiKey.dec
> >>@@ -30,6 +30,7 @@
> >>
> >> [Guids.common]
> >>   gHiKeyTokenSpaceGuid          =  { 0x91148425, 0xcdd2, 0x4830, { 0x8b, 0xd0, 0xc6, 0x1c, 0x6d, 0xea, 0x36, 0x21 } }
> >>+  gHiKeyVariableGuid            =  { 0x66b8d063, 0x1daa, 0x4c60, { 0xb9, 0xf2, 0x55, 0x0d, 0x7e, 0xe1, 0x2f, 0x38 } }
> >>
> >> [PcdsFixedAtBuild.common]
> >>   gHiKeyTokenSpaceGuid.PcdAndroidFastbootNvmDevicePath|L""|VOID*|0x00000001
> >>diff --git a/Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.c b/Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.c
> >>new file mode 100644
> >>index 0000000..2597f7a
> >>--- /dev/null
> >>+++ b/Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.c
> >>@@ -0,0 +1,672 @@
> >>+/** @file
> >>+
> >>+  Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
> >>+  Copyright (c) 2015-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.
> >>+
> >>+**/
> >>+
> >>+/*
> >>+  Implementation of the Android Fastboot Platform protocol, to be used by the
> >>+  Fastboot UEFI application, for Hisilicon HiKey platform.
> >>+*/
> >>+
> >>+#include <Protocol/AndroidFastbootPlatform.h>
> >>+#include <Protocol/BlockIo.h>
> >>+#include <Protocol/DiskIo.h>
> >>+#include <Protocol/EraseBlock.h>
> >>+#include <Protocol/SimpleTextOut.h>
> >>+
> >>+#include <Library/BaseLib.h>
> >>+#include <Library/BaseMemoryLib.h>
> >>+#include <Library/DebugLib.h>
> >>+#include <Library/DevicePathLib.h>
> >>+#include <Library/MemoryAllocationLib.h>
> >>+#include <Library/UefiBootServicesTableLib.h>
> >>+#include <Library/UefiRuntimeServicesTableLib.h>
> >>+#include <Library/PrintLib.h>
> >>+#include <Library/TimerLib.h>
> >>+
> >>+#include <Guid/HiKeyVariable.h>
> >>+
> >>+#define FLASH_DEVICE_PATH_SIZE(DevPath) ( GetDevicePathSize (DevPath) - \
> >>+                                            sizeof (EFI_DEVICE_PATH_PROTOCOL))
> >>+
> >>+#define PARTITION_NAME_MAX_LENGTH 72/2
> >>+
> >>+#define IS_ALPHA(Char) (((Char) <= L'z' && (Char) >= L'a') || \
> >>+                        ((Char) <= L'Z' && (Char) >= L'Z'))
> >>+#define IS_HEXCHAR(Char) (((Char) <= L'9' && (Char) >= L'0') || \
> >>+                          IS_ALPHA(Char))
> >>+
> >>+#define SERIAL_NUMBER_LENGTH                     16
> >>+#define BOOT_DEVICE_LENGTH                       16
> >>+
> >>+#define HIKEY_ERASE_SIZE                         (16 * 1024 * 1024)
> >>+#define HIKEY_ERASE_BLOCKS                       (HIKEY_ERASE_SIZE / EFI_PAGE_SIZE)
> >>+#define PARTITION_TYPE_STRING                    "partition-type"
> >>+#define PARTITION_SIZE_STRING                    "partition-size"
> >>+// length of a 12-byte hex string
> >>+#define PARTITION_SIZE_LENGTH                    12
> >>+#define PARTITION_NAME_LENGTH                    36 // CHAR16
> >
> >And here I asked:
> >---
> >Where does this limit come from? Specification?
> >---
> 
> Yes, it's from GPT spec.

OK - can you do one of:
- add a comment to that effect to any definition imported from the
  spec
  - or just group all of these together under a single comment
- rename definitions based on the GPT specification, adding GPT_ prefix
?

/
    Leif
diff mbox series

Patch

diff --git a/Platforms/Hisilicon/HiKey/HiKey.dec b/Platforms/Hisilicon/HiKey/HiKey.dec
index 537138e..17c6484 100644
--- a/Platforms/Hisilicon/HiKey/HiKey.dec
+++ b/Platforms/Hisilicon/HiKey/HiKey.dec
@@ -30,6 +30,7 @@ 
 
 [Guids.common]
   gHiKeyTokenSpaceGuid          =  { 0x91148425, 0xcdd2, 0x4830, { 0x8b, 0xd0, 0xc6, 0x1c, 0x6d, 0xea, 0x36, 0x21 } }
+  gHiKeyVariableGuid            =  { 0x66b8d063, 0x1daa, 0x4c60, { 0xb9, 0xf2, 0x55, 0x0d, 0x7e, 0xe1, 0x2f, 0x38 } }
 
 [PcdsFixedAtBuild.common]
   gHiKeyTokenSpaceGuid.PcdAndroidFastbootNvmDevicePath|L""|VOID*|0x00000001
diff --git a/Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.c b/Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.c
new file mode 100644
index 0000000..2597f7a
--- /dev/null
+++ b/Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.c
@@ -0,0 +1,672 @@ 
+/** @file
+
+  Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
+  Copyright (c) 2015-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.
+
+**/
+
+/*
+  Implementation of the Android Fastboot Platform protocol, to be used by the
+  Fastboot UEFI application, for Hisilicon HiKey platform.
+*/
+
+#include <Protocol/AndroidFastbootPlatform.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/DiskIo.h>
+#include <Protocol/EraseBlock.h>
+#include <Protocol/SimpleTextOut.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/PrintLib.h>
+#include <Library/TimerLib.h>
+
+#include <Guid/HiKeyVariable.h>
+
+#define FLASH_DEVICE_PATH_SIZE(DevPath) ( GetDevicePathSize (DevPath) - \
+                                            sizeof (EFI_DEVICE_PATH_PROTOCOL))
+
+#define PARTITION_NAME_MAX_LENGTH 72/2
+
+#define IS_ALPHA(Char) (((Char) <= L'z' && (Char) >= L'a') || \
+                        ((Char) <= L'Z' && (Char) >= L'Z'))
+#define IS_HEXCHAR(Char) (((Char) <= L'9' && (Char) >= L'0') || \
+                          IS_ALPHA(Char))
+
+#define SERIAL_NUMBER_LENGTH                     16
+#define BOOT_DEVICE_LENGTH                       16
+
+#define HIKEY_ERASE_SIZE                         (16 * 1024 * 1024)
+#define HIKEY_ERASE_BLOCKS                       (HIKEY_ERASE_SIZE / EFI_PAGE_SIZE)
+#define PARTITION_TYPE_STRING                    "partition-type"
+#define PARTITION_SIZE_STRING                    "partition-size"
+// length of a 12-byte hex string
+#define PARTITION_SIZE_LENGTH                    12
+#define PARTITION_NAME_LENGTH                    36 // CHAR16
+
+/*
+ * struct entry_head {
+ *   unsigned char        magic[8];   // "ENTRYHDR"
+ *   unsigned char        name[8];    // "primary"/"second"
+ *   unsigned int         start_lba;
+ *   unsigned int         count_lba;
+ *   unsigned int         flag;
+ * }
+ *
+ * ptable:
+ *   ------------------------------------------------------
+ *   | head (primary) | content | head (second) | content |
+ *   ------------------------------------------------------
+ */
+
+#define HIKEY_PTABLE_HEAD_MAGIC_LEN              8
+#define HIKEY_PTABLE_HEAD_NAME_LEN               8
+#define HIKEY_PTABLE_HEAD_SIZE                   28
+#define HIKEY_PTABLE_CONTENT_OFFSET              512
+
+
+typedef struct _FASTBOOT_PARTITION_LIST {
+  LIST_ENTRY  Link;
+  CHAR16      PartitionName[PARTITION_NAME_MAX_LENGTH];
+  EFI_HANDLE  PartitionHandle;
+  EFI_LBA     Lba;
+} FASTBOOT_PARTITION_LIST;
+
+STATIC LIST_ENTRY mPartitionListHead;
+
+/*
+  Helper to free the partition list
+*/
+STATIC
+VOID
+FreePartitionList (
+  VOID
+  )
+{
+  FASTBOOT_PARTITION_LIST *Entry;
+  FASTBOOT_PARTITION_LIST *NextEntry;
+
+  Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&mPartitionListHead);
+  while (!IsNull (&mPartitionListHead, &Entry->Link)) {
+    NextEntry = (FASTBOOT_PARTITION_LIST *) GetNextNode (&mPartitionListHead, &Entry->Link);
+
+    RemoveEntryList (&Entry->Link);
+    FreePool (Entry);
+
+    Entry = NextEntry;
+  }
+}
+/*
+  Read the PartitionName fields from the GPT partition entries, putting them
+  into an allocated array that should later be freed.
+*/
+STATIC
+EFI_STATUS
+ReadPartitionEntries (
+  IN  EFI_BLOCK_IO_PROTOCOL *BlockIo,
+  OUT EFI_PARTITION_ENTRY  **PartitionEntries
+  )
+{
+  UINTN                       EntrySize;
+  UINTN                       NumEntries;
+  UINTN                       BufferSize;
+  UINT32                      MediaId;
+  EFI_PARTITION_TABLE_HEADER *GptHeader;
+  EFI_STATUS                  Status;
+
+  MediaId = BlockIo->Media->MediaId;
+
+  //
+  // Read size of Partition entry and number of entries from GPT header
+  //
+
+  GptHeader = AllocatePool (BlockIo->Media->BlockSize);
+  if (GptHeader == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Status = BlockIo->ReadBlocks (BlockIo, MediaId, 1, BlockIo->Media->BlockSize, GptHeader);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  // Check there is a GPT on the media
+  if (GptHeader->Header.Signature != EFI_PTAB_HEADER_ID ||
+      GptHeader->MyLBA != 1) {
+    DEBUG ((DEBUG_ERROR,
+      "Fastboot platform: No GPT on flash. "
+      "Fastboot on HiKey does not support MBR.\n"
+      ));
+    return EFI_DEVICE_ERROR;
+  }
+
+  EntrySize = GptHeader->SizeOfPartitionEntry;
+  NumEntries = GptHeader->NumberOfPartitionEntries;
+
+  FreePool (GptHeader);
+
+  ASSERT (EntrySize != 0);
+  ASSERT (NumEntries != 0);
+
+  BufferSize = ALIGN_VALUE (EntrySize * NumEntries, BlockIo->Media->BlockSize);
+  *PartitionEntries = AllocatePool (BufferSize);
+  if (PartitionEntries == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Status = BlockIo->ReadBlocks (BlockIo, MediaId, 2, BufferSize, (VOID *) *PartitionEntries);
+  if (EFI_ERROR (Status)) {
+    FreePool (PartitionEntries);
+    return Status;
+  }
+
+  return Status;
+}
+
+
+STATIC
+EFI_STATUS
+CreateGptPartitionEntry (
+  IN EFI_HANDLE                      *AllHandles,
+  IN UINTN                            LoopIndex,
+  IN HARDDRIVE_DEVICE_PATH           *PartitionNode,
+  IN EFI_PARTITION_ENTRY             *PartitionEntries
+  )
+{
+  FASTBOOT_PARTITION_LIST            *Entry;
+
+  // Create entry
+  Entry = AllocatePool (sizeof (FASTBOOT_PARTITION_LIST));
+  if (Entry == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  // Copy handle and partition name
+  Entry->PartitionHandle = AllHandles[LoopIndex];
+  StrnCpy (
+    Entry->PartitionName,
+    PartitionEntries[PartitionNode->PartitionNumber - 1].PartitionName, // Partition numbers start from 1.
+    PARTITION_NAME_MAX_LENGTH
+    );
+  Entry->Lba = PartitionEntries[PartitionNode->PartitionNumber - 1].StartingLBA;
+  InsertTailList (&mPartitionListHead, &Entry->Link);
+
+  // Print a debug message if the partition label is empty or looks like
+  // garbage.
+  if (!IS_ALPHA (Entry->PartitionName[0])) {
+    DEBUG ((DEBUG_WARN,
+      "Warning: Partition %d doesn't seem to have a GPT partition label. "
+      "You won't be able to flash it with Fastboot.\n",
+      PartitionNode->PartitionNumber
+      ));
+  }
+  return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+CreatePartitionEntry (
+  IN  EFI_HANDLE                     *AllHandles,
+  IN  UINTN                           LoopIndex,
+  IN  EFI_DEVICE_PATH_PROTOCOL       *FlashDevicePath,
+  IN  EFI_DEVICE_PATH_PROTOCOL       *DevicePath,
+  IN  EFI_PARTITION_ENTRY            *PartitionEntries
+  )
+{
+  EFI_DEVICE_PATH_PROTOCOL           *NextNode;
+  FASTBOOT_PARTITION_LIST            *Entry;
+  HARDDRIVE_DEVICE_PATH              *PartitionNode;
+
+  // Fill out if it isn't a sub-device of the flash device
+  if (CompareMem (DevicePath, FlashDevicePath, FLASH_DEVICE_PATH_SIZE (FlashDevicePath))) {
+    return EFI_SUCCESS;
+  }
+  // Device path starts with path of flash device. Check it isn't the flash
+  // device itself.
+  NextNode = NextDevicePathNode (DevicePath);
+  if (IsDevicePathEndType (NextNode)) {
+    // Create entry
+    Entry = AllocatePool (sizeof (FASTBOOT_PARTITION_LIST));
+    if (Entry == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    // Copy handle and partition name
+    Entry->PartitionHandle = AllHandles[LoopIndex];
+    StrCpy (Entry->PartitionName, L"ptable");
+    InsertTailList (&mPartitionListHead, &Entry->Link);
+    return EFI_SUCCESS;
+  }
+
+  // Assert that this device path node represents a partition.
+  ASSERT (NextNode->Type == MEDIA_DEVICE_PATH &&
+          NextNode->SubType == MEDIA_HARDDRIVE_DP);
+
+  PartitionNode = (HARDDRIVE_DEVICE_PATH *) NextNode;
+
+  // Assert that the partition type is GPT. ReadPartitionEntries checks for
+  // presence of a GPT, so we should never find MBR partitions.
+  // ("MBRType" is a misnomer - this field is actually called "Partition
+  //  Format")
+  ASSERT (PartitionNode->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER);
+
+  // The firmware may install a handle for "partition 0", representing the
+  // whole device. Ignore it.
+  if (PartitionNode->PartitionNumber == 0) {
+    return EFI_SUCCESS;
+  }
+  return CreateGptPartitionEntry (AllHandles, LoopIndex, PartitionNode, PartitionEntries);
+}
+
+/*
+  Initialise: Open the Android NVM device and find the partitions on it. Save them in
+  a list along with the "PartitionName" fields for their GPT entries.
+  We will use these partition names as the key in
+  HiKeyFastbootPlatformFlashPartition.
+*/
+STATIC
+EFI_STATUS
+HiKeyFastbootPlatformInit (
+  VOID
+  )
+{
+  EFI_STATUS                          Status;
+  EFI_DEVICE_PATH_PROTOCOL           *FlashDevicePath;
+  EFI_DEVICE_PATH_PROTOCOL           *FlashDevicePathDup;
+  EFI_DEVICE_PATH_PROTOCOL           *DevicePath;
+  UINTN                               NumHandles;
+  EFI_HANDLE                         *AllHandles;
+  UINTN                               LoopIndex;
+  EFI_HANDLE                          FlashHandle;
+  EFI_BLOCK_IO_PROTOCOL              *FlashBlockIo;
+  EFI_PARTITION_ENTRY                *PartitionEntries;
+
+  InitializeListHead (&mPartitionListHead);
+
+  //
+  // Get EFI_HANDLES for all the partitions on the block devices pointed to by
+  // PcdFastbootFlashDevicePath, also saving their GPT partition labels.
+  // There's no way to find all of a device's children, so we get every handle
+  // in the system supporting EFI_BLOCK_IO_PROTOCOL and then filter out ones
+  // that don't represent partitions on the flash device.
+  //
+
+  FlashDevicePath = ConvertTextToDevicePath ((CHAR16*)FixedPcdGetPtr (PcdAndroidFastbootNvmDevicePath));
+
+  //
+  // Open the Disk IO protocol on the flash device - this will be used to read
+  // partition names out of the GPT entries
+  //
+  // Create another device path pointer because LocateDevicePath will modify it.
+  FlashDevicePathDup = FlashDevicePath;
+  Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &FlashDevicePathDup, &FlashHandle);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Warning: Couldn't locate Android NVM device (status: %r)\n", Status));
+    // Failing to locate partitions should not prevent to do other Android FastBoot actions
+    return EFI_SUCCESS;
+  }
+
+  Status = gBS->OpenProtocol (
+                  FlashHandle,
+                  &gEfiBlockIoProtocolGuid,
+                  (VOID **) &FlashBlockIo,
+                  gImageHandle,
+                  NULL,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Fastboot platform: Couldn't open Android NVM device (status: %r)\n", Status));
+    return EFI_DEVICE_ERROR;
+  }
+
+  // Read the GPT partition entry array into memory so we can get the partition names
+  Status = ReadPartitionEntries (FlashBlockIo, &PartitionEntries);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Warning: Failed to read partitions from Android NVM device (status: %r)\n", Status));
+    // Failing to locate partitions should not prevent to do other Android FastBoot actions
+    return EFI_SUCCESS;
+  }
+
+  // Get every Block IO protocol instance installed in the system
+  Status = gBS->LocateHandleBuffer (
+                  ByProtocol,
+                  &gEfiBlockIoProtocolGuid,
+                  NULL,
+                  &NumHandles,
+                  &AllHandles
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  // Filter out handles that aren't children of the flash device
+  for (LoopIndex = 0; LoopIndex < NumHandles; LoopIndex++) {
+    // Get the device path for the handle
+    Status = gBS->OpenProtocol (
+                    AllHandles[LoopIndex],
+                    &gEfiDevicePathProtocolGuid,
+                    (VOID **) &DevicePath,
+                    gImageHandle,
+                    NULL,
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                    );
+    ASSERT_EFI_ERROR (Status);
+
+    Status = CreatePartitionEntry (
+               AllHandles,
+               LoopIndex,
+               FlashDevicePath,
+               DevicePath,
+               PartitionEntries
+               );
+    if (EFI_ERROR (Status)) {
+      FreePartitionList ();
+      goto Exit;
+    }
+  }
+
+Exit:
+  FreePool (PartitionEntries);
+  FreePool (FlashDevicePath);
+  FreePool (AllHandles);
+  return Status;
+
+}
+
+STATIC
+VOID
+HiKeyFastbootPlatformUnInit (
+  VOID
+  )
+{
+  FreePartitionList ();
+}
+
+STATIC
+VOID *
+WritePartition (
+  IN VOID                    *Image,
+  IN UINTN                   Size,
+  IN EFI_DISK_IO_PROTOCOL    *DiskIo,
+  IN EFI_BLOCK_IO_PROTOCOL   *BlockIo,
+  IN CHAR8                   *Name
+  )
+{
+  UINT32                     EntrySize, EntryOffset;
+  EFI_STATUS                 Status;
+  VOID                       *Buffer;
+
+  Buffer = Image;
+  // not a string with terminated '\0'
+  if (AsciiStrnCmp (Buffer, "ENTRYHDR", HIKEY_PTABLE_HEAD_MAGIC_LEN) != 0) {
+    DEBUG ((DEBUG_ERROR, "unknown ptable image\n"));
+    return NULL;
+  }
+  Buffer += HIKEY_PTABLE_HEAD_MAGIC_LEN;
+  // not a string with terminated '\0'
+  if (AsciiStrnCmp (Buffer, Name, HIKEY_PTABLE_HEAD_NAME_LEN) != 0) {
+    DEBUG ((DEBUG_ERROR, "unknown ptable image\n"));
+    return NULL;
+  }
+  Buffer += HIKEY_PTABLE_HEAD_NAME_LEN;
+  EntryOffset = *(UINT32 *)Buffer * BlockIo->Media->BlockSize;
+  Buffer += sizeof (UINT32);
+  EntrySize = *(UINT32 *)Buffer * BlockIo->Media->BlockSize;
+  if ((EntrySize + HIKEY_PTABLE_CONTENT_OFFSET) > Size) {
+    DEBUG ((DEBUG_ERROR, "Entry size doesn't match\n"));
+    return NULL;
+  }
+  Buffer = Image + HIKEY_PTABLE_CONTENT_OFFSET;
+  Status = DiskIo->WriteDisk (DiskIo, BlockIo->Media->MediaId, EntryOffset, EntrySize, Buffer);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Can't flush partition table\n"));
+    return NULL;
+  }
+  Buffer += EntrySize;
+  return Buffer;
+}
+
+STATIC
+EFI_STATUS
+HiKeyFastbootPlatformFlashPartition (
+  IN CHAR8  *PartitionName,
+  IN UINTN   Size,
+  IN VOID   *Image
+  )
+{
+  EFI_STATUS               Status;
+  EFI_BLOCK_IO_PROTOCOL   *BlockIo;
+  EFI_DISK_IO_PROTOCOL    *DiskIo;
+  UINT32                   MediaId;
+  UINTN                    PartitionSize;
+  FASTBOOT_PARTITION_LIST *Entry;
+  CHAR16                   PartitionNameUnicode[PARTITION_NAME_LENGTH];
+  BOOLEAN                  PartitionFound;
+  VOID                    *Buffer;
+
+
+  AsciiStrToUnicodeStr (PartitionName, PartitionNameUnicode);
+
+  PartitionFound = FALSE;
+  Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&(mPartitionListHead));
+  while (!IsNull (&mPartitionListHead, &Entry->Link)) {
+    // Search the partition list for the partition named by PartitionName
+    if (StrCmp (Entry->PartitionName, PartitionNameUnicode) == 0) {
+      PartitionFound = TRUE;
+      break;
+    }
+
+   Entry = (FASTBOOT_PARTITION_LIST *) GetNextNode (&mPartitionListHead, &(Entry)->Link);
+  }
+  if (!PartitionFound) {
+    return EFI_NOT_FOUND;
+  }
+
+  Status = gBS->OpenProtocol (
+                  Entry->PartitionHandle,
+                  &gEfiBlockIoProtocolGuid,
+                  (VOID **) &BlockIo,
+                  gImageHandle,
+                  NULL,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Fastboot platform: couldn't open Block IO for flash: %r\n", Status));
+    return EFI_NOT_FOUND;
+  }
+
+  // Check image will fit on device
+  // LastBlock counts from 0
+  PartitionSize = (BlockIo->Media->LastBlock + 1) * BlockIo->Media->BlockSize;
+  if (PartitionSize < Size) {
+    DEBUG ((DEBUG_ERROR, "Partition not big enough.\n"));
+    DEBUG ((DEBUG_ERROR, "Partition Size:\t%ld\nImage Size:\t%ld\n", PartitionSize, Size));
+
+    return EFI_VOLUME_FULL;
+  }
+
+  MediaId = BlockIo->Media->MediaId;
+
+  Status = gBS->OpenProtocol (
+                  Entry->PartitionHandle,
+                  &gEfiDiskIoProtocolGuid,
+                  (VOID **) &DiskIo,
+                  gImageHandle,
+                  NULL,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  if (AsciiStrCmp (PartitionName, "ptable") == 0) {
+    Buffer = WritePartition (Image, Size, DiskIo, BlockIo, "primary");
+    if (Buffer == NULL) {
+      return EFI_DEVICE_ERROR;
+    }
+    if (Size >= (2 * PartitionSize)) {
+      Buffer = WritePartition (Buffer, Size, DiskIo, BlockIo, "second");
+      if (Buffer == NULL) {
+        return EFI_DEVICE_ERROR;
+      }
+    }
+  } else {
+    Status = DiskIo->WriteDisk (DiskIo, MediaId, 0, Size, Image);
+  }
+
+  BlockIo->FlushBlocks(BlockIo);
+  // wait DMA finished
+  MicroSecondDelay (50000);
+
+  return Status;
+}
+
+STATIC
+EFI_STATUS
+HiKeyFastbootPlatformErasePartition (
+  IN CHAR8 *PartitionName
+  )
+{
+  return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+HiKeyFastbootPlatformGetVar (
+  IN  CHAR8   *Name,
+  OUT CHAR8   *Value
+  )
+{
+  EFI_STATUS               Status;
+  EFI_BLOCK_IO_PROTOCOL   *BlockIo;
+  UINT64                   PartitionSize;
+  FASTBOOT_PARTITION_LIST *Entry;
+  CHAR16                   PartitionNameUnicode[PARTITION_NAME_LENGTH];
+  BOOLEAN                  PartitionFound;
+  CHAR16                   DataUnicode[SERIAL_NUMBER_LENGTH + 1]; // terminated '\0'
+  UINTN                    VariableSize;
+  CHAR8                    PartTypeStr[] = "partition-type";
+  CHAR8                    PartSizeStr[] = "partition-size";
+
+  if (!AsciiStrCmp (Name, "max-download-size")) {
+    AsciiStrCpy (Value, FixedPcdGetPtr (PcdArmFastbootFlashLimit));
+  } else if (!AsciiStrCmp (Name, "product")) {
+    AsciiStrCpy (Value, FixedPcdGetPtr (PcdFirmwareVendor));
+  } else if (!AsciiStrCmp (Name, "serialno")) {
+    VariableSize = (SERIAL_NUMBER_LENGTH + 1) * sizeof (CHAR16);
+    Status = gRT->GetVariable (
+                    (CHAR16 *)L"SerialNo",
+                    &gHiKeyVariableGuid,
+                    NULL,
+                    &VariableSize,
+                    &DataUnicode
+                    );
+    if (EFI_ERROR (Status)) {
+      *Value = '\0';
+      return EFI_NOT_FOUND;
+    }
+    DataUnicode[SERIAL_NUMBER_LENGTH * sizeof(CHAR16)] = '\0';
+    UnicodeStrToAsciiStr (DataUnicode, Value);
+  } else if (!AsciiStrnCmp (Name, PartSizeStr, AsciiStrLen (PartSizeStr))) {
+    // skip ':', then copy
+    AsciiStrToUnicodeStr ((Name + AsciiStrLen (PartSizeStr) + 1), PartitionNameUnicode);
+    PartitionFound = FALSE;
+    Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&(mPartitionListHead));
+    while (!IsNull (&mPartitionListHead, &Entry->Link)) {
+      // Search the partition list for the partition named by PartitionName
+      if (StrCmp (Entry->PartitionName, PartitionNameUnicode) == 0) {
+        PartitionFound = TRUE;
+        break;
+      }
+
+     Entry = (FASTBOOT_PARTITION_LIST *) GetNextNode (&mPartitionListHead, &(Entry)->Link);
+    }
+    if (!PartitionFound) {
+      *Value = '\0';
+      return EFI_NOT_FOUND;
+    }
+
+    Status = gBS->OpenProtocol (
+                    Entry->PartitionHandle,
+                    &gEfiBlockIoProtocolGuid,
+                    (VOID **) &BlockIo,
+                    gImageHandle,
+                    NULL,
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                    );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "Fastboot platform: couldn't open Block IO for flash: %r\n", Status));
+      *Value = '\0';
+      return EFI_NOT_FOUND;
+    }
+
+    // LastBlock counts from 0
+    PartitionSize = (BlockIo->Media->LastBlock + 1) * BlockIo->Media->BlockSize;
+    DEBUG ((DEBUG_INFO, "Fastboot platform: check for partition-size:%a 0x%llx\n", Name, PartitionSize));
+    AsciiSPrint (Value, PARTITION_SIZE_LENGTH, "0x%llx", PartitionSize);
+  } else if ( !AsciiStrnCmp (Name, PartTypeStr, AsciiStrLen (PartTypeStr))) {
+    DEBUG ((DEBUG_INFO, "Fastboot platform: check for partition-type:%a\n", Name + AsciiStrLen (PartTypeStr)));
+    // skip ':'
+    if (!AsciiStrCmp ((Name + AsciiStrLen (PartTypeStr) + 1) , "system") ||
+        !AsciiStrCmp ((Name + AsciiStrLen (PartTypeStr) + 1) , "userdata") ||
+        !AsciiStrCmp ((Name + AsciiStrLen (PartTypeStr) + 1) , "cache")) {
+      AsciiStrCpy (Value, "ext4");
+    } else {
+      AsciiStrCpy (Value, "raw");
+    }
+  } else {
+    *Value = '\0';
+  }
+  return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+HiKeyFastbootPlatformOemCommand (
+  IN  CHAR8   *Command
+  )
+{
+  if (AsciiStrCmp (Command, "Demonstrate") == 0) {
+    DEBUG ((DEBUG_ERROR, "ARM OEM Fastboot command 'Demonstrate' received.\n"));
+    return EFI_SUCCESS;
+  } else {
+    DEBUG ((DEBUG_ERROR,
+      "HiKey: Unrecognised Fastboot OEM command: %s\n",
+      Command
+      ));
+    return EFI_NOT_FOUND;
+  }
+}
+
+FASTBOOT_PLATFORM_PROTOCOL mPlatformProtocol = {
+  HiKeyFastbootPlatformInit,
+  HiKeyFastbootPlatformUnInit,
+  HiKeyFastbootPlatformFlashPartition,
+  HiKeyFastbootPlatformErasePartition,
+  HiKeyFastbootPlatformGetVar,
+  HiKeyFastbootPlatformOemCommand
+};
+
+EFI_STATUS
+EFIAPI
+HiKeyFastbootPlatformEntryPoint (
+  IN EFI_HANDLE                            ImageHandle,
+  IN EFI_SYSTEM_TABLE                      *SystemTable
+  )
+{
+  return gBS->InstallProtocolInterface (
+                &ImageHandle,
+                &gAndroidFastbootPlatformProtocolGuid,
+                EFI_NATIVE_INTERFACE,
+                &mPlatformProtocol
+                );
+}
diff --git a/Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.inf b/Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.inf
new file mode 100644
index 0000000..353c6c3
--- /dev/null
+++ b/Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.inf
@@ -0,0 +1,61 @@ 
+#/** @file
+#
+#  Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
+#  Copyright (c) 2015-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                      = HiKeyFastbootDxe
+  FILE_GUID                      = 8e335c38-c4e1-494e-8011-37a858d9763d
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = HiKeyFastbootPlatformEntryPoint
+
+[Sources.common]
+  HiKeyFastbootDxe.c
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  DevicePathLib
+  MemoryAllocationLib
+  PcdLib
+  UefiBootServicesTableLib
+  UefiRuntimeServicesTableLib
+  UefiDriverEntryPoint
+  TimerLib
+
+[Protocols]
+  gAndroidFastbootPlatformProtocolGuid
+  gEfiBlockIoProtocolGuid
+  gEfiDiskIoProtocolGuid
+  gEfiSimpleTextOutProtocolGuid
+  gEfiEraseBlockProtocolGuid
+
+[Packages]
+  EmbeddedPkg/EmbeddedPkg.dec
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  ArmPlatformPkg/ArmPlatformPkg.dec
+  ArmPlatformPkg/ArmVExpressPkg/ArmVExpressPkg.dec
+  ArmPkg/ArmPkg.dec
+  OpenPlatformPkg/Platforms/Hisilicon/HiKey/HiKey.dec
+
+[Guids]
+  gHiKeyVariableGuid
+
+[Pcd]
+  gArmPlatformTokenSpaceGuid.PcdFirmwareVendor
+  gHiKeyTokenSpaceGuid.PcdAndroidFastbootNvmDevicePath
+  gHiKeyTokenSpaceGuid.PcdArmFastbootFlashLimit
diff --git a/Platforms/Hisilicon/HiKey/Include/Guid/HiKeyVariable.h b/Platforms/Hisilicon/HiKey/Include/Guid/HiKeyVariable.h
new file mode 100644
index 0000000..56d5a0e
--- /dev/null
+++ b/Platforms/Hisilicon/HiKey/Include/Guid/HiKeyVariable.h
@@ -0,0 +1,24 @@ 
+/** @file
+*
+*  Copyright (c) 2013-2014, ARM Limited. All rights reserved.
+*  Copyright (c) 2015-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.
+*
+**/
+
+#ifndef __HIKEY_VARIABLE_H__
+#define __HIKEY_VARIABLE_H__
+
+#define HIKEY_VARIABLE_GUID \
+  { 0x66b8d063, 0x1daa, 0x4c60, { 0xb9, 0xf2, 0x55, 0x0d, 0x7e, 0xe1, 0x2f, 0x38 } }
+
+extern EFI_GUID gHiKeyVariableGuid;
+
+#endif /* __HIKEY_VARIABLE_H__ */