Platforms/HiKey: update fastboot driver

Since sparse image is already implemented in AndroidFastbootApp, update
the HiKeyFastbootDxe driver too.

Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
diff --git a/Platforms/Hisilicon/HiKey/HiKey.dsc b/Platforms/Hisilicon/HiKey/HiKey.dsc
index 0413599..98353d8 100644
--- a/Platforms/Hisilicon/HiKey/HiKey.dsc
+++ b/Platforms/Hisilicon/HiKey/HiKey.dsc
@@ -60,6 +60,7 @@
   MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf

   SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf

 

+  AbootimgLib|EmbeddedPkg/Library/AbootimgLib/AbootimgLib.inf

   FdtLib|EmbeddedPkg/Library/FdtLib/FdtLib.inf

   UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf

   PlatformBootManagerLib|OpenPlatformPkg/Platforms/Hisilicon/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf

diff --git a/Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.c b/Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.c
index 568c08b..d1ae898 100644
--- a/Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.c
+++ b/Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.c
@@ -36,33 +36,18 @@
 

 #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 BOOTIMG_KERNEL_ARGS_SIZE  1024

+#define PARTITION_NAME_MAX_LENGTH (72/2)

 

 typedef struct _FASTBOOT_PARTITION_LIST {

   LIST_ENTRY  Link;

   CHAR16      PartitionName[PARTITION_NAME_MAX_LENGTH];

-  EFI_HANDLE  PartitionHandle;

-  EFI_LBA     Lba;

+  EFI_LBA     StartingLBA;

+  EFI_LBA     EndingLBA;

 } FASTBOOT_PARTITION_LIST;

 

-STATIC LIST_ENTRY mPartitionListHead;

-

+STATIC LIST_ENTRY                       mPartitionListHead;

+STATIC EFI_HANDLE                       mFlashHandle;

+STATIC EFI_BLOCK_IO_PROTOCOL           *mFlashBlockIo;

 STATIC EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *mTextOut;

 

 /*

@@ -87,6 +72,7 @@
     Entry = NextEntry;

   }

 }

+

 /*

   Read the PartitionName fields from the GPT partition entries, putting them

   into an allocated array that should later be freed.

@@ -95,88 +81,86 @@
 EFI_STATUS

 ReadPartitionEntries (

   IN  EFI_BLOCK_IO_PROTOCOL *BlockIo,

-  OUT EFI_PARTITION_ENTRY  **PartitionEntries

+  OUT EFI_PARTITION_ENTRY  **PartitionEntries,

+  OUT UINTN                 *PartitionNumbers

   )

 {

-  UINTN                       EntrySize;

-  UINTN                       NumEntries;

-  UINTN                       BufferSize;

-  UINT32                      MediaId;

-  EFI_PARTITION_TABLE_HEADER *GptHeader;

   EFI_STATUS                  Status;

+  UINT32                      MediaId;

+  UINTN                       BlockSize;

+  UINTN                       PageCount;

+  UINTN                       Count, EndLBA;

+  EFI_PARTITION_TABLE_HEADER *GptHeader;

+  EFI_PARTITION_ENTRY        *Entry;

+  VOID                       *Buffer;

+

+  if ((PartitionEntries == NULL) || (PartitionNumbers == NULL)) {

+    return EFI_INVALID_PARAMETER;

+  }

 

   MediaId = BlockIo->Media->MediaId;

+  BlockSize = BlockIo->Media->BlockSize;

 

   //

   // Read size of Partition entry and number of entries from GPT header

   //

 

-  GptHeader = AllocatePool (BlockIo->Media->BlockSize);

-  if (GptHeader == NULL) {

+  PageCount = EFI_SIZE_TO_PAGES (34 * BlockSize);

+  Buffer = AllocatePages (PageCount);

+  if (Buffer == NULL) {

     return EFI_OUT_OF_RESOURCES;

   }

 

-  Status = BlockIo->ReadBlocks (BlockIo, MediaId, 1, BlockIo->Media->BlockSize, (VOID *) GptHeader);

+  Status = BlockIo->ReadBlocks (BlockIo, MediaId, 0, PageCount * EFI_PAGE_SIZE, Buffer);

   if (EFI_ERROR (Status)) {

     return Status;

   }

+  GptHeader = (EFI_PARTITION_TABLE_HEADER *)(Buffer + BlockSize);

 

   // Check there is a GPT on the media

   if (GptHeader->Header.Signature != EFI_PTAB_HEADER_ID ||

       GptHeader->MyLBA != 1) {

-    DEBUG ((DEBUG_ERROR,

+    DEBUG ((EFI_D_ERROR,

       "Fastboot platform: No GPT on flash. "

       "Fastboot on Versatile Express 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;

+  Entry = (EFI_PARTITION_ENTRY *)(Buffer + (2 * BlockSize));

+  EndLBA = GptHeader->FirstUsableLBA - 1;

+  Count = 0;

+  while (1) {

+    if ((Entry->StartingLBA > EndLBA) && (Entry->EndingLBA <= GptHeader->LastUsableLBA)) {

+      Count++;

+      EndLBA = Entry->EndingLBA;

+      Entry++;

+    } else {

+      break;

+    }

+  }

+  if (Count == 0) {

+    return EFI_INVALID_PARAMETER;

+  }

+  if (Count > GptHeader->NumberOfPartitionEntries) {

+    Count = GptHeader->NumberOfPartitionEntries;

   }

 

-  Status = BlockIo->ReadBlocks (BlockIo, MediaId, 2, BufferSize, (VOID *) *PartitionEntries);

-  if (EFI_ERROR (Status)) {

-    FreePool (PartitionEntries);

-    return Status;

-  }

-

-  return Status;

+  *PartitionEntries = (EFI_PARTITION_ENTRY *)((UINTN)Buffer + (2 * BlockSize));

+  *PartitionNumbers = Count;

+  return EFI_SUCCESS;

 }

 

-

-/*

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

-*/

 EFI_STATUS

