Home | History | Annotate | Download | only in HiKeyFastbootDxe
      1 /** @file
      2 
      3   Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
      4   Copyright (c) 2015-2017, Linaro. All rights reserved.
      5 
      6   This program and the accompanying materials
      7   are licensed and made available under the terms and conditions of the BSD License
      8   which accompanies this distribution.  The full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.php
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 /*
     17   Implementation of the Android Fastboot Platform protocol, to be used by the
     18   Fastboot UEFI application, for Hisilicon HiKey platform.
     19 */
     20 
     21 #include <Protocol/AndroidFastbootPlatform.h>
     22 #include <Protocol/BlockIo.h>
     23 #include <Protocol/DiskIo.h>
     24 #include <Protocol/EraseBlock.h>
     25 #include <Protocol/SimpleTextOut.h>
     26 
     27 #include <Library/BaseLib.h>
     28 #include <Library/BaseMemoryLib.h>
     29 #include <Library/CacheMaintenanceLib.h>
     30 #include <Library/DebugLib.h>
     31 #include <Library/DevicePathLib.h>
     32 #include <Library/MemoryAllocationLib.h>
     33 #include <Library/IoLib.h>
     34 #include <Library/UefiBootServicesTableLib.h>
     35 #include <Library/UefiRuntimeServicesTableLib.h>
     36 #include <Library/UsbSerialNumberLib.h>
     37 #include <Library/PrintLib.h>
     38 #include <Library/TimerLib.h>
     39 
     40 #define PARTITION_NAME_MAX_LENGTH (72/2)
     41 
     42 #define SERIAL_NUMBER_LBA                1024
     43 #define RANDOM_MAX                       0x7FFFFFFFFFFFFFFF
     44 #define RANDOM_MAGIC                     0x9A4DBEAF
     45 
     46 #define ADB_REBOOT_ADDRESS               0x05F01000
     47 #define ADB_REBOOT_BOOTLOADER            0x77665500
     48 
     49 #define MMC_BLOCK_SIZE                   512
     50 #define HIKEY_ERASE_SIZE                 4096
     51 
     52 typedef struct _FASTBOOT_PARTITION_LIST {
     53   LIST_ENTRY  Link;
     54   CHAR16      PartitionName[PARTITION_NAME_MAX_LENGTH];
     55   EFI_LBA     StartingLBA;
     56   EFI_LBA     EndingLBA;
     57 } FASTBOOT_PARTITION_LIST;
     58 
     59 STATIC LIST_ENTRY                       mPartitionListHead;
     60 STATIC EFI_HANDLE                       mFlashHandle;
     61 STATIC EFI_BLOCK_IO_PROTOCOL           *mFlashBlockIo;
     62 STATIC EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *mTextOut;
     63 
     64 /*
     65   Helper to free the partition list
     66 */
     67 STATIC
     68 VOID
     69 FreePartitionList (
     70   VOID
     71   )
     72 {
     73   FASTBOOT_PARTITION_LIST *Entry;
     74   FASTBOOT_PARTITION_LIST *NextEntry;
     75 
     76   Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&mPartitionListHead);
     77   while (!IsNull (&mPartitionListHead, &Entry->Link)) {
     78     NextEntry = (FASTBOOT_PARTITION_LIST *) GetNextNode (&mPartitionListHead, &Entry->Link);
     79 
     80     RemoveEntryList (&Entry->Link);
     81     FreePool (Entry);
     82 
     83     Entry = NextEntry;
     84   }
     85 }
     86 
     87 /*
     88   Read the PartitionName fields from the GPT partition entries, putting them
     89   into an allocated array that should later be freed.
     90 */
     91 STATIC
     92 EFI_STATUS
     93 ReadPartitionEntries (
     94   IN  EFI_BLOCK_IO_PROTOCOL *BlockIo,
     95   OUT EFI_PARTITION_ENTRY  **PartitionEntries,
     96   OUT UINTN                 *PartitionNumbers
     97   )
     98 {
     99   EFI_STATUS                  Status;
    100   UINT32                      MediaId;
    101   UINTN                       BlockSize;
    102   UINTN                       PageCount;
    103   UINTN                       Count, EndLBA;
    104   EFI_PARTITION_TABLE_HEADER *GptHeader;
    105   EFI_PARTITION_ENTRY        *Entry;
    106   VOID                       *Buffer;
    107 
    108   if ((PartitionEntries == NULL) || (PartitionNumbers == NULL)) {
    109     return EFI_INVALID_PARAMETER;
    110   }
    111 
    112   MediaId = BlockIo->Media->MediaId;
    113   BlockSize = BlockIo->Media->BlockSize;
    114 
    115   //
    116   // Read size of Partition entry and number of entries from GPT header
    117   //
    118 
    119   PageCount = EFI_SIZE_TO_PAGES (34 * BlockSize);
    120   Buffer = AllocatePages (PageCount);
    121   if (Buffer == NULL) {
    122     return EFI_OUT_OF_RESOURCES;
    123   }
    124 
    125   Status = BlockIo->ReadBlocks (BlockIo, MediaId, 0, PageCount * EFI_PAGE_SIZE, Buffer);
    126   if (EFI_ERROR (Status)) {
    127     return Status;
    128   }
    129   GptHeader = (EFI_PARTITION_TABLE_HEADER *)(Buffer + BlockSize);
    130 
    131   // Check there is a GPT on the media
    132   if (GptHeader->Header.Signature != EFI_PTAB_HEADER_ID ||
    133       GptHeader->MyLBA != 1) {
    134     DEBUG ((EFI_D_ERROR,
    135       "Fastboot platform: No GPT on flash. "
    136       "Fastboot on HiKey does not support MBR.\n"
    137       ));
    138     return EFI_DEVICE_ERROR;
    139   }
    140 
    141   Entry = (EFI_PARTITION_ENTRY *)(Buffer + (2 * BlockSize));
    142   EndLBA = GptHeader->FirstUsableLBA - 1;
    143   Count = 0;
    144   while (1) {
    145     if ((Entry->StartingLBA > EndLBA) && (Entry->EndingLBA <= GptHeader->LastUsableLBA)) {
    146       Count++;
    147       EndLBA = Entry->EndingLBA;
    148       Entry++;
    149     } else {
    150       break;
    151     }
    152   }
    153   if (Count == 0) {
    154     return EFI_INVALID_PARAMETER;
    155   }
    156   if (Count > GptHeader->NumberOfPartitionEntries) {
    157     Count = GptHeader->NumberOfPartitionEntries;
    158   }
    159 
    160   *PartitionEntries = (EFI_PARTITION_ENTRY *)((UINTN)Buffer + (2 * BlockSize));
    161   *PartitionNumbers = Count;
    162   return EFI_SUCCESS;
    163 }
    164 
    165 EFI_STATUS
    166 LoadPtable (
    167   VOID
    168   )
    169 {
    170   EFI_STATUS                          Status;
    171   EFI_DEVICE_PATH_PROTOCOL           *FlashDevicePath;
    172   EFI_DEVICE_PATH_PROTOCOL           *FlashDevicePathDup;
    173   UINTN                               PartitionNumbers = 0;
    174   UINTN                               LoopIndex;
    175   EFI_PARTITION_ENTRY                *PartitionEntries = NULL;
    176   FASTBOOT_PARTITION_LIST            *Entry;
    177 
    178   InitializeListHead (&mPartitionListHead);
    179 
    180   Status = gBS->LocateProtocol (&gEfiSimpleTextOutProtocolGuid, NULL, (VOID **) &mTextOut);
    181   if (EFI_ERROR (Status)) {
    182     DEBUG ((DEBUG_ERROR,
    183       "Fastboot platform: Couldn't open Text Output Protocol: %r\n", Status
    184       ));
    185     return Status;
    186   }
    187 
    188   //
    189   // Get EFI_HANDLES for all the partitions on the block devices pointed to by
    190   // PcdFastbootFlashDevicePath, also saving their GPT partition labels.
    191   // There's no way to find all of a device's children, so we get every handle
    192   // in the system supporting EFI_BLOCK_IO_PROTOCOL and then filter out ones
    193   // that don't represent partitions on the flash device.
    194   //
    195   FlashDevicePath = ConvertTextToDevicePath ((CHAR16*)FixedPcdGetPtr (PcdAndroidFastbootNvmDevicePath));
    196 
    197   // Create another device path pointer because LocateDevicePath will modify it.
    198   FlashDevicePathDup = FlashDevicePath;
    199   Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &FlashDevicePathDup, &mFlashHandle);
    200   if (EFI_ERROR (Status)) {
    201     DEBUG ((DEBUG_ERROR, "Warning: Couldn't locate Android NVM device (status: %r)\n", Status));
    202     // Failing to locate partitions should not prevent to do other Android FastBoot actions
    203     return EFI_SUCCESS;
    204   }
    205 
    206 
    207   Status = gBS->OpenProtocol (
    208                   mFlashHandle,
    209                   &gEfiBlockIoProtocolGuid,
    210                   (VOID **) &mFlashBlockIo,
    211                   gImageHandle,
    212                   NULL,
    213                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    214                   );
    215   if (EFI_ERROR (Status)) {
    216     DEBUG ((DEBUG_ERROR, "Fastboot platform: Couldn't open Android NVM device (status: %r)\n", Status));
    217     return EFI_DEVICE_ERROR;
    218   }
    219 
    220   // Read the GPT partition entry array into memory so we can get the partition names
    221   Status = ReadPartitionEntries (mFlashBlockIo, &PartitionEntries, &PartitionNumbers);
    222   if (EFI_ERROR (Status)) {
    223     DEBUG ((DEBUG_ERROR, "Warning: Failed to read partitions from Android NVM device (status: %r)\n", Status));
    224     // Failing to locate partitions should not prevent to do other Android FastBoot actions
    225     return EFI_SUCCESS;
    226   }
    227   for (LoopIndex = 0; LoopIndex < PartitionNumbers; LoopIndex++) {
    228     // Create entry
    229     Entry = AllocatePool (sizeof (FASTBOOT_PARTITION_LIST));
    230     if (Entry == NULL) {
    231       Status = EFI_BUFFER_TOO_SMALL;
    232       FreePartitionList ();
    233       goto Exit;
    234     }
    235     StrnCpy (
    236       Entry->PartitionName,
    237       PartitionEntries[LoopIndex].PartitionName,
    238       PARTITION_NAME_MAX_LENGTH
    239       );
    240     Entry->StartingLBA = PartitionEntries[LoopIndex].StartingLBA;
    241     Entry->EndingLBA = PartitionEntries[LoopIndex].EndingLBA;
    242     InsertTailList (&mPartitionListHead, &Entry->Link);
    243   }
    244 Exit:
    245   FreePages (
    246     (VOID *)((UINTN)PartitionEntries - (2 * mFlashBlockIo->Media->BlockSize)),
    247     EFI_SIZE_TO_PAGES (34 * mFlashBlockIo->Media->BlockSize)
    248     );
    249   return Status;
    250 }
    251 
    252 /*
    253   Initialise: Open the Android NVM device and find the partitions on it. Save them in
    254   a list along with the "PartitionName" fields for their GPT entries.
    255   We will use these partition names as the key in
    256   HiKeyFastbootPlatformFlashPartition.
    257 */
    258 EFI_STATUS
    259 HiKeyFastbootPlatformInit (
    260   VOID
    261   )
    262 {
    263   return LoadPtable ();
    264 }
    265 
    266 VOID
    267 HiKeyFastbootPlatformUnInit (
    268   VOID
    269   )
    270 {
    271   FreePartitionList ();
    272 }
    273 
    274 EFI_STATUS
    275 HiKeyFlashPtable (
    276   IN UINTN   Size,
    277   IN VOID   *Image
    278   )
    279 {
    280   EFI_STATUS               Status;
    281   EFI_DISK_IO_PROTOCOL    *DiskIo;
    282   UINT32                   MediaId;
    283   VOID                    *Buffer;
    284   UINT32                   EntrySize, EntryOffset;
    285   UINTN                    BlockSize;
    286 
    287   MediaId = mFlashBlockIo->Media->MediaId;
    288   BlockSize = mFlashBlockIo->Media->BlockSize;
    289   Status = gBS->OpenProtocol (
    290                   mFlashHandle,
    291                   &gEfiDiskIoProtocolGuid,
    292                   (VOID **) &DiskIo,
    293                   gImageHandle,
    294                   NULL,
    295                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    296                   );
    297   if (EFI_ERROR (Status)) {
    298     return Status;
    299   }
    300   Buffer = Image;
    301   if (AsciiStrnCmp (Buffer, "ENTRYHDR", 8) != 0) {
    302     DEBUG ((EFI_D_ERROR, "It should be raw ptable image\n"));
    303     Status = DiskIo->WriteDisk (DiskIo, MediaId, 0, Size, Image);
    304     if (EFI_ERROR (Status)) {
    305       return Status;
    306     }
    307   } else {
    308     /* ptable with entry header */
    309     Buffer += 8;
    310     if (AsciiStrnCmp (Buffer, "primary", 7) != 0) {
    311       DEBUG ((EFI_D_ERROR, "unknown ptable imag\n"));
    312       return EFI_UNSUPPORTED;
    313     }
    314     Buffer += 8;
    315     EntryOffset = *(UINT32 *)Buffer * BlockSize;
    316     Buffer += 4;
    317     EntrySize = *(UINT32 *)Buffer * BlockSize;
    318     if ((EntrySize + BlockSize) > Size) {
    319       DEBUG ((DEBUG_ERROR, "Entry size doesn't match\n"));
    320       return EFI_UNSUPPORTED;
    321     }
    322     Buffer = Image + BlockSize;
    323     Status = DiskIo->WriteDisk (DiskIo, MediaId, EntryOffset, EntrySize, Buffer);
    324     if (EFI_ERROR (Status)) {
    325       return Status;
    326     }
    327   }
    328   FreePartitionList ();
    329   Status = LoadPtable ();
    330   return Status;
    331 }
    332 
    333 EFI_STATUS
    334 HiKeyFastbootPlatformFlashPartition (
    335   IN CHAR8  *PartitionName,
    336   IN UINTN   Size,
    337   IN VOID   *Image
    338   )
    339 {
    340   EFI_STATUS               Status;
    341   UINTN                    PartitionSize;
    342   FASTBOOT_PARTITION_LIST *Entry;
    343   CHAR16                   PartitionNameUnicode[60];
    344   BOOLEAN                  PartitionFound;
    345   EFI_DISK_IO_PROTOCOL    *DiskIo;
    346   UINTN                    BlockSize;
    347 
    348   // Support the pseudo partition name, such as "ptable".
    349   if (AsciiStrCmp (PartitionName, "ptable") == 0) {
    350     return HiKeyFlashPtable (Size, Image);
    351   }
    352 
    353   AsciiStrToUnicodeStr (PartitionName, PartitionNameUnicode);
    354   PartitionFound = FALSE;
    355   Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&(mPartitionListHead));
    356   while (!IsNull (&mPartitionListHead, &Entry->Link)) {
    357     // Search the partition list for the partition named by PartitionName
    358     if (StrCmp (Entry->PartitionName, PartitionNameUnicode) == 0) {
    359       PartitionFound = TRUE;
    360       break;
    361     }
    362 
    363    Entry = (FASTBOOT_PARTITION_LIST *) GetNextNode (&mPartitionListHead, &(Entry)->Link);
    364   }
    365   if (!PartitionFound) {
    366     return EFI_NOT_FOUND;
    367   }
    368 
    369   // Check image will fit on device
    370   BlockSize = mFlashBlockIo->Media->BlockSize;
    371   PartitionSize = (Entry->EndingLBA - Entry->StartingLBA + 1) * BlockSize;
    372   if (PartitionSize < Size) {
    373     DEBUG ((DEBUG_ERROR, "Partition not big enough.\n"));
    374     DEBUG ((DEBUG_ERROR, "Partition Size:\t%ld\nImage Size:\t%ld\n", PartitionSize, Size));
    375 
    376     return EFI_VOLUME_FULL;
    377   }
    378   Status = gBS->OpenProtocol (
    379                   mFlashHandle,
    380                   &gEfiDiskIoProtocolGuid,
    381                   (VOID **) &DiskIo,
    382                   gImageHandle,
    383                   NULL,
    384                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    385                   );
    386   ASSERT_EFI_ERROR (Status);
    387 
    388   Status = DiskIo->WriteDisk (
    389                      DiskIo,
    390                      mFlashBlockIo->Media->MediaId,
    391                      Entry->StartingLBA * BlockSize,
    392                      Size,
    393                      Image
    394                      );
    395   if (EFI_ERROR (Status)) {
    396     DEBUG ((DEBUG_ERROR, "Failed to write %d bytes into 0x%x, Status:%r\n", Size, Entry->StartingLBA * BlockSize, Status));
    397     return Status;
    398   }
    399 
    400   mFlashBlockIo->FlushBlocks(mFlashBlockIo);
    401   MicroSecondDelay (50000);
    402 
    403   return Status;
    404 }
    405 
    406 EFI_STATUS
    407 HiKeyErasePtable (
    408   VOID
    409   )
    410 {
    411   EFI_STATUS                  Status;
    412   EFI_ERASE_BLOCK_PROTOCOL   *EraseBlockProtocol;
    413 
    414   Status = gBS->OpenProtocol (
    415                   mFlashHandle,
    416                   &gEfiEraseBlockProtocolGuid,
    417                   (VOID **) &EraseBlockProtocol,
    418                   gImageHandle,
    419                   NULL,
    420                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    421                   );
    422   if (EFI_ERROR (Status)) {
    423     DEBUG ((DEBUG_ERROR, "Fastboot platform: could not open Erase Block IO: %r\n", Status));
    424     return EFI_DEVICE_ERROR;
    425   }
    426   Status = EraseBlockProtocol->EraseBlocks (
    427                                  EraseBlockProtocol,
    428                                  mFlashBlockIo->Media->MediaId,
    429                                  0,
    430                                  NULL,
    431                                  34 * mFlashBlockIo->Media->BlockSize
    432                                  );
    433   if (EFI_ERROR (Status)) {
    434     return Status;
    435   }
    436   FreePartitionList ();
    437   return Status;
    438 }
    439 
    440 EFI_STATUS
    441 HiKeyFastbootPlatformErasePartition (
    442   IN CHAR8 *PartitionName
    443   )
    444 {
    445   EFI_STATUS                  Status;
    446   EFI_ERASE_BLOCK_PROTOCOL   *EraseBlockProtocol;
    447   UINTN                       Size;
    448   BOOLEAN                     PartitionFound;
    449   CHAR16                      PartitionNameUnicode[60];
    450   FASTBOOT_PARTITION_LIST    *Entry;
    451 
    452   AsciiStrToUnicodeStr (PartitionName, PartitionNameUnicode);
    453 
    454   // Support the pseudo partition name, such as "ptable".
    455   if (AsciiStrCmp (PartitionName, "ptable") == 0) {
    456     return HiKeyErasePtable ();
    457   }
    458 
    459   PartitionFound = FALSE;
    460   Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&mPartitionListHead);
    461   while (!IsNull (&mPartitionListHead, &Entry->Link)) {
    462     // Search the partition list for the partition named by PartitionName
    463     if (StrCmp (Entry->PartitionName, PartitionNameUnicode) == 0) {
    464       PartitionFound = TRUE;
    465       break;
    466     }
    467     Entry = (FASTBOOT_PARTITION_LIST *) GetNextNode (&mPartitionListHead, &Entry->Link);
    468   }
    469   if (!PartitionFound) {
    470     return EFI_NOT_FOUND;
    471   }
    472 
    473   Status = gBS->OpenProtocol (
    474                   mFlashHandle,
    475                   &gEfiEraseBlockProtocolGuid,
    476                   (VOID **) &EraseBlockProtocol,
    477                   gImageHandle,
    478                   NULL,
    479                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    480                   );
    481   if (EFI_ERROR (Status)) {
    482     return Status;
    483   }
    484   Size = (Entry->EndingLBA - Entry->StartingLBA + 1) * mFlashBlockIo->Media->BlockSize;
    485   Status = EraseBlockProtocol->EraseBlocks (
    486                                  EraseBlockProtocol,
    487                                  mFlashBlockIo->Media->MediaId,
    488                                  Entry->StartingLBA,
    489                                  NULL,
    490                                  Size
    491                                  );
    492   return Status;
    493 }
    494 
    495 EFI_STATUS
    496 HiKeyFastbootPlatformGetVar (
    497   IN  CHAR8   *Name,
    498   OUT CHAR8   *Value
    499   )
    500 {
    501   EFI_STATUS               Status;
    502   UINT64                   PartitionSize;
    503   FASTBOOT_PARTITION_LIST *Entry;
    504   CHAR16                   PartitionNameUnicode[60];
    505   BOOLEAN                  PartitionFound;
    506   CHAR16                   UnicodeSN[SERIAL_NUMBER_SIZE];
    507 
    508   if (!AsciiStrCmp (Name, "max-download-size")) {
    509     AsciiStrCpy (Value, FixedPcdGetPtr (PcdArmFastbootFlashLimit));
    510   } else if (!AsciiStrCmp (Name, "product")) {
    511     AsciiStrCpy (Value, FixedPcdGetPtr (PcdFirmwareVendor));
    512   } else if (!AsciiStrCmp (Name, "serialno")) {
    513     Status = LoadSNFromBlock (mFlashHandle, SERIAL_NUMBER_LBA, UnicodeSN);
    514     if (EFI_ERROR (Status)) {
    515       *Value = '\0';
    516       return Status;
    517     }
    518     UnicodeStrToAsciiStr (UnicodeSN, Value);
    519   } else if ( !AsciiStrnCmp (Name, "partition-size", 14)) {
    520     AsciiStrToUnicodeStr ((Name + 15), PartitionNameUnicode);
    521     PartitionFound = FALSE;
    522     Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&(mPartitionListHead));
    523     while (!IsNull (&mPartitionListHead, &Entry->Link)) {
    524       // Search the partition list for the partition named by PartitionName
    525       if (StrCmp (Entry->PartitionName, PartitionNameUnicode) == 0) {
    526         PartitionFound = TRUE;
    527         break;
    528       }
    529 
    530      Entry = (FASTBOOT_PARTITION_LIST *) GetNextNode (&mPartitionListHead, &(Entry)->Link);
    531     }
    532     if (!PartitionFound) {
    533       *Value = '\0';
    534       return EFI_NOT_FOUND;
    535     }
    536 
    537     PartitionSize = (Entry->EndingLBA - Entry->StartingLBA + 1) * mFlashBlockIo->Media->BlockSize;
    538     DEBUG ((DEBUG_ERROR, "Fastboot platform: check for partition-size:%a 0X%llx\n", Name, PartitionSize));
    539     AsciiSPrint (Value, 12, "0x%llx", PartitionSize);
    540   } else if ( !AsciiStrnCmp (Name, "partition-type", 14)) {
    541       DEBUG ((DEBUG_ERROR, "Fastboot platform: check for partition-type:%a\n", (Name + 15)));
    542     if ( !AsciiStrnCmp  ( (Name + 15) , "system", 6) || !AsciiStrnCmp  ( (Name + 15) , "userdata", 8)
    543             || !AsciiStrnCmp  ( (Name + 15) , "cache", 5)) {
    544       AsciiStrCpy (Value, "ext4");
    545     } else {
    546       AsciiStrCpy (Value, "raw");
    547     }
    548   } else if ( !AsciiStrCmp (Name, "erase-block-size")) {
    549     AsciiSPrint (Value, 12, "0x%llx", HIKEY_ERASE_SIZE);
    550   } else if ( !AsciiStrCmp (Name, "logical-block-size")) {
    551     AsciiSPrint (Value, 12, "0x%llx", HIKEY_ERASE_SIZE);
    552   } else {
    553     *Value = '\0';
    554   }
    555   return EFI_SUCCESS;
    556 }
    557 
    558 EFI_STATUS
    559 HiKeyFastbootPlatformOemCommand (
    560   IN  CHAR8   *Command
    561   )
    562 {
    563   EFI_STATUS   Status;
    564   CHAR16       UnicodeSN[SERIAL_NUMBER_SIZE];
    565 
    566   if (AsciiStrCmp (Command, "Demonstrate") == 0) {
    567     DEBUG ((DEBUG_ERROR, "ARM OEM Fastboot command 'Demonstrate' received.\n"));
    568     return EFI_SUCCESS;
    569   } else if (AsciiStrCmp (Command, "serialno") == 0) {
    570     Status = GenerateUsbSN (UnicodeSN);
    571     if (EFI_ERROR (Status)) {
    572       DEBUG ((DEBUG_ERROR, "Failed to generate USB Serial Number.\n"));
    573       return Status;
    574     }
    575     Status = StoreSNToBlock (mFlashHandle, SERIAL_NUMBER_LBA, UnicodeSN);
    576     return Status;
    577   } else if (AsciiStrCmp (Command, "reboot-bootloader") == 0) {
    578     MmioWrite32 (ADB_REBOOT_ADDRESS, ADB_REBOOT_BOOTLOADER);
    579     WriteBackInvalidateDataCacheRange ((VOID *)ADB_REBOOT_ADDRESS, 4);
    580     return EFI_SUCCESS;
    581   } else {
    582     DEBUG ((DEBUG_ERROR,
    583       "HiKey: Unrecognised Fastboot OEM command: %s\n",
    584       Command
    585       ));
    586     return EFI_NOT_FOUND;
    587   }
    588 }
    589 
    590 EFI_STATUS
    591 HiKeyFastbootPlatformFlashPartitionEx (
    592   IN CHAR8  *PartitionName,
    593   IN UINTN   Offset,
    594   IN UINTN   Size,
    595   IN VOID   *Image
    596   )
    597 {
    598   EFI_STATUS               Status;
    599   UINTN                    PartitionSize;
    600   FASTBOOT_PARTITION_LIST *Entry;
    601   CHAR16                   PartitionNameUnicode[60];
    602   BOOLEAN                  PartitionFound;
    603   UINTN                    BlockSize;
    604   EFI_DISK_IO_PROTOCOL    *DiskIo;
    605 
    606   AsciiStrToUnicodeStr (PartitionName, PartitionNameUnicode);
    607   PartitionFound = FALSE;
    608   Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&(mPartitionListHead));
    609   while (!IsNull (&mPartitionListHead, &Entry->Link)) {
    610     // Search the partition list for the partition named by PartitionName
    611     if (StrCmp (Entry->PartitionName, PartitionNameUnicode) == 0) {
    612       PartitionFound = TRUE;
    613       break;
    614     }
    615 
    616    Entry = (FASTBOOT_PARTITION_LIST *) GetNextNode (&mPartitionListHead, &(Entry)->Link);
    617   }
    618   if (!PartitionFound) {
    619     return EFI_NOT_FOUND;
    620   }
    621 
    622   // Check image will fit on device
    623   PartitionSize = (Entry->EndingLBA - Entry->StartingLBA + 1) * mFlashBlockIo->Media->BlockSize;
    624   if (PartitionSize < Size) {
    625     DEBUG ((DEBUG_ERROR, "Partition not big enough.\n"));
    626     DEBUG ((DEBUG_ERROR, "Partition Size:\t%ld\nImage Size:\t%ld\n", PartitionSize, Size));
    627 
    628     return EFI_VOLUME_FULL;
    629   }
    630 
    631   BlockSize = mFlashBlockIo->Media->BlockSize;
    632   Status = gBS->OpenProtocol (
    633                   mFlashHandle,
    634                   &gEfiDiskIoProtocolGuid,
    635                   (VOID **) &DiskIo,
    636                   gImageHandle,
    637                   NULL,
    638                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    639                   );
    640   if (EFI_ERROR (Status)) {
    641     return Status;
    642   }
    643 
    644   Status = DiskIo->WriteDisk (
    645                      DiskIo,
    646                      mFlashBlockIo->Media->MediaId,
    647                      Entry->StartingLBA * BlockSize + Offset,
    648                      Size,
    649                      Image
    650                      );
    651   if (EFI_ERROR (Status)) {
    652     DEBUG ((DEBUG_ERROR, "Failed to write %d bytes into 0x%x, Status:%r\n", Size, Entry->StartingLBA * BlockSize + Offset, Status));
    653     return Status;
    654   }
    655   return Status;
    656 }
    657 
    658 FASTBOOT_PLATFORM_PROTOCOL mPlatformProtocol = {
    659   HiKeyFastbootPlatformInit,
    660   HiKeyFastbootPlatformUnInit,
    661   HiKeyFastbootPlatformFlashPartition,
    662   HiKeyFastbootPlatformErasePartition,
    663   HiKeyFastbootPlatformGetVar,
    664   HiKeyFastbootPlatformOemCommand,
    665   HiKeyFastbootPlatformFlashPartitionEx
    666 };
    667 
    668 EFI_STATUS
    669 EFIAPI
    670 HiKeyFastbootPlatformEntryPoint (
    671   IN EFI_HANDLE                            ImageHandle,
    672   IN EFI_SYSTEM_TABLE                      *SystemTable
    673   )
    674 {
    675   return gBS->InstallProtocolInterface (
    676                 &ImageHandle,
    677                 &gAndroidFastbootPlatformProtocolGuid,
    678                 EFI_NATIVE_INTERFACE,
    679                 &mPlatformProtocol
    680                 );
    681 }
    682