[edk2] EmbeddedPkg/AndroidFastbootApp: support sparse image

Message ID 1494560766-5451-2-git-send-email-haojian.zhuang@linaro.org
State New
Headers show

Commit Message

Haojian Zhuang May 12, 2017, 3:46 a.m.
Support sparse image that is reformatted from large raw image and
splitted into a few smaller images. The sparse image follows the
rule of Android Sparse Image format.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>

---
 .../AndroidFastboot/AndroidFastbootApp.c           | 100 +++++++++++++++++++--
 .../AndroidFastboot/AndroidFastbootApp.h           |  29 +++++-
 .../Include/Protocol/AndroidFastbootPlatform.h     |  23 +++++
 3 files changed, 144 insertions(+), 8 deletions(-)

-- 
2.7.4

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

Patch hide | download patch | download mbox

diff --git a/EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.c b/EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.c
index c5e8a7e..6226bd5 100644
--- a/EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.c
+++ b/EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.c
@@ -138,13 +138,83 @@  HandleDownload (
 }
 
 STATIC
+EFI_STATUS
+FlashSparseImage (
+  IN CHAR8         *PartitionName,
+  IN SPARSE_HEADER *SparseHeader
+  )
+{
+  EFI_STATUS        Status;
+  UINTN             Chunk, Offset = 0, Index;
+  VOID             *Image;
+  CHUNK_HEADER     *ChunkHeader;
+  UINT32            FillBuf[FILL_BUF_SIZE];
+  CHAR16            OutputString[FASTBOOT_STRING_MAX_LENGTH];
+
+  Image = (VOID *)SparseHeader;
+  Image += SparseHeader->FileHeaderSize;
+  for (Chunk = 0; Chunk < SparseHeader->TotalChunks; Chunk++) {
+    ChunkHeader = (CHUNK_HEADER *)Image;
+    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);
+    switch (ChunkHeader->ChunkType) {
+    case CHUNK_TYPE_RAW:
+      Status = mPlatform->FlashPartitionEx (
+                            PartitionName,
+                            Offset,
+                            ChunkHeader->ChunkSize * SparseHeader->BlockSize,
+                            Image
+                            );
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+      Image += ChunkHeader->ChunkSize * SparseHeader->BlockSize;
+      Offset += ChunkHeader->ChunkSize * SparseHeader->BlockSize;
+      break;
+    case CHUNK_TYPE_FILL:
+      SetMem32 (FillBuf, sizeof (FillBuf), *(UINT32 *)Image);
+      Image += sizeof (UINT32);
+      for (Index = 0; Index < ChunkHeader->ChunkSize; Index++) {
+        Status = mPlatform->FlashPartitionEx (
+                              PartitionName,
+                              Offset,
+                              SparseHeader->BlockSize,
+                              FillBuf
+                              );
+        if (EFI_ERROR (Status)) {
+          return Status;
+        }
+        Offset += SparseHeader->BlockSize;
+      }
+      break;
+    case CHUNK_TYPE_DONT_CARE:
+      Offset += ChunkHeader->ChunkSize * SparseHeader->BlockSize;
+      break;
+    default:
+      UnicodeSPrint (
+        OutputString,
+        sizeof (OutputString),
+        L"Unsupported Chunk Type:0x%x\n",
+        ChunkHeader->ChunkType
+        );
+      mTextOut->OutputString (mTextOut, OutputString);
+      break;
+    }
+  }
+  return Status;
+}
+
+STATIC
 VOID
 HandleFlash (
   IN CHAR8 *PartitionName
   )
 {
-  EFI_STATUS  Status;
-  CHAR16      OutputString[FASTBOOT_STRING_MAX_LENGTH];
+  EFI_STATUS        Status;
+  CHAR16            OutputString[FASTBOOT_STRING_MAX_LENGTH];
+  SPARSE_HEADER    *SparseHeader;
 
   // Build output string
   UnicodeSPrint (OutputString, sizeof (OutputString), L"Flashing partition %a\r\n", PartitionName);
@@ -156,11 +226,27 @@  HandleFlash (
     return;
   }
 
-  Status = mPlatform->FlashPartition (
-                        PartitionName,
-                        mNumDataBytes,
-                        mDataBuffer
-                        );
+  SparseHeader = (SPARSE_HEADER *)mDataBuffer;
+  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;
+    }
+    Status = FlashSparseImage (PartitionName, SparseHeader);
+  } else {
+    Status = mPlatform->FlashPartition (
+                          PartitionName,
+                          mNumDataBytes,
+                          mDataBuffer
+                          );
+  }
   if (Status == EFI_NOT_FOUND) {
     SEND_LITERAL ("FAILNo such partition.");
     mTextOut->OutputString (mTextOut, L"No such partition.\r\n");
diff --git a/EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.h b/EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.h
index f62660f..0e90b1f 100644
--- a/EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.h
+++ b/EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.h
@@ -21,7 +21,34 @@ 
 
 #define BOOTIMG_KERNEL_ARGS_SIZE 512
 
-#define ANDROID_FASTBOOT_VERSION "0.4"
+#define ANDROID_FASTBOOT_VERSION "0.5"
+
+#define SPARSE_HEADER_MAGIC         0xED26FF3A
+#define CHUNK_TYPE_RAW              0xCAC1
+#define CHUNK_TYPE_FILL             0xCAC2
+#define CHUNK_TYPE_DONT_CARE        0xCAC3
+#define CHUNK_TYPE_CRC32            0xCAC4
+
+#define FILL_BUF_SIZE               1024
+
+typedef struct _SPARSE_HEADER {
+  UINT32       Magic;
+  UINT16       MajorVersion;
+  UINT16       MinorVersion;
+  UINT16       FileHeaderSize;
+  UINT16       ChunkHeaderSize;
+  UINT32       BlockSize;
+  UINT32       TotalBlocks;
+  UINT32       TotalChunks;
+  UINT32       ImageChecksum;
+} SPARSE_HEADER;
+
+typedef struct _CHUNK_HEADER {
+  UINT16       ChunkType;
+  UINT16       Reserved1;
+  UINT32       ChunkSize;
+  UINT32       TotalSize;
+} CHUNK_HEADER;
 
 EFI_STATUS
 BootAndroidBootImg (
diff --git a/EmbeddedPkg/Include/Protocol/AndroidFastbootPlatform.h b/EmbeddedPkg/Include/Protocol/AndroidFastbootPlatform.h
index a9b4aac..2cb51eb 100644
--- a/EmbeddedPkg/Include/Protocol/AndroidFastbootPlatform.h
+++ b/EmbeddedPkg/Include/Protocol/AndroidFastbootPlatform.h
@@ -133,6 +133,28 @@  EFI_STATUS
   IN  CHAR8   *Command
   );
 
+/*
+  Flash the partition named (according to a platform-specific scheme)
+  PartitionName, with partition offset and the image pointed to by Buffer,
+  whose size is BufferSize.
+
+  @param[in] PartitionName  Null-terminated name of partition to write.
+  @param[in] Offset         Offset of partition.
+  @param[in] BufferSize     Size of Buffer in byets.
+  @param[in] Buffer         Data to write to partition.
+
+  @retval EFI_NOT_FOUND     No such partition.
+  @retval EFI_DEVICE_ERROR  Flashing failed.
+*/
+typedef
+EFI_STATUS
+(*FASTBOOT_PLATFORM_FLASH_EX) (
+  IN CHAR8   *PartitionName,
+  IN UINTN    Offset,
+  IN UINTN    BufferSize,
+  IN VOID    *Buffer
+  );
+
 typedef struct _FASTBOOT_PLATFORM_PROTOCOL {
   FASTBOOT_PLATFORM_INIT          Init;
   FASTBOOT_PLATFORM_UN_INIT       UnInit;
@@ -140,6 +162,7 @@  typedef struct _FASTBOOT_PLATFORM_PROTOCOL {
   FASTBOOT_PLATFORM_ERASE         ErasePartition;
   FASTBOOT_PLATFORM_GETVAR        GetVar;
   FASTBOOT_PLATFORM_OEM_COMMAND   DoOemCommand;
+  FASTBOOT_PLATFORM_FLASH_EX      FlashPartitionEx;
 } FASTBOOT_PLATFORM_PROTOCOL;
 
 #endif