-HiKeyFastbootPlatformInit (

+LoadPtable (

   VOID

   )

 {

   EFI_STATUS                          Status;

   EFI_DEVICE_PATH_PROTOCOL           *FlashDevicePath;

   EFI_DEVICE_PATH_PROTOCOL           *FlashDevicePathDup;

-  EFI_DEVICE_PATH_PROTOCOL           *DevicePath;

-  EFI_DEVICE_PATH_PROTOCOL           *NextNode;

-  HARDDRIVE_DEVICE_PATH              *PartitionNode;

-  UINTN                               NumHandles;

-  EFI_HANDLE                         *AllHandles;

+  UINTN                               PartitionNumbers;

   UINTN                               LoopIndex;

-  EFI_HANDLE                          FlashHandle;

-  EFI_BLOCK_IO_PROTOCOL              *FlashBlockIo;

   EFI_PARTITION_ENTRY                *PartitionEntries;

   FASTBOOT_PARTITION_LIST            *Entry;

 

@@ -197,26 +181,22 @@
   // 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);

+  Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &FlashDevicePathDup, &mFlashHandle);

   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,

+                  mFlashHandle,

                   &gEfiBlockIoProtocolGuid,

-                  (VOID **) &FlashBlockIo,

+                  (VOID **) &mFlashBlockIo,

                   gImageHandle,

                   NULL,

                   EFI_OPEN_PROTOCOL_GET_PROTOCOL

@@ -227,115 +207,49 @@
   }

 

   // Read the GPT partition entry array into memory so we can get the partition names

-  Status = ReadPartitionEntries (FlashBlockIo, &PartitionEntries);

+  Status = ReadPartitionEntries (mFlashBlockIo, &PartitionEntries, &PartitionNumbers);

   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);

-

-    // Check if it is a sub-device of the flash device

-    if (!CompareMem (DevicePath, FlashDevicePath, FLASH_DEVICE_PATH_SIZE (FlashDevicePath))) {

-      // 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) {

-          Status = EFI_OUT_OF_RESOURCES;

-          FreePartitionList ();

-          goto Exit;

-        }

-

-        // Copy handle and partition name

-        Entry->PartitionHandle = AllHandles[LoopIndex];

-        StrCpy (Entry->PartitionName, L"ptable");

-        InsertTailList (&mPartitionListHead, &Entry->Link);

-        continue;

-      }

-

-      // 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) {

-        continue;

-      }

-

-      //

-      // Add the partition handle to the list

-      //

-

-      // Create entry

-      Entry = AllocatePool (sizeof (FASTBOOT_PARTITION_LIST));

-      if (Entry == NULL) {

-        Status = EFI_OUT_OF_RESOURCES;

-        FreePartitionList ();

-        goto Exit;

-      }

-

