181f2915669f734f34e3e83c83287e7371e298390Olivier Martin/** @file
281f2915669f734f34e3e83c83287e7371e298390Olivier Martin
381f2915669f734f34e3e83c83287e7371e298390Olivier Martin  Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
481f2915669f734f34e3e83c83287e7371e298390Olivier Martin
581f2915669f734f34e3e83c83287e7371e298390Olivier Martin  This program and the accompanying materials
681f2915669f734f34e3e83c83287e7371e298390Olivier Martin  are licensed and made available under the terms and conditions of the BSD License
781f2915669f734f34e3e83c83287e7371e298390Olivier Martin  which accompanies this distribution.  The full text of the license may be found at
881f2915669f734f34e3e83c83287e7371e298390Olivier Martin  http://opensource.org/licenses/bsd-license.php
981f2915669f734f34e3e83c83287e7371e298390Olivier Martin
1081f2915669f734f34e3e83c83287e7371e298390Olivier Martin  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
1181f2915669f734f34e3e83c83287e7371e298390Olivier Martin  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
1281f2915669f734f34e3e83c83287e7371e298390Olivier Martin
1381f2915669f734f34e3e83c83287e7371e298390Olivier Martin**/
1481f2915669f734f34e3e83c83287e7371e298390Olivier Martin
1581f2915669f734f34e3e83c83287e7371e298390Olivier Martin/*
1681f2915669f734f34e3e83c83287e7371e298390Olivier Martin  Implementation of the Android Fastboot Platform protocol, to be used by the
1781f2915669f734f34e3e83c83287e7371e298390Olivier Martin  Fastboot UEFI application, for ARM Versatile Express platforms.
1881f2915669f734f34e3e83c83287e7371e298390Olivier Martin*/
1981f2915669f734f34e3e83c83287e7371e298390Olivier Martin
2081f2915669f734f34e3e83c83287e7371e298390Olivier Martin#include <Protocol/AndroidFastbootPlatform.h>
2181f2915669f734f34e3e83c83287e7371e298390Olivier Martin#include <Protocol/BlockIo.h>
2281f2915669f734f34e3e83c83287e7371e298390Olivier Martin#include <Protocol/DiskIo.h>
2381f2915669f734f34e3e83c83287e7371e298390Olivier Martin
2481f2915669f734f34e3e83c83287e7371e298390Olivier Martin#include <Library/BaseLib.h>
2581f2915669f734f34e3e83c83287e7371e298390Olivier Martin#include <Library/BaseMemoryLib.h>
2681f2915669f734f34e3e83c83287e7371e298390Olivier Martin#include <Library/DebugLib.h>
2781f2915669f734f34e3e83c83287e7371e298390Olivier Martin#include <Library/DevicePathLib.h>
2881f2915669f734f34e3e83c83287e7371e298390Olivier Martin#include <Library/MemoryAllocationLib.h>
2981f2915669f734f34e3e83c83287e7371e298390Olivier Martin#include <Library/UefiBootServicesTableLib.h>
3081f2915669f734f34e3e83c83287e7371e298390Olivier Martin
3181f2915669f734f34e3e83c83287e7371e298390Olivier Martin#define FLASH_DEVICE_PATH_SIZE(DevPath) ( GetDevicePathSize (DevPath) - \
3281f2915669f734f34e3e83c83287e7371e298390Olivier Martin                                            sizeof (EFI_DEVICE_PATH_PROTOCOL))
3381f2915669f734f34e3e83c83287e7371e298390Olivier Martin
3481f2915669f734f34e3e83c83287e7371e298390Olivier Martin#define PARTITION_NAME_MAX_LENGTH 72/2
3581f2915669f734f34e3e83c83287e7371e298390Olivier Martin
3681f2915669f734f34e3e83c83287e7371e298390Olivier Martin#define IS_ALPHA(Char) (((Char) <= L'z' && (Char) >= L'a') || \
3781f2915669f734f34e3e83c83287e7371e298390Olivier Martin                        ((Char) <= L'Z' && (Char) >= L'Z'))
3881f2915669f734f34e3e83c83287e7371e298390Olivier Martin
3981f2915669f734f34e3e83c83287e7371e298390Olivier Martintypedef struct _FASTBOOT_PARTITION_LIST {
4081f2915669f734f34e3e83c83287e7371e298390Olivier Martin  LIST_ENTRY  Link;
4181f2915669f734f34e3e83c83287e7371e298390Olivier Martin  CHAR16      PartitionName[PARTITION_NAME_MAX_LENGTH];
4281f2915669f734f34e3e83c83287e7371e298390Olivier Martin  EFI_HANDLE  PartitionHandle;
4381f2915669f734f34e3e83c83287e7371e298390Olivier Martin} FASTBOOT_PARTITION_LIST;
4481f2915669f734f34e3e83c83287e7371e298390Olivier Martin
4581f2915669f734f34e3e83c83287e7371e298390Olivier MartinSTATIC LIST_ENTRY mPartitionListHead;
4681f2915669f734f34e3e83c83287e7371e298390Olivier Martin
4781f2915669f734f34e3e83c83287e7371e298390Olivier Martin/*
4881f2915669f734f34e3e83c83287e7371e298390Olivier Martin  Helper to free the partition list
4981f2915669f734f34e3e83c83287e7371e298390Olivier Martin*/
5081f2915669f734f34e3e83c83287e7371e298390Olivier MartinSTATIC
5181f2915669f734f34e3e83c83287e7371e298390Olivier MartinVOID
5281f2915669f734f34e3e83c83287e7371e298390Olivier MartinFreePartitionList (
5381f2915669f734f34e3e83c83287e7371e298390Olivier Martin  VOID
5481f2915669f734f34e3e83c83287e7371e298390Olivier Martin  )
5581f2915669f734f34e3e83c83287e7371e298390Olivier Martin{
5681f2915669f734f34e3e83c83287e7371e298390Olivier Martin  FASTBOOT_PARTITION_LIST *Entry;
5781f2915669f734f34e3e83c83287e7371e298390Olivier Martin  FASTBOOT_PARTITION_LIST *NextEntry;
5881f2915669f734f34e3e83c83287e7371e298390Olivier Martin
5981f2915669f734f34e3e83c83287e7371e298390Olivier Martin  Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&mPartitionListHead);
6081f2915669f734f34e3e83c83287e7371e298390Olivier Martin  while (!IsNull (&mPartitionListHead, &Entry->Link)) {
6181f2915669f734f34e3e83c83287e7371e298390Olivier Martin    NextEntry = (FASTBOOT_PARTITION_LIST *) GetNextNode (&mPartitionListHead, &Entry->Link);
6281f2915669f734f34e3e83c83287e7371e298390Olivier Martin
6381f2915669f734f34e3e83c83287e7371e298390Olivier Martin    RemoveEntryList (&Entry->Link);
6481f2915669f734f34e3e83c83287e7371e298390Olivier Martin    FreePool (Entry);
6581f2915669f734f34e3e83c83287e7371e298390Olivier Martin
6681f2915669f734f34e3e83c83287e7371e298390Olivier Martin    Entry = NextEntry;
6781f2915669f734f34e3e83c83287e7371e298390Olivier Martin  }
6881f2915669f734f34e3e83c83287e7371e298390Olivier Martin}
6981f2915669f734f34e3e83c83287e7371e298390Olivier Martin/*
7081f2915669f734f34e3e83c83287e7371e298390Olivier Martin  Read the PartitionName fields from the GPT partition entries, putting them
7181f2915669f734f34e3e83c83287e7371e298390Olivier Martin  into an allocated array that should later be freed.
7281f2915669f734f34e3e83c83287e7371e298390Olivier Martin*/
7381f2915669f734f34e3e83c83287e7371e298390Olivier MartinSTATIC
7481f2915669f734f34e3e83c83287e7371e298390Olivier MartinEFI_STATUS
7581f2915669f734f34e3e83c83287e7371e298390Olivier MartinReadPartitionEntries (
7681f2915669f734f34e3e83c83287e7371e298390Olivier Martin  IN  EFI_BLOCK_IO_PROTOCOL *BlockIo,
7781f2915669f734f34e3e83c83287e7371e298390Olivier Martin  OUT EFI_PARTITION_ENTRY  **PartitionEntries
7881f2915669f734f34e3e83c83287e7371e298390Olivier Martin  )
7981f2915669f734f34e3e83c83287e7371e298390Olivier Martin{
8081f2915669f734f34e3e83c83287e7371e298390Olivier Martin  UINTN                       EntrySize;
8181f2915669f734f34e3e83c83287e7371e298390Olivier Martin  UINTN                       NumEntries;
8281f2915669f734f34e3e83c83287e7371e298390Olivier Martin  UINTN                       BufferSize;
8381f2915669f734f34e3e83c83287e7371e298390Olivier Martin  UINT32                      MediaId;
8481f2915669f734f34e3e83c83287e7371e298390Olivier Martin  EFI_PARTITION_TABLE_HEADER *GptHeader;
8581f2915669f734f34e3e83c83287e7371e298390Olivier Martin  EFI_STATUS                  Status;
8681f2915669f734f34e3e83c83287e7371e298390Olivier Martin
8781f2915669f734f34e3e83c83287e7371e298390Olivier Martin  MediaId = BlockIo->Media->MediaId;
8881f2915669f734f34e3e83c83287e7371e298390Olivier Martin
8981f2915669f734f34e3e83c83287e7371e298390Olivier Martin  //
9081f2915669f734f34e3e83c83287e7371e298390Olivier Martin  // Read size of Partition entry and number of entries from GPT header
9181f2915669f734f34e3e83c83287e7371e298390Olivier Martin  //
9281f2915669f734f34e3e83c83287e7371e298390Olivier Martin
9381f2915669f734f34e3e83c83287e7371e298390Olivier Martin  GptHeader = AllocatePool (BlockIo->Media->BlockSize);
9481f2915669f734f34e3e83c83287e7371e298390Olivier Martin  if (GptHeader == NULL) {
9581f2915669f734f34e3e83c83287e7371e298390Olivier Martin    return EFI_OUT_OF_RESOURCES;
9681f2915669f734f34e3e83c83287e7371e298390Olivier Martin  }
9781f2915669f734f34e3e83c83287e7371e298390Olivier Martin
9881f2915669f734f34e3e83c83287e7371e298390Olivier Martin  Status = BlockIo->ReadBlocks (BlockIo, MediaId, 1, BlockIo->Media->BlockSize, (VOID *) GptHeader);
9981f2915669f734f34e3e83c83287e7371e298390Olivier Martin  if (EFI_ERROR (Status)) {
10081f2915669f734f34e3e83c83287e7371e298390Olivier Martin    return Status;
10181f2915669f734f34e3e83c83287e7371e298390Olivier Martin  }
10281f2915669f734f34e3e83c83287e7371e298390Olivier Martin
10381f2915669f734f34e3e83c83287e7371e298390Olivier Martin  // Check there is a GPT on the media
10481f2915669f734f34e3e83c83287e7371e298390Olivier Martin  if (GptHeader->Header.Signature != EFI_PTAB_HEADER_ID ||
10581f2915669f734f34e3e83c83287e7371e298390Olivier Martin      GptHeader->MyLBA != 1) {
10681f2915669f734f34e3e83c83287e7371e298390Olivier Martin    DEBUG ((EFI_D_ERROR,
10781f2915669f734f34e3e83c83287e7371e298390Olivier Martin      "Fastboot platform: No GPT on flash. "
10881f2915669f734f34e3e83c83287e7371e298390Olivier Martin      "Fastboot on Versatile Express does not support MBR.\n"
10981f2915669f734f34e3e83c83287e7371e298390Olivier Martin      ));
11081f2915669f734f34e3e83c83287e7371e298390Olivier Martin    return EFI_DEVICE_ERROR;
11181f2915669f734f34e3e83c83287e7371e298390Olivier Martin  }
11281f2915669f734f34e3e83c83287e7371e298390Olivier Martin
11381f2915669f734f34e3e83c83287e7371e298390Olivier Martin  EntrySize = GptHeader->SizeOfPartitionEntry;
11481f2915669f734f34e3e83c83287e7371e298390Olivier Martin  NumEntries = GptHeader->NumberOfPartitionEntries;
11581f2915669f734f34e3e83c83287e7371e298390Olivier Martin
11681f2915669f734f34e3e83c83287e7371e298390Olivier Martin  FreePool (GptHeader);
11781f2915669f734f34e3e83c83287e7371e298390Olivier Martin
11881f2915669f734f34e3e83c83287e7371e298390Olivier Martin  ASSERT (EntrySize != 0);
11981f2915669f734f34e3e83c83287e7371e298390Olivier Martin  ASSERT (NumEntries != 0);
12081f2915669f734f34e3e83c83287e7371e298390Olivier Martin
12181f2915669f734f34e3e83c83287e7371e298390Olivier Martin  BufferSize = ALIGN_VALUE (EntrySize * NumEntries, BlockIo->Media->BlockSize);
12281f2915669f734f34e3e83c83287e7371e298390Olivier Martin  *PartitionEntries = AllocatePool (BufferSize);
12381f2915669f734f34e3e83c83287e7371e298390Olivier Martin  if (PartitionEntries == NULL) {
12481f2915669f734f34e3e83c83287e7371e298390Olivier Martin    return EFI_OUT_OF_RESOURCES;
12581f2915669f734f34e3e83c83287e7371e298390Olivier Martin  }
12681f2915669f734f34e3e83c83287e7371e298390Olivier Martin
12781f2915669f734f34e3e83c83287e7371e298390Olivier Martin  Status = BlockIo->ReadBlocks (BlockIo, MediaId, 2, BufferSize, (VOID *) *PartitionEntries);
12881f2915669f734f34e3e83c83287e7371e298390Olivier Martin  if (EFI_ERROR (Status)) {
12981f2915669f734f34e3e83c83287e7371e298390Olivier Martin    FreePool (PartitionEntries);
13081f2915669f734f34e3e83c83287e7371e298390Olivier Martin    return Status;
13181f2915669f734f34e3e83c83287e7371e298390Olivier Martin  }
13281f2915669f734f34e3e83c83287e7371e298390Olivier Martin
13381f2915669f734f34e3e83c83287e7371e298390Olivier Martin  return Status;
13481f2915669f734f34e3e83c83287e7371e298390Olivier Martin}
13581f2915669f734f34e3e83c83287e7371e298390Olivier Martin
13681f2915669f734f34e3e83c83287e7371e298390Olivier Martin
13781f2915669f734f34e3e83c83287e7371e298390Olivier Martin/*
13881f2915669f734f34e3e83c83287e7371e298390Olivier Martin  Initialise: Open the Android NVM device and find the partitions on it. Save them in
13981f2915669f734f34e3e83c83287e7371e298390Olivier Martin  a list along with the "PartitionName" fields for their GPT entries.
14081f2915669f734f34e3e83c83287e7371e298390Olivier Martin  We will use these partition names as the key in
14181f2915669f734f34e3e83c83287e7371e298390Olivier Martin  ArmFastbootPlatformFlashPartition.
14281f2915669f734f34e3e83c83287e7371e298390Olivier Martin*/
14381f2915669f734f34e3e83c83287e7371e298390Olivier MartinEFI_STATUS
14481f2915669f734f34e3e83c83287e7371e298390Olivier MartinArmFastbootPlatformInit (
14581f2915669f734f34e3e83c83287e7371e298390Olivier Martin  VOID
14681f2915669f734f34e3e83c83287e7371e298390Olivier Martin  )
14781f2915669f734f34e3e83c83287e7371e298390Olivier Martin{
14881f2915669f734f34e3e83c83287e7371e298390Olivier Martin  EFI_STATUS                          Status;
14981f2915669f734f34e3e83c83287e7371e298390Olivier Martin  EFI_DEVICE_PATH_PROTOCOL           *FlashDevicePath;
15081f2915669f734f34e3e83c83287e7371e298390Olivier Martin  EFI_DEVICE_PATH_PROTOCOL           *FlashDevicePathDup;
15181f2915669f734f34e3e83c83287e7371e298390Olivier Martin  EFI_DEVICE_PATH_PROTOCOL           *DevicePath;
15281f2915669f734f34e3e83c83287e7371e298390Olivier Martin  EFI_DEVICE_PATH_PROTOCOL           *NextNode;
15381f2915669f734f34e3e83c83287e7371e298390Olivier Martin  HARDDRIVE_DEVICE_PATH              *PartitionNode;
15481f2915669f734f34e3e83c83287e7371e298390Olivier Martin  UINTN                               NumHandles;
15581f2915669f734f34e3e83c83287e7371e298390Olivier Martin  EFI_HANDLE                         *AllHandles;
15681f2915669f734f34e3e83c83287e7371e298390Olivier Martin  UINTN                               LoopIndex;
15781f2915669f734f34e3e83c83287e7371e298390Olivier Martin  EFI_HANDLE                          FlashHandle;
15881f2915669f734f34e3e83c83287e7371e298390Olivier Martin  EFI_BLOCK_IO_PROTOCOL              *FlashBlockIo;
15981f2915669f734f34e3e83c83287e7371e298390Olivier Martin  EFI_PARTITION_ENTRY                *PartitionEntries;
16081f2915669f734f34e3e83c83287e7371e298390Olivier Martin  FASTBOOT_PARTITION_LIST            *Entry;
16181f2915669f734f34e3e83c83287e7371e298390Olivier Martin
16281f2915669f734f34e3e83c83287e7371e298390Olivier Martin  InitializeListHead (&mPartitionListHead);
16381f2915669f734f34e3e83c83287e7371e298390Olivier Martin
16481f2915669f734f34e3e83c83287e7371e298390Olivier Martin  //
16581f2915669f734f34e3e83c83287e7371e298390Olivier Martin  // Get EFI_HANDLES for all the partitions on the block devices pointed to by
16681f2915669f734f34e3e83c83287e7371e298390Olivier Martin  // PcdFastbootFlashDevicePath, also saving their GPT partition labels.
16781f2915669f734f34e3e83c83287e7371e298390Olivier Martin  // There's no way to find all of a device's children, so we get every handle
16881f2915669f734f34e3e83c83287e7371e298390Olivier Martin  // in the system supporting EFI_BLOCK_IO_PROTOCOL and then filter out ones
16981f2915669f734f34e3e83c83287e7371e298390Olivier Martin  // that don't represent partitions on the flash device.
17081f2915669f734f34e3e83c83287e7371e298390Olivier Martin  //
17181f2915669f734f34e3e83c83287e7371e298390Olivier Martin
17281f2915669f734f34e3e83c83287e7371e298390Olivier Martin  FlashDevicePath = ConvertTextToDevicePath ((CHAR16*)FixedPcdGetPtr (PcdAndroidFastbootNvmDevicePath));
17381f2915669f734f34e3e83c83287e7371e298390Olivier Martin
17481f2915669f734f34e3e83c83287e7371e298390Olivier Martin  //
17581f2915669f734f34e3e83c83287e7371e298390Olivier Martin  // Open the Disk IO protocol on the flash device - this will be used to read
17681f2915669f734f34e3e83c83287e7371e298390Olivier Martin  // partition names out of the GPT entries
17781f2915669f734f34e3e83c83287e7371e298390Olivier Martin  //
17881f2915669f734f34e3e83c83287e7371e298390Olivier Martin  // Create another device path pointer because LocateDevicePath will modify it.
17981f2915669f734f34e3e83c83287e7371e298390Olivier Martin  FlashDevicePathDup = FlashDevicePath;
18081f2915669f734f34e3e83c83287e7371e298390Olivier Martin  Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &FlashDevicePathDup, &FlashHandle);
18181f2915669f734f34e3e83c83287e7371e298390Olivier Martin  if (EFI_ERROR (Status)) {
18281f2915669f734f34e3e83c83287e7371e298390Olivier Martin    DEBUG ((EFI_D_ERROR, "Warning: Couldn't locate Android NVM device (status: %r)\n", Status));
18381f2915669f734f34e3e83c83287e7371e298390Olivier Martin    // Failing to locate partitions should not prevent to do other Android FastBoot actions
18481f2915669f734f34e3e83c83287e7371e298390Olivier Martin    return EFI_SUCCESS;
18581f2915669f734f34e3e83c83287e7371e298390Olivier Martin  }
18681f2915669f734f34e3e83c83287e7371e298390Olivier Martin
18781f2915669f734f34e3e83c83287e7371e298390Olivier Martin  Status = gBS->OpenProtocol (
18881f2915669f734f34e3e83c83287e7371e298390Olivier Martin                  FlashHandle,
18981f2915669f734f34e3e83c83287e7371e298390Olivier Martin                  &gEfiBlockIoProtocolGuid,
19081f2915669f734f34e3e83c83287e7371e298390Olivier Martin                  (VOID **) &FlashBlockIo,
19181f2915669f734f34e3e83c83287e7371e298390Olivier Martin                  gImageHandle,
19281f2915669f734f34e3e83c83287e7371e298390Olivier Martin                  NULL,
19381f2915669f734f34e3e83c83287e7371e298390Olivier Martin                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
19481f2915669f734f34e3e83c83287e7371e298390Olivier Martin                  );
19581f2915669f734f34e3e83c83287e7371e298390Olivier Martin  if (EFI_ERROR (Status)) {
19681f2915669f734f34e3e83c83287e7371e298390Olivier Martin    DEBUG ((EFI_D_ERROR, "Fastboot platform: Couldn't open Android NVM device (status: %r)\n", Status));
19781f2915669f734f34e3e83c83287e7371e298390Olivier Martin    return EFI_DEVICE_ERROR;
19881f2915669f734f34e3e83c83287e7371e298390Olivier Martin  }
19981f2915669f734f34e3e83c83287e7371e298390Olivier Martin
20081f2915669f734f34e3e83c83287e7371e298390Olivier Martin  // Read the GPT partition entry array into memory so we can get the partition names
20181f2915669f734f34e3e83c83287e7371e298390Olivier Martin  Status = ReadPartitionEntries (FlashBlockIo, &PartitionEntries);
20281f2915669f734f34e3e83c83287e7371e298390Olivier Martin  if (EFI_ERROR (Status)) {
20391c38d4e94c1461f5824b83d3722fe46626aa0d3Ronald Cron    DEBUG ((EFI_D_ERROR, "Warning: Failed to read partitions from Android NVM device (status: %r)\n", Status));
20491c38d4e94c1461f5824b83d3722fe46626aa0d3Ronald Cron    // Failing to locate partitions should not prevent to do other Android FastBoot actions
20591c38d4e94c1461f5824b83d3722fe46626aa0d3Ronald Cron    return EFI_SUCCESS;
20681f2915669f734f34e3e83c83287e7371e298390Olivier Martin  }
20781f2915669f734f34e3e83c83287e7371e298390Olivier Martin
20881f2915669f734f34e3e83c83287e7371e298390Olivier Martin  // Get every Block IO protocol instance installed in the system
20981f2915669f734f34e3e83c83287e7371e298390Olivier Martin  Status = gBS->LocateHandleBuffer (
21081f2915669f734f34e3e83c83287e7371e298390Olivier Martin                  ByProtocol,
21181f2915669f734f34e3e83c83287e7371e298390Olivier Martin                  &gEfiBlockIoProtocolGuid,
21281f2915669f734f34e3e83c83287e7371e298390Olivier Martin                  NULL,
21381f2915669f734f34e3e83c83287e7371e298390Olivier Martin                  &NumHandles,
21481f2915669f734f34e3e83c83287e7371e298390Olivier Martin                  &AllHandles
21581f2915669f734f34e3e83c83287e7371e298390Olivier Martin                  );
21681f2915669f734f34e3e83c83287e7371e298390Olivier Martin  ASSERT_EFI_ERROR (Status);
21781f2915669f734f34e3e83c83287e7371e298390Olivier Martin
21881f2915669f734f34e3e83c83287e7371e298390Olivier Martin  // Filter out handles that aren't children of the flash device
21981f2915669f734f34e3e83c83287e7371e298390Olivier Martin  for (LoopIndex = 0; LoopIndex < NumHandles; LoopIndex++) {
22081f2915669f734f34e3e83c83287e7371e298390Olivier Martin    // Get the device path for the handle
22181f2915669f734f34e3e83c83287e7371e298390Olivier Martin    Status = gBS->OpenProtocol (
22281f2915669f734f34e3e83c83287e7371e298390Olivier Martin                    AllHandles[LoopIndex],
22381f2915669f734f34e3e83c83287e7371e298390Olivier Martin                    &gEfiDevicePathProtocolGuid,
22481f2915669f734f34e3e83c83287e7371e298390Olivier Martin                    (VOID **) &DevicePath,
22581f2915669f734f34e3e83c83287e7371e298390Olivier Martin                    gImageHandle,
22681f2915669f734f34e3e83c83287e7371e298390Olivier Martin                    NULL,
22781f2915669f734f34e3e83c83287e7371e298390Olivier Martin                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
22881f2915669f734f34e3e83c83287e7371e298390Olivier Martin                    );
22981f2915669f734f34e3e83c83287e7371e298390Olivier Martin    ASSERT_EFI_ERROR (Status);
23081f2915669f734f34e3e83c83287e7371e298390Olivier Martin
23181f2915669f734f34e3e83c83287e7371e298390Olivier Martin    // Check if it is a sub-device of the flash device
23281f2915669f734f34e3e83c83287e7371e298390Olivier Martin    if (!CompareMem (DevicePath, FlashDevicePath, FLASH_DEVICE_PATH_SIZE (FlashDevicePath))) {
23381f2915669f734f34e3e83c83287e7371e298390Olivier Martin      // Device path starts with path of flash device. Check it isn't the flash
23481f2915669f734f34e3e83c83287e7371e298390Olivier Martin      // device itself.
23581f2915669f734f34e3e83c83287e7371e298390Olivier Martin      NextNode = NextDevicePathNode (DevicePath);
23681f2915669f734f34e3e83c83287e7371e298390Olivier Martin      if (IsDevicePathEndType (NextNode)) {
23781f2915669f734f34e3e83c83287e7371e298390Olivier Martin        continue;
23881f2915669f734f34e3e83c83287e7371e298390Olivier Martin      }
23981f2915669f734f34e3e83c83287e7371e298390Olivier Martin
24081f2915669f734f34e3e83c83287e7371e298390Olivier Martin      // Assert that this device path node represents a partition.
24181f2915669f734f34e3e83c83287e7371e298390Olivier Martin      ASSERT (NextNode->Type == MEDIA_DEVICE_PATH &&
24281f2915669f734f34e3e83c83287e7371e298390Olivier Martin              NextNode->SubType == MEDIA_HARDDRIVE_DP);
24381f2915669f734f34e3e83c83287e7371e298390Olivier Martin
24481f2915669f734f34e3e83c83287e7371e298390Olivier Martin      PartitionNode = (HARDDRIVE_DEVICE_PATH *) NextNode;
24581f2915669f734f34e3e83c83287e7371e298390Olivier Martin
24681f2915669f734f34e3e83c83287e7371e298390Olivier Martin      // Assert that the partition type is GPT. ReadPartitionEntries checks for
24781f2915669f734f34e3e83c83287e7371e298390Olivier Martin      // presence of a GPT, so we should never find MBR partitions.
24881f2915669f734f34e3e83c83287e7371e298390Olivier Martin      // ("MBRType" is a misnomer - this field is actually called "Partition
24981f2915669f734f34e3e83c83287e7371e298390Olivier Martin      //  Format")
25081f2915669f734f34e3e83c83287e7371e298390Olivier Martin      ASSERT (PartitionNode->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER);
25181f2915669f734f34e3e83c83287e7371e298390Olivier Martin
25281f2915669f734f34e3e83c83287e7371e298390Olivier Martin      // The firmware may install a handle for "partition 0", representing the
25381f2915669f734f34e3e83c83287e7371e298390Olivier Martin      // whole device. Ignore it.
25481f2915669f734f34e3e83c83287e7371e298390Olivier Martin      if (PartitionNode->PartitionNumber == 0) {
25581f2915669f734f34e3e83c83287e7371e298390Olivier Martin        continue;
25681f2915669f734f34e3e83c83287e7371e298390Olivier Martin      }
25781f2915669f734f34e3e83c83287e7371e298390Olivier Martin
25881f2915669f734f34e3e83c83287e7371e298390Olivier Martin      //
25981f2915669f734f34e3e83c83287e7371e298390Olivier Martin      // Add the partition handle to the list
26081f2915669f734f34e3e83c83287e7371e298390Olivier Martin      //
26181f2915669f734f34e3e83c83287e7371e298390Olivier Martin
26281f2915669f734f34e3e83c83287e7371e298390Olivier Martin      // Create entry
26381f2915669f734f34e3e83c83287e7371e298390Olivier Martin      Entry = AllocatePool (sizeof (FASTBOOT_PARTITION_LIST));
26481f2915669f734f34e3e83c83287e7371e298390Olivier Martin      if (Entry == NULL) {
26581f2915669f734f34e3e83c83287e7371e298390Olivier Martin        Status = EFI_OUT_OF_RESOURCES;
26681f2915669f734f34e3e83c83287e7371e298390Olivier Martin        FreePartitionList ();
26781f2915669f734f34e3e83c83287e7371e298390Olivier Martin        goto Exit;
26881f2915669f734f34e3e83c83287e7371e298390Olivier Martin      }
26981f2915669f734f34e3e83c83287e7371e298390Olivier Martin
27081f2915669f734f34e3e83c83287e7371e298390Olivier Martin      // Copy handle and partition name
27181f2915669f734f34e3e83c83287e7371e298390Olivier Martin      Entry->PartitionHandle = AllHandles[LoopIndex];
27281f2915669f734f34e3e83c83287e7371e298390Olivier Martin      StrnCpy (
27381f2915669f734f34e3e83c83287e7371e298390Olivier Martin        Entry->PartitionName,
27481f2915669f734f34e3e83c83287e7371e298390Olivier Martin        PartitionEntries[PartitionNode->PartitionNumber - 1].PartitionName, // Partition numbers start from 1.
27581f2915669f734f34e3e83c83287e7371e298390Olivier Martin        PARTITION_NAME_MAX_LENGTH
27681f2915669f734f34e3e83c83287e7371e298390Olivier Martin        );
27781f2915669f734f34e3e83c83287e7371e298390Olivier Martin      InsertTailList (&mPartitionListHead, &Entry->Link);
27881f2915669f734f34e3e83c83287e7371e298390Olivier Martin
27981f2915669f734f34e3e83c83287e7371e298390Olivier Martin      // Print a debug message if the partition label is empty or looks like
28081f2915669f734f34e3e83c83287e7371e298390Olivier Martin      // garbage.
28181f2915669f734f34e3e83c83287e7371e298390Olivier Martin      if (!IS_ALPHA (Entry->PartitionName[0])) {
28281f2915669f734f34e3e83c83287e7371e298390Olivier Martin        DEBUG ((EFI_D_ERROR,
28381f2915669f734f34e3e83c83287e7371e298390Olivier Martin          "Warning: Partition %d doesn't seem to have a GPT partition label. "
28481f2915669f734f34e3e83c83287e7371e298390Olivier Martin          "You won't be able to flash it with Fastboot.\n",
28581f2915669f734f34e3e83c83287e7371e298390Olivier Martin          PartitionNode->PartitionNumber
28681f2915669f734f34e3e83c83287e7371e298390Olivier Martin          ));
28781f2915669f734f34e3e83c83287e7371e298390Olivier Martin      }
28881f2915669f734f34e3e83c83287e7371e298390Olivier Martin    }
28981f2915669f734f34e3e83c83287e7371e298390Olivier Martin  }
29081f2915669f734f34e3e83c83287e7371e298390Olivier Martin
29181f2915669f734f34e3e83c83287e7371e298390Olivier MartinExit:
29281f2915669f734f34e3e83c83287e7371e298390Olivier Martin  FreePool (PartitionEntries);
29381f2915669f734f34e3e83c83287e7371e298390Olivier Martin  FreePool (FlashDevicePath);
29481f2915669f734f34e3e83c83287e7371e298390Olivier Martin  FreePool (AllHandles);
29581f2915669f734f34e3e83c83287e7371e298390Olivier Martin  return Status;
29681f2915669f734f34e3e83c83287e7371e298390Olivier Martin
29781f2915669f734f34e3e83c83287e7371e298390Olivier Martin}
29881f2915669f734f34e3e83c83287e7371e298390Olivier Martin
29981f2915669f734f34e3e83c83287e7371e298390Olivier MartinVOID
30081f2915669f734f34e3e83c83287e7371e298390Olivier MartinArmFastbootPlatformUnInit (
30181f2915669f734f34e3e83c83287e7371e298390Olivier Martin  VOID
30281f2915669f734f34e3e83c83287e7371e298390Olivier Martin  )
30381f2915669f734f34e3e83c83287e7371e298390Olivier Martin{
30481f2915669f734f34e3e83c83287e7371e298390Olivier Martin  FreePartitionList ();
30581f2915669f734f34e3e83c83287e7371e298390Olivier Martin}
30681f2915669f734f34e3e83c83287e7371e298390Olivier Martin
30781f2915669f734f34e3e83c83287e7371e298390Olivier MartinEFI_STATUS
30881f2915669f734f34e3e83c83287e7371e298390Olivier MartinArmFastbootPlatformFlashPartition (
30981f2915669f734f34e3e83c83287e7371e298390Olivier Martin  IN CHAR8  *PartitionName,
31081f2915669f734f34e3e83c83287e7371e298390Olivier Martin  IN UINTN   Size,
31181f2915669f734f34e3e83c83287e7371e298390Olivier Martin  IN VOID   *Image
31281f2915669f734f34e3e83c83287e7371e298390Olivier Martin  )
31381f2915669f734f34e3e83c83287e7371e298390Olivier Martin{
31481f2915669f734f34e3e83c83287e7371e298390Olivier Martin  EFI_STATUS               Status;
31581f2915669f734f34e3e83c83287e7371e298390Olivier Martin  EFI_BLOCK_IO_PROTOCOL   *BlockIo;
31681f2915669f734f34e3e83c83287e7371e298390Olivier Martin  EFI_DISK_IO_PROTOCOL    *DiskIo;
31781f2915669f734f34e3e83c83287e7371e298390Olivier Martin  UINT32                   MediaId;
31881f2915669f734f34e3e83c83287e7371e298390Olivier Martin  UINTN                    PartitionSize;
31981f2915669f734f34e3e83c83287e7371e298390Olivier Martin  FASTBOOT_PARTITION_LIST *Entry;
32081f2915669f734f34e3e83c83287e7371e298390Olivier Martin  CHAR16                   PartitionNameUnicode[60];
32181f2915669f734f34e3e83c83287e7371e298390Olivier Martin  BOOLEAN                  PartitionFound;
322026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio  SPARSE_HEADER           *SparseHeader;
323026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio  CHUNK_HEADER            *ChunkHeader;
324026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio  UINTN                    Offset = 0;
325026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio  UINT32                   Chunk;
326026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio
32781f2915669f734f34e3e83c83287e7371e298390Olivier Martin
32881f2915669f734f34e3e83c83287e7371e298390Olivier Martin  AsciiStrToUnicodeStr (PartitionName, PartitionNameUnicode);
32981f2915669f734f34e3e83c83287e7371e298390Olivier Martin
33081f2915669f734f34e3e83c83287e7371e298390Olivier Martin  PartitionFound = FALSE;
33181f2915669f734f34e3e83c83287e7371e298390Olivier Martin  Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&(mPartitionListHead));
33281f2915669f734f34e3e83c83287e7371e298390Olivier Martin  while (!IsNull (&mPartitionListHead, &Entry->Link)) {
33381f2915669f734f34e3e83c83287e7371e298390Olivier Martin    // Search the partition list for the partition named by PartitionName
33481f2915669f734f34e3e83c83287e7371e298390Olivier Martin    if (StrCmp (Entry->PartitionName, PartitionNameUnicode) == 0) {
33581f2915669f734f34e3e83c83287e7371e298390Olivier Martin      PartitionFound = TRUE;
33681f2915669f734f34e3e83c83287e7371e298390Olivier Martin      break;
33781f2915669f734f34e3e83c83287e7371e298390Olivier Martin    }
33881f2915669f734f34e3e83c83287e7371e298390Olivier Martin
33981f2915669f734f34e3e83c83287e7371e298390Olivier Martin   Entry = (FASTBOOT_PARTITION_LIST *) GetNextNode (&mPartitionListHead, &(Entry)->Link);
34081f2915669f734f34e3e83c83287e7371e298390Olivier Martin  }
34181f2915669f734f34e3e83c83287e7371e298390Olivier Martin  if (!PartitionFound) {
34281f2915669f734f34e3e83c83287e7371e298390Olivier Martin    return EFI_NOT_FOUND;
34381f2915669f734f34e3e83c83287e7371e298390Olivier Martin  }
34481f2915669f734f34e3e83c83287e7371e298390Olivier Martin
34581f2915669f734f34e3e83c83287e7371e298390Olivier Martin  Status = gBS->OpenProtocol (
34681f2915669f734f34e3e83c83287e7371e298390Olivier Martin                  Entry->PartitionHandle,
34781f2915669f734f34e3e83c83287e7371e298390Olivier Martin                  &gEfiBlockIoProtocolGuid,
34881f2915669f734f34e3e83c83287e7371e298390Olivier Martin                  (VOID **) &BlockIo,
34981f2915669f734f34e3e83c83287e7371e298390Olivier Martin                  gImageHandle,
35081f2915669f734f34e3e83c83287e7371e298390Olivier Martin                  NULL,
35181f2915669f734f34e3e83c83287e7371e298390Olivier Martin                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
35281f2915669f734f34e3e83c83287e7371e298390Olivier Martin                  );
35381f2915669f734f34e3e83c83287e7371e298390Olivier Martin  if (EFI_ERROR (Status)) {
35481f2915669f734f34e3e83c83287e7371e298390Olivier Martin    DEBUG ((EFI_D_ERROR, "Fastboot platform: couldn't open Block IO for flash: %r\n", Status));
35581f2915669f734f34e3e83c83287e7371e298390Olivier Martin    return EFI_NOT_FOUND;
35681f2915669f734f34e3e83c83287e7371e298390Olivier Martin  }
35781f2915669f734f34e3e83c83287e7371e298390Olivier Martin
358026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio  SparseHeader=(SPARSE_HEADER *)Image;
359026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio
360026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio  if (SparseHeader->Magic == SPARSE_HEADER_MAGIC) {
361026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio    DEBUG ((EFI_D_INFO, "Sparse Magic: 0x%x Major: %d Minor: %d fhs: %d chs: %d bs: %d tbs: %d tcs: %d checksum: %d \n",
362026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio                SparseHeader->Magic, SparseHeader->MajorVersion, SparseHeader->MinorVersion,  SparseHeader->FileHeaderSize,
363026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio                SparseHeader->ChunkHeaderSize, SparseHeader->BlockSize, SparseHeader->TotalBlocks,
364026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio                SparseHeader->TotalChunks, SparseHeader->ImageChecksum));
365026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio    if (SparseHeader->MajorVersion != 1) {
366026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio        DEBUG ((EFI_D_ERROR, "Sparse image version %d.%d not supported.\n",
367026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio                    SparseHeader->MajorVersion, SparseHeader->MinorVersion));
368026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio        return EFI_INVALID_PARAMETER;
369026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio    }
370026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio
371026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio    Size = SparseHeader->BlockSize * SparseHeader->TotalBlocks;
372026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio  }
373026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio
37481f2915669f734f34e3e83c83287e7371e298390Olivier Martin  // Check image will fit on device
37581f2915669f734f34e3e83c83287e7371e298390Olivier Martin  PartitionSize = (BlockIo->Media->LastBlock + 1) * BlockIo->Media->BlockSize;
37681f2915669f734f34e3e83c83287e7371e298390Olivier Martin  if (PartitionSize < Size) {
37781f2915669f734f34e3e83c83287e7371e298390Olivier Martin    DEBUG ((EFI_D_ERROR, "Partition not big enough.\n"));
37881f2915669f734f34e3e83c83287e7371e298390Olivier Martin    DEBUG ((EFI_D_ERROR, "Partition Size:\t%d\nImage Size:\t%d\n", PartitionSize, Size));
37981f2915669f734f34e3e83c83287e7371e298390Olivier Martin
38081f2915669f734f34e3e83c83287e7371e298390Olivier Martin    return EFI_VOLUME_FULL;
38181f2915669f734f34e3e83c83287e7371e298390Olivier Martin  }
38281f2915669f734f34e3e83c83287e7371e298390Olivier Martin
38381f2915669f734f34e3e83c83287e7371e298390Olivier Martin  MediaId = BlockIo->Media->MediaId;
38481f2915669f734f34e3e83c83287e7371e298390Olivier Martin
38581f2915669f734f34e3e83c83287e7371e298390Olivier Martin  Status = gBS->OpenProtocol (
38681f2915669f734f34e3e83c83287e7371e298390Olivier Martin                  Entry->PartitionHandle,
38781f2915669f734f34e3e83c83287e7371e298390Olivier Martin                  &gEfiDiskIoProtocolGuid,
38881f2915669f734f34e3e83c83287e7371e298390Olivier Martin                  (VOID **) &DiskIo,
38981f2915669f734f34e3e83c83287e7371e298390Olivier Martin                  gImageHandle,
39081f2915669f734f34e3e83c83287e7371e298390Olivier Martin                  NULL,
39181f2915669f734f34e3e83c83287e7371e298390Olivier Martin                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
39281f2915669f734f34e3e83c83287e7371e298390Olivier Martin                  );
39381f2915669f734f34e3e83c83287e7371e298390Olivier Martin  ASSERT_EFI_ERROR (Status);
39481f2915669f734f34e3e83c83287e7371e298390Olivier Martin
395026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio  if (SparseHeader->Magic == SPARSE_HEADER_MAGIC) {
396026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio    Image += SparseHeader->FileHeaderSize;
397026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio    for (Chunk = 0; Chunk < SparseHeader->TotalChunks; Chunk++) {
398026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio      UINTN WriteSize;
399026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio      ChunkHeader = (CHUNK_HEADER *)Image;
400026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio      DEBUG ((EFI_D_INFO, "Chunk #%d - Type: 0x%x Size: %d TotalSize: %d Offset %d\n",
401026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio                  (Chunk+1), ChunkHeader->ChunkType, ChunkHeader->ChunkSize,
402026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio                  ChunkHeader->TotalSize, Offset));
403026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio      Image += sizeof(CHUNK_HEADER);
404026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio      WriteSize=(SparseHeader->BlockSize) * ChunkHeader->ChunkSize;
405026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio      switch (ChunkHeader->ChunkType) {
406026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio        case CHUNK_TYPE_RAW:
407026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio          DEBUG ((EFI_D_INFO, "Writing %d at Offset %d\n", WriteSize, Offset));
408026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio          Status = DiskIo->WriteDisk (DiskIo, MediaId, Offset, WriteSize, Image);
409026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio          if (EFI_ERROR (Status)) {
410026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio            return Status;
411026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio          }
412026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio          Image+=WriteSize;
413026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio          break;
414026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio        case CHUNK_TYPE_DONT_CARE:
415026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio          break;
416026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio        case CHUNK_TYPE_CRC32:
417026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio          break;
418026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio        default:
419026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio          DEBUG ((EFI_D_ERROR, "Unknown Chunk Type: 0x%x"));
420026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio          return EFI_PROTOCOL_ERROR;
421026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio      }
422026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio      Offset += WriteSize;
423026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio    }
424026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio  } else {
425026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio    Status = DiskIo->WriteDisk (DiskIo, MediaId, 0, Size, Image);
426026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio    if (EFI_ERROR (Status)) {
427026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio      return Status;
428026fae27f87f326759ef0ad35f7f80a96c3e660eRiku Voipio    }
42981f2915669f734f34e3e83c83287e7371e298390Olivier Martin  }
43081f2915669f734f34e3e83c83287e7371e298390Olivier Martin
43181f2915669f734f34e3e83c83287e7371e298390Olivier Martin  BlockIo->FlushBlocks(BlockIo);
43281f2915669f734f34e3e83c83287e7371e298390Olivier Martin
43381f2915669f734f34e3e83c83287e7371e298390Olivier Martin  return Status;
43481f2915669f734f34e3e83c83287e7371e298390Olivier Martin}
43581f2915669f734f34e3e83c83287e7371e298390Olivier Martin
43681f2915669f734f34e3e83c83287e7371e298390Olivier MartinEFI_STATUS
43781f2915669f734f34e3e83c83287e7371e298390Olivier MartinArmFastbootPlatformErasePartition (
43881f2915669f734f34e3e83c83287e7371e298390Olivier Martin  IN CHAR8 *Partition
43981f2915669f734f34e3e83c83287e7371e298390Olivier Martin  )
44081f2915669f734f34e3e83c83287e7371e298390Olivier Martin{
44181f2915669f734f34e3e83c83287e7371e298390Olivier Martin  return EFI_SUCCESS;
44281f2915669f734f34e3e83c83287e7371e298390Olivier Martin}
44381f2915669f734f34e3e83c83287e7371e298390Olivier Martin
44481f2915669f734f34e3e83c83287e7371e298390Olivier MartinEFI_STATUS
44581f2915669f734f34e3e83c83287e7371e298390Olivier MartinArmFastbootPlatformGetVar (
44681f2915669f734f34e3e83c83287e7371e298390Olivier Martin  IN  CHAR8   *Name,
44781f2915669f734f34e3e83c83287e7371e298390Olivier Martin  OUT CHAR8   *Value
44881f2915669f734f34e3e83c83287e7371e298390Olivier Martin  )
44981f2915669f734f34e3e83c83287e7371e298390Olivier Martin{
45081f2915669f734f34e3e83c83287e7371e298390Olivier Martin  if (AsciiStrCmp (Name, "product")) {
45181f2915669f734f34e3e83c83287e7371e298390Olivier Martin    AsciiStrCpy (Value, FixedPcdGetPtr (PcdFirmwareVendor));
45281f2915669f734f34e3e83c83287e7371e298390Olivier Martin  } else {
45381f2915669f734f34e3e83c83287e7371e298390Olivier Martin    *Value = '\0';
45481f2915669f734f34e3e83c83287e7371e298390Olivier Martin  }
45581f2915669f734f34e3e83c83287e7371e298390Olivier Martin  return EFI_SUCCESS;
45681f2915669f734f34e3e83c83287e7371e298390Olivier Martin}
45781f2915669f734f34e3e83c83287e7371e298390Olivier Martin
45881f2915669f734f34e3e83c83287e7371e298390Olivier MartinEFI_STATUS
45981f2915669f734f34e3e83c83287e7371e298390Olivier MartinArmFastbootPlatformOemCommand (
46081f2915669f734f34e3e83c83287e7371e298390Olivier Martin  IN  CHAR8   *Command
46181f2915669f734f34e3e83c83287e7371e298390Olivier Martin  )
46281f2915669f734f34e3e83c83287e7371e298390Olivier Martin{
46381f2915669f734f34e3e83c83287e7371e298390Olivier Martin  CHAR16 CommandUnicode[65];
46481f2915669f734f34e3e83c83287e7371e298390Olivier Martin
46581f2915669f734f34e3e83c83287e7371e298390Olivier Martin  AsciiStrToUnicodeStr (Command, CommandUnicode);
46681f2915669f734f34e3e83c83287e7371e298390Olivier Martin
46781f2915669f734f34e3e83c83287e7371e298390Olivier Martin  if (AsciiStrCmp (Command, "Demonstrate") == 0) {
46881f2915669f734f34e3e83c83287e7371e298390Olivier Martin    DEBUG ((EFI_D_ERROR, "ARM OEM Fastboot command 'Demonstrate' received.\n"));
46981f2915669f734f34e3e83c83287e7371e298390Olivier Martin    return EFI_SUCCESS;
47081f2915669f734f34e3e83c83287e7371e298390Olivier Martin  } else {
47181f2915669f734f34e3e83c83287e7371e298390Olivier Martin    DEBUG ((EFI_D_ERROR,
47281f2915669f734f34e3e83c83287e7371e298390Olivier Martin      "VExpress: Unrecognised Fastboot OEM command: %s\n",
47381f2915669f734f34e3e83c83287e7371e298390Olivier Martin      CommandUnicode
47481f2915669f734f34e3e83c83287e7371e298390Olivier Martin      ));
47581f2915669f734f34e3e83c83287e7371e298390Olivier Martin    return EFI_NOT_FOUND;
47681f2915669f734f34e3e83c83287e7371e298390Olivier Martin  }
47781f2915669f734f34e3e83c83287e7371e298390Olivier Martin}
47881f2915669f734f34e3e83c83287e7371e298390Olivier Martin
47981f2915669f734f34e3e83c83287e7371e298390Olivier MartinFASTBOOT_PLATFORM_PROTOCOL mPlatformProtocol = {
48081f2915669f734f34e3e83c83287e7371e298390Olivier Martin  ArmFastbootPlatformInit,
48181f2915669f734f34e3e83c83287e7371e298390Olivier Martin  ArmFastbootPlatformUnInit,
48281f2915669f734f34e3e83c83287e7371e298390Olivier Martin  ArmFastbootPlatformFlashPartition,
48381f2915669f734f34e3e83c83287e7371e298390Olivier Martin  ArmFastbootPlatformErasePartition,
48481f2915669f734f34e3e83c83287e7371e298390Olivier Martin  ArmFastbootPlatformGetVar,
48581f2915669f734f34e3e83c83287e7371e298390Olivier Martin  ArmFastbootPlatformOemCommand
48681f2915669f734f34e3e83c83287e7371e298390Olivier Martin};
48781f2915669f734f34e3e83c83287e7371e298390Olivier Martin
48881f2915669f734f34e3e83c83287e7371e298390Olivier MartinEFI_STATUS
48981f2915669f734f34e3e83c83287e7371e298390Olivier MartinEFIAPI
49081f2915669f734f34e3e83c83287e7371e298390Olivier MartinArmAndroidFastbootPlatformEntryPoint (
49181f2915669f734f34e3e83c83287e7371e298390Olivier Martin  IN EFI_HANDLE                            ImageHandle,
49281f2915669f734f34e3e83c83287e7371e298390Olivier Martin  IN EFI_SYSTEM_TABLE                      *SystemTable
49381f2915669f734f34e3e83c83287e7371e298390Olivier Martin  )
49481f2915669f734f34e3e83c83287e7371e298390Olivier Martin{
49581f2915669f734f34e3e83c83287e7371e298390Olivier Martin  return gBS->InstallProtocolInterface (
49681f2915669f734f34e3e83c83287e7371e298390Olivier Martin                &ImageHandle,
49781f2915669f734f34e3e83c83287e7371e298390Olivier Martin                &gAndroidFastbootPlatformProtocolGuid,
49881f2915669f734f34e3e83c83287e7371e298390Olivier Martin                EFI_NATIVE_INTERFACE,
49981f2915669f734f34e3e83c83287e7371e298390Olivier Martin                &mPlatformProtocol
50081f2915669f734f34e3e83c83287e7371e298390Olivier Martin                );
50181f2915669f734f34e3e83c83287e7371e298390Olivier Martin}
502