Message ID | 1486998621-30420-6-git-send-email-haojian.zhuang@linaro.org |
---|---|
State | Superseded |
Headers | show |
Series | add drivers for Android Fastboot App on HiKey | expand |
On Mon, Feb 13, 2017 at 11:10:21PM +0800, Haojian Zhuang wrote: > Support HiKey Fastboot driver for Fastboot App. > 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 | 667 +++++++++++++++++++++ > .../HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.inf | 61 ++ > .../Hisilicon/HiKey/Include/Guid/HiKeyVariable.h | 24 + > 4 files changed, 753 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..ce6293c > --- /dev/null > +++ b/Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.c > @@ -0,0 +1,667 @@ > +/** @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 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 > +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; > + UINT32 EntrySize, EntryOffset; > + 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 = Image; Is it not the case that this block... > + // not a string with terminated '\0' > + if (AsciiStrnCmp (Buffer, "ENTRYHDR", HIKEY_PTABLE_HEAD_MAGIC_LEN) != 0) { > + DEBUG ((DEBUG_ERROR, "unknown ptable image\n")); > + return EFI_UNSUPPORTED; > + } > + Buffer += HIKEY_PTABLE_HEAD_MAGIC_LEN; > + // not a string with terminated '\0' > + if (AsciiStrnCmp (Buffer, "primary", HIKEY_PTABLE_HEAD_NAME_LEN) != 0) { > + DEBUG ((DEBUG_ERROR, "unknown ptable image\n")); > + return EFI_UNSUPPORTED; > + } > + 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 EFI_UNSUPPORTED; > + } > + Buffer = Image + HIKEY_PTABLE_CONTENT_OFFSET; > + Status = DiskIo->WriteDisk (DiskIo, MediaId, EntryOffset, EntrySize, Buffer); ...to here ... > + if (EFI_ERROR (Status)) { > + return Status; > + } > + ... is identical to this block ... > + Buffer = Image + HIKEY_PTABLE_CONTENT_OFFSET; > + // not a string with terminated '\0' > + if (AsciiStrnCmp (Buffer, "ENTRYHDR", HIKEY_PTABLE_HEAD_MAGIC_LEN) != 0) { > + return Status; > + } > + Buffer += HIKEY_PTABLE_HEAD_MAGIC_LEN; > + // not a string with terminated '\0' > + if (AsciiStrnCmp (Buffer, "second", HIKEY_PTABLE_HEAD_NAME_LEN) != 0) { > + return Status; > + } > + 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 EFI_UNSUPPORTED; > + } > + Buffer = Image + HIKEY_PTABLE_CONTENT_OFFSET; > + Status = DiskIo->WriteDisk (DiskIo, MediaId, EntryOffset, EntrySize, Buffer); ... to here. With the exception of the PTABLE_HEAD_NAME being "primary" in the first case and "second" in the latter? If so, could that be turned into a single helper function, called twice? > + } else { > + Status = DiskIo->WriteDisk (DiskIo, MediaId, 0, Size, Image); > + } > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + BlockIo->FlushBlocks(BlockIo); > + MicroSecondDelay (50000); Why this delay? Barrier needed? Why 50ms? > + > + 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 Please insert TimerLib alphabetically. > + > +[Protocols] > + gAndroidFastbootPlatformProtocolGuid > + gEfiBlockIoProtocolGuid > + gEfiDiskIoProtocolGuid > + gEfiSimpleTextOutProtocolGuid > + gEfiEraseBlockProtocolGuid 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 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 >
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..ce6293c --- /dev/null +++ b/Platforms/Hisilicon/HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.c @@ -0,0 +1,667 @@ +/** @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 +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; + UINT32 EntrySize, EntryOffset; + 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 = 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 EFI_UNSUPPORTED; + } + Buffer += HIKEY_PTABLE_HEAD_MAGIC_LEN; + // not a string with terminated '\0' + if (AsciiStrnCmp (Buffer, "primary", HIKEY_PTABLE_HEAD_NAME_LEN) != 0) { + DEBUG ((DEBUG_ERROR, "unknown ptable image\n")); + return EFI_UNSUPPORTED; + } + 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 EFI_UNSUPPORTED; + } + Buffer = Image + HIKEY_PTABLE_CONTENT_OFFSET; + Status = DiskIo->WriteDisk (DiskIo, MediaId, EntryOffset, EntrySize, Buffer); + if (EFI_ERROR (Status)) { + return Status; + } + + Buffer = Image + HIKEY_PTABLE_CONTENT_OFFSET; + // not a string with terminated '\0' + if (AsciiStrnCmp (Buffer, "ENTRYHDR", HIKEY_PTABLE_HEAD_MAGIC_LEN) != 0) { + return Status; + } + Buffer += HIKEY_PTABLE_HEAD_MAGIC_LEN; + // not a string with terminated '\0' + if (AsciiStrnCmp (Buffer, "second", HIKEY_PTABLE_HEAD_NAME_LEN) != 0) { + return Status; + } + 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 EFI_UNSUPPORTED; + } + Buffer = Image + HIKEY_PTABLE_CONTENT_OFFSET; + Status = DiskIo->WriteDisk (DiskIo, MediaId, EntryOffset, EntrySize, Buffer); + } else { + Status = DiskIo->WriteDisk (DiskIo, MediaId, 0, Size, Image); + } + if (EFI_ERROR (Status)) { + return Status; + } + + BlockIo->FlushBlocks(BlockIo); + 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__ */
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 | 667 +++++++++++++++++++++ .../HiKey/HiKeyFastbootDxe/HiKeyFastbootDxe.inf | 61 ++ .../Hisilicon/HiKey/Include/Guid/HiKeyVariable.h | 24 + 4 files changed, 753 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