-      // 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_ERROR,

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

-          ));

-      }

+  for (LoopIndex = 0; LoopIndex < PartitionNumbers; LoopIndex++) {

+    // Create entry

+    Entry = AllocatePool (sizeof (FASTBOOT_PARTITION_LIST));

+    if (Entry == NULL) {

+      Status = EFI_BUFFER_TOO_SMALL;

+      FreePartitionList ();

+      goto Exit;

     }

+    StrnCpy (

+      Entry->PartitionName,

+      PartitionEntries[LoopIndex].PartitionName,

+      PARTITION_NAME_MAX_LENGTH

+      );

+    Entry->StartingLBA = PartitionEntries[LoopIndex].StartingLBA;

+    Entry->EndingLBA = PartitionEntries[LoopIndex].EndingLBA;

+    InsertTailList (&mPartitionListHead, &Entry->Link);

   }

-

 Exit:

-  FreePool (PartitionEntries);

-  FreePool (FlashDevicePath);

-  FreePool (AllHandles);

+  FreePages (

+    (VOID *)((UINTN)PartitionEntries - (2 * mFlashBlockIo->Media->BlockSize)),

+    EFI_SIZE_TO_PAGES (34 * mFlashBlockIo->Media->BlockSize)

+    );

   return Status;

+}

 

+/*

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

+*/

+EFI_STATUS

+HiKeyFastbootPlatformInit (

+  VOID

+  )

+{

+  return LoadPtable ();

 }

 

 VOID

@@ -347,6 +261,87 @@
 }

 

 EFI_STATUS

+HiKeyFlashPtable (

+  IN UINTN   Size,

+  IN VOID   *Image

+  )

+{

+  EFI_STATUS               Status;

+  VOID                    *Buffer;

+  UINTN                    BlockSize;

+  EFI_DISK_IO_PROTOCOL    *DiskIo;

+  UINT32                   EntrySize, EntryOffset;

+  UINT32                   MediaId;

+

+  MediaId = mFlashBlockIo->Media->MediaId;

+  BlockSize = mFlashBlockIo->Media->BlockSize;

+  Status = gBS->OpenProtocol (

+                  mFlashHandle,

+                  &gEfiDiskIoProtocolGuid,

+                  (VOID **) &DiskIo,

+                  gImageHandle,

+                  NULL,

+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL

+                  );

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+  Buffer = Image;

+  if (AsciiStrnCmp (Buffer, "ENTRYHDR", 8) != 0) {

+    DEBUG ((EFI_D_ERROR, "unknown ptable image\n"));

+    return EFI_UNSUPPORTED;

+  }

+  Buffer += 8;

+  if (AsciiStrnCmp (Buffer, "primary", 7) != 0) {

+    DEBUG ((EFI_D_ERROR, "unknown ptable imag\n"));

+    return EFI_UNSUPPORTED;

+  }

+  Buffer += 8;

+  EntryOffset = *(UINT32 *)Buffer * BlockSize;

+  Buffer += 4;

+  EntrySize = *(UINT32 *)Buffer * BlockSize;

+  if ((EntrySize + BlockSize) > Size) {

+    DEBUG ((DEBUG_ERROR, "Entry size doesn't match\n"));

+    return EFI_UNSUPPORTED;

+  }

+  Buffer = Image + BlockSize;

+  Status = DiskIo->WriteDisk (DiskIo, MediaId, EntryOffset, EntrySize, Buffer);

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+  FreePartitionList ();

+  Status = LoadPtable ();

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  Buffer = Image + 16 + 12;

+  if (AsciiStrnCmp (Buffer, "ENTRYHDR", 8) != 0) {

+    return Status;

+  }

+  Buffer += 8;

+  if (AsciiStrnCmp (Buffer, "second", 6) != 0) {

+    return Status;

+  }

+  Buffer += 8;

+  EntryOffset = *(UINT32 *)Buffer * BlockSize;

+  Buffer += 4;

+  EntrySize = *(UINT32 *)Buffer * BlockSize;

+  if ((EntrySize + BlockSize) > Size) {

+    DEBUG ((DEBUG_ERROR, "Entry size doens't match\n"));

+    return EFI_UNSUPPORTED;

+  }

+  Buffer = Image + BlockSize;

+  Status = DiskIo->WriteDisk (DiskIo, MediaId, EntryOffset, EntrySize, Buffer);

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+  mFlashBlockIo->FlushBlocks (mFlashBlockIo);

+  MicroSecondDelay (50000);

+  return Status;

+}

+

+EFI_STATUS

 HiKeyFastbootPlatformFlashPartition (

   IN CHAR8  *PartitionName,

   IN UINTN   Size,

@@ -354,27 +349,19 @@
   )

 {

   EFI_STATUS               Status;

-  EFI_BLOCK_IO_PROTOCOL   *BlockIo;

-  EFI_DISK_IO_PROTOCOL    *DiskIo;

-  UINT32                   MediaId;

   UINTN                    PartitionSize;

   FASTBOOT_PARTITION_LIST *Entry;

   CHAR16                   PartitionNameUnicode[60];

   BOOLEAN                  PartitionFound;

-#ifdef SPARSE_HEADER

-  SPARSE_HEADER           *SparseHeader;

-  CHUNK_HEADER            *ChunkHeader;

-  UINTN                    Offset = 0;

-  UINT32                   Chunk, EntrySize, EntryOffset;

-  UINT32                  *FillVal, TmpCount, FillBuf[1024];

-#else

-  UINT32                   EntrySize, EntryOffset;

-#endif

-  VOID                    *Buffer;

+  EFI_DISK_IO_PROTOCOL    *DiskIo;

+  UINTN                    BlockSize;

 

+  // Support the pseudo partition name, such as "ptable".

+  if (AsciiStrCmp (PartitionName, "ptable") == 0) {

+    return HiKeyFlashPtable (Size, Image);

+  }

 

   AsciiStrToUnicodeStr (PartitionName, PartitionNameUnicode);

-

   PartitionFound = FALSE;

   Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&(mPartitionListHead));

   while (!IsNull (&mPartitionListHead, &Entry->Link)) {

@@ -390,50 +377,17 @@
     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;

-  }

-

-#ifdef SPARSE_HEADER

-  SparseHeader=(SPARSE_HEADER *)Image;

-

-  if (SparseHeader->Magic == SPARSE_HEADER_MAGIC) {

-    DEBUG ((DEBUG_INFO, "Sparse Magic: 0x%x Major: %d Minor: %d fhs: %d chs: %d bs: %d tbs: %d tcs: %d checksum: %d \n",

-                SparseHeader->Magic, SparseHeader->MajorVersion, SparseHeader->MinorVersion,  SparseHeader->FileHeaderSize,

-                SparseHeader->ChunkHeaderSize, SparseHeader->BlockSize, SparseHeader->TotalBlocks,

-                SparseHeader->TotalChunks, SparseHeader->ImageChecksum));

-    if (SparseHeader->MajorVersion != 1) {

-        DEBUG ((DEBUG_ERROR, "Sparse image version %d.%d not supported.\n",

-                    SparseHeader->MajorVersion, SparseHeader->MinorVersion));

-        return EFI_INVALID_PARAMETER;

-    }

-

-    Size = SparseHeader->BlockSize * SparseHeader->TotalBlocks;

-  }

-#endif

-

   // Check image will fit on device

-  PartitionSize = (BlockIo->Media->LastBlock + 1) * BlockIo->Media->BlockSize;

+  BlockSize = mFlashBlockIo->Media->BlockSize;

+  PartitionSize = (Entry->EndingLBA - Entry->StartingLBA + 1) * 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,

+                  mFlashHandle,

                   &gEfiDiskIoProtocolGuid,

                   (VOID **) &DiskIo,

                   gImageHandle,

@@ -442,144 +396,111 @@
                   );

   ASSERT_EFI_ERROR (Status);

 

-#ifdef SPARSE_HEADER

-  if (SparseHeader->Magic == SPARSE_HEADER_MAGIC) {

-    CHAR16 OutputString[64];

-    UINTN ChunkPrintDensity =

-        SparseHeader->TotalChunks > 1600 ? SparseHeader->TotalChunks / 200 : 32;

-

-    Image += SparseHeader->FileHeaderSize;

-    for (Chunk = 0; Chunk < SparseHeader->TotalChunks; Chunk++) {

-      UINTN WriteSize;

-      ChunkHeader = (CHUNK_HEADER *)Image;

-

-      // Show progress. Don't do it for every packet as outputting text

-      // might be time consuming. ChunkPrintDensity is calculated to

-      // provide an update every half percent change for large

-      // downloads.

-      if (Chunk % ChunkPrintDensity == 0) {

-        UnicodeSPrint(OutputString, sizeof(OutputString),

-                      L"\r%5d / %5d chunks written (%d%%)", Chunk,

-                      SparseHeader->TotalChunks,

-                     (Chunk * 100) / SparseHeader->TotalChunks);

-        mTextOut->OutputString(mTextOut, OutputString);

-      }

-

-      DEBUG ((DEBUG_INFO, "Chunk #%d - Type: 0x%x Size: %d TotalSize: %d Offset %d\n",

-                  (Chunk+1), ChunkHeader->ChunkType, ChunkHeader->ChunkSize,

-                  ChunkHeader->TotalSize, Offset));

-      Image += sizeof(CHUNK_HEADER);

-      WriteSize=(SparseHeader->BlockSize) * ChunkHeader->ChunkSize;

-      switch (ChunkHeader->ChunkType) {

-        case CHUNK_TYPE_RAW:

-          DEBUG ((DEBUG_INFO, "Writing %d at Offset %d\n", WriteSize, Offset));

-          Status = DiskIo->WriteDisk (DiskIo, MediaId, Offset, WriteSize, Image);

-          if (EFI_ERROR (Status)) {

-            return Status;

-          }

-          Image+=WriteSize;

-          break;

-        case CHUNK_TYPE_FILL:

-          //Assume fillVal is 0, and we can skip here

-          FillVal = (UINT32 *)Image;

-          Image += sizeof(UINT32);

-          if (*FillVal != 0){

-            mTextOut->OutputString(mTextOut, OutputString);

-            for(TmpCount = 0; TmpCount < 1024; TmpCount++){

-                FillBuf[TmpCount] = *FillVal;

-            }

-            for (TmpCount= 0; TmpCount < WriteSize; TmpCount += sizeof(FillBuf)) {

-                if ((WriteSize - TmpCount) < sizeof(FillBuf)) {

-                  Status = DiskIo->WriteDisk (DiskIo, MediaId, Offset + TmpCount, WriteSize - TmpCount, FillBuf);

-                } else {

-                  Status = DiskIo->WriteDisk (DiskIo, MediaId, Offset + TmpCount, sizeof(FillBuf), FillBuf);

-                }

-                if (EFI_ERROR (Status)) {

-                    return Status;

-                }

-            }

-          }

-          break;

-        case CHUNK_TYPE_DONT_CARE:

-          break;

-        case CHUNK_TYPE_CRC32:

-          break;

-        default:

-          DEBUG ((DEBUG_ERROR, "Unknown Chunk Type: 0x%x", ChunkHeader->ChunkType));

-          return EFI_PROTOCOL_ERROR;

-      }

-      Offset += WriteSize;

-    }

-

-    UnicodeSPrint(OutputString, sizeof(OutputString),

-                  L"\r%5d / %5d chunks written (100%%)\r\n",

-                  SparseHeader->TotalChunks, SparseHeader->TotalChunks);

-    mTextOut->OutputString(mTextOut, OutputString);

-  } else {

-#endif

-    if (AsciiStrCmp (PartitionName, "ptable") == 0) {

-      Buffer = Image;

-      if (AsciiStrnCmp (Buffer, "ENTRYHDR", 8) != 0) {

-        DEBUG ((DEBUG_ERROR, "unknown ptable image\n"));

-        return EFI_UNSUPPORTED;

-      }

-      Buffer += 8;

-      if (AsciiStrnCmp (Buffer, "primary", 7) != 0) {

-        DEBUG ((DEBUG_ERROR, "unknown ptable image\n"));

-        return EFI_UNSUPPORTED;

-      }

-      Buffer += 8;

-      EntryOffset = *(UINT32 *)Buffer * BlockIo->Media->BlockSize;

-      Buffer += 4;

-      EntrySize = *(UINT32 *)Buffer * BlockIo->Media->BlockSize;

-      if ((EntrySize + 512) > Size) {

-        DEBUG ((DEBUG_ERROR, "Entry size doesn't match\n"));

-        return EFI_UNSUPPORTED;

-      }

-      Buffer = Image + 512;

-      Status = DiskIo->WriteDisk (DiskIo, MediaId, EntryOffset, EntrySize, Buffer);

-      if (EFI_ERROR (Status)) {

-        return Status;

-      }

-

-      Buffer = Image + 16 + 12;

-      if (AsciiStrnCmp (Buffer, "ENTRYHDR", 8) != 0)

-        return Status;

-      Buffer += 8;

-      if (AsciiStrnCmp (Buffer, "second", 6) != 0)

-        return Status;

-      Buffer += 8;

-      EntryOffset = *(UINT32 *)Buffer * BlockIo->Media->BlockSize;

-      Buffer += 4;

-      EntrySize = *(UINT32 *)Buffer * BlockIo->Media->BlockSize;

-      if ((EntrySize + 512) > Size) {

-        DEBUG ((DEBUG_ERROR, "Entry size doesn't match\n"));

-        return EFI_UNSUPPORTED;

-      }

-      Buffer = Image + 512;

-      Status = DiskIo->WriteDisk (DiskIo, MediaId, EntryOffset, EntrySize, Buffer);

-    } else {

-      Status = DiskIo->WriteDisk (DiskIo, MediaId, 0, Size, Image);

-    }

-    if (EFI_ERROR (Status)) {

-      return Status;

-    }

-#ifdef SPARSE_HEADER

+  Status = DiskIo->WriteDisk (

+                     DiskIo,

+                     mFlashBlockIo->Media->MediaId,

+                     Entry->StartingLBA * BlockSize,

+                     Size,

+                     Image

+                     );

+  if (EFI_ERROR (Status)) {

+    DEBUG ((DEBUG_ERROR, "Failed to write %d bytes into 0x%x, Status:%r\n", Size, Entry->StartingLBA * BlockSize, Status));

+    return Status;

   }

-#endif

 

-  BlockIo->FlushBlocks(BlockIo);

+  mFlashBlockIo->FlushBlocks(mFlashBlockIo);

   MicroSecondDelay (50000);

 

   return Status;

 }

 

 EFI_STATUS

+HiKeyErasePtable (

+  VOID

+  )

+{

+  EFI_STATUS                  Status;

+  EFI_ERASE_BLOCK_PROTOCOL   *EraseBlockProtocol;

+

+  Status = gBS->OpenProtocol (

+                  mFlashHandle,

+                  &gEfiEraseBlockProtocolGuid,

+                  (VOID **) &EraseBlockProtocol,

+                  gImageHandle,

+                  NULL,

+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL

+                  );

+  if (EFI_ERROR (Status)) {

+    DEBUG ((DEBUG_ERROR, "Fastboot platform: could not open Erase Block IO: %r\n", Status));

+    return EFI_DEVICE_ERROR;

+  }

+  Status = EraseBlockProtocol->EraseBlocks (

+                                 EraseBlockProtocol,

+                                 mFlashBlockIo->Media->MediaId,

+                                 0,

+                                 NULL,

+                                 34 * mFlashBlockIo->Media->BlockSize

+                                 );

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+  FreePartitionList ();

+  return Status;

+}

+

+EFI_STATUS

 HiKeyFastbootPlatformErasePartition (

   IN CHAR8 *PartitionName

   )

 {

-  return EFI_SUCCESS;

+  EFI_STATUS                  Status;

+  EFI_ERASE_BLOCK_PROTOCOL   *EraseBlockProtocol;

+  UINTN                       Size;

+  BOOLEAN                     PartitionFound;

+  CHAR16                      PartitionNameUnicode[60];

+  FASTBOOT_PARTITION_LIST    *Entry;

+

+  AsciiStrToUnicodeStr (PartitionName, PartitionNameUnicode);

+

+  // Support the pseudo partition name, such as "ptable".

+  if (AsciiStrCmp (PartitionName, "ptable") == 0) {

+    return HiKeyErasePtable ();

+  }

+

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

+                  mFlashHandle,

+                  &gEfiEraseBlockProtocolGuid,

+                  (VOID **) &EraseBlockProtocol,

+                  gImageHandle,

+                  NULL,

+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL

+                  );

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+  Size = (Entry->EndingLBA - Entry->StartingLBA + 1) * mFlashBlockIo->Media->BlockSize;

+  Status = EraseBlockProtocol->EraseBlocks (

+                                 EraseBlockProtocol,

+                                 mFlashBlockIo->Media->MediaId,

+                                 Entry->StartingLBA,

+                                 NULL,

+                                 Size

+                                 );

+  return Status;

 }

 

 EFI_STATUS

@@ -589,7 +510,6 @@
   )

 {

   EFI_STATUS               Status;

-  EFI_BLOCK_IO_PROTOCOL   *BlockIo;

   UINT64                   PartitionSize;

   FASTBOOT_PARTITION_LIST *Entry;

   CHAR16                   PartitionNameUnicode[60];

@@ -634,25 +554,11 @@
       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;

-    }

-

-    PartitionSize = (BlockIo->Media->LastBlock + 1) * BlockIo->Media->BlockSize;

-    DEBUG ((DEBUG_ERROR, "Fastboot platform: check for partition-size:%a 0X%llx\n", Name, PartitionSize ));

+    PartitionSize = (Entry->EndingLBA - Entry->StartingLBA + 1) * mFlashBlockIo->Media->BlockSize;

+    DEBUG ((DEBUG_ERROR, "Fastboot platform: check for partition-size:%a 0X%llx\n", Name, PartitionSize));

     AsciiSPrint (Value, 12, "0x%llx", PartitionSize);

   } else if ( !AsciiStrnCmp (Name, "partition-type", 14)) {

-      DEBUG ((DEBUG_ERROR, "Fastboot platform: check for partition-type:%a\n", (Name + 15) ));

+      DEBUG ((DEBUG_ERROR, "Fastboot platform: check for partition-type:%a\n", (Name + 15)));

     if ( !AsciiStrnCmp  ( (Name + 15) , "system", 6) || !AsciiStrnCmp  ( (Name + 15) , "userdata", 8)

             || !AsciiStrnCmp  ( (Name + 15) , "cache", 5)) {

       AsciiStrCpy (Value, "ext4");

@@ -682,22 +588,72 @@
   }

 }

 

-CHAR16 *

-HiKeyFastbootPlatformGetKernelArgs (

-  VOID

+EFI_STATUS

+HiKeyFastbootPlatformFlashPartitionEx (

+  IN CHAR8  *PartitionName,

+  IN UINTN   Offset,

+  IN UINTN   Size,

+  IN VOID   *Image

   )

 {

-  CHAR16                             *CommandLineArgs;

+  EFI_STATUS               Status;

+  UINTN                    PartitionSize;

+  FASTBOOT_PARTITION_LIST *Entry;

+  CHAR16                   PartitionNameUnicode[60];

+  BOOLEAN                  PartitionFound;

+  UINTN                    BlockSize;

+  EFI_DISK_IO_PROTOCOL    *DiskIo;

 

-  CommandLineArgs = AllocateZeroPool (BOOTIMG_KERNEL_ARGS_SIZE);

-  if (CommandLineArgs == NULL) {

-    return NULL;

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

   }

-  UnicodeSPrint (

-    CommandLineArgs, BOOTIMG_KERNEL_ARGS_SIZE,

-    L"root=/dev/mmcblk0p9 earlycon=pl011,0xf7113000"

-    );

-  return CommandLineArgs;

+  if (!PartitionFound) {

+    return EFI_NOT_FOUND;

+  }

+

+  // Check image will fit on device

+  PartitionSize = (Entry->EndingLBA - Entry->StartingLBA + 1) * mFlashBlockIo->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;

+  }

+

+  BlockSize = mFlashBlockIo->Media->BlockSize;

+  Status = gBS->OpenProtocol (

+                  mFlashHandle,

+                  &gEfiDiskIoProtocolGuid,

+                  (VOID **) &DiskIo,

+                  gImageHandle,

+                  NULL,

+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL

+                  );

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  Status = DiskIo->WriteDisk (

+                     DiskIo,

+                     mFlashBlockIo->Media->MediaId,

+                     Entry->StartingLBA * BlockSize + Offset,

+                     Size,

+                     Image

+                     );

+  if (EFI_ERROR (Status)) {

+    DEBUG ((DEBUG_ERROR, "Failed to write %d bytes into 0x%x, Status:%r\n", Size, Entry->StartingLBA * BlockSize + Offset, Status));

+    return Status;

+  }

+  return Status;

 }

 

 FASTBOOT_PLATFORM_PROTOCOL mPlatformProtocol = {

@@ -707,7 +663,7 @@
   HiKeyFastbootPlatformErasePartition,

   HiKeyFastbootPlatformGetVar,

   HiKeyFastbootPlatformOemCommand,

-  HiKeyFastbootPlatformGetKernelArgs

+  HiKeyFastbootPlatformFlashPartitionEx

 };

 

 EFI_STATUS