public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Carsey, Jaben" <jaben.carsey@intel.com>
To: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>,
	"edk2-devel@lists.01.org" <edk2-devel@lists.01.org>,
	"Shah, Tapan (tapandshah@hpe.com)" <tapandshah@hpe.com>,
	"Ni, Ruiyu" <ruiyu.ni@intel.com>
Cc: "Ni, Ruiyu" <ruiyu.ni@intel.com>,
	"Carsey, Jaben" <jaben.carsey@intel.com>
Subject: Re: [PATCH] ShellPkg: Added GPT Shell Application/Library
Date: Thu, 20 Oct 2016 20:48:50 +0000	[thread overview]
Message-ID: <CB6E33457884FA40993F35157061515C54AA2A6D@FMSMSX103.amr.corp.intel.com> (raw)
In-Reply-To: <1476927117-4521-1-git-send-email-vladimir.olovyannikov@broadcom.com>

Tapan & Ray,

Any thoughts on this?

Reviewed-by: Jaben Carsey <jaben.carsey@intel.com>

> -----Original Message-----
> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
> Vladimir Olovyannikov
> Sent: Wednesday, October 19, 2016 6:32 PM
> To: edk2-devel@lists.01.org
> Cc: Carsey, Jaben <jaben.carsey@intel.com>; Ni, Ruiyu
> <ruiyu.ni@intel.com>; Vladimir Olovyannikov
> <vladimir.olovyannikov@broadcom.com>
> Subject: [edk2] [PATCH] ShellPkg: Added GPT Shell Application/Library
> Importance: High
> 
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Vladimir Olovyannikov
> <vladimir.olovyannikov@broadcom.com>
> 
> This tool allows managing (create, delete, modify, fat format) of GPT
> partitions from within UEFI Shell. See usage examples in the .uni file
> 
> Hope that this tool can be useful for anybody wishing to manipulate GPT
> partitions from within the UEFI Shell.
> I am planning to create a shared library for GPT-related activities.
> But because of time shortage this could happen much later than planned.
> 
> This is the final version of the tool which we are going to use.
> If anybody wants to use this tool and create a separate library please
> by all means go ahead.
> ---
>  .../Library/UefiShellGptCommandLib/FatFormat.c     |  693 +++++++
>  .../Library/UefiShellGptCommandLib/FatFormat.h     |  115 ++
>  .../Library/UefiShellGptCommandLib/GptWorker.c     | 1922
> ++++++++++++++++++++
>  .../Library/UefiShellGptCommandLib/GptWorker.h     |  188 ++
>  .../UefiShellGptCommandLib.c                       | 1267 +++++++++++++
>  .../UefiShellGptCommandLib.inf                     |   74 +
>  .../UefiShellGptCommandLib.uni                     |  113 ++
>  ShellPkg/ShellPkg.dec                              |    1 +
>  ShellPkg/ShellPkg.dsc                              |    4 +
>  9 files changed, 4377 insertions(+)
>  create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
>  create mode 100644
> ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
>  create mode 100644
> ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
>  create mode 100644
> ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
>  create mode 100644
> ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
>  create mode 100644
> ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
>  create mode 100644
> ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
> 
> diff --git a/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> new file mode 100644
> index 000000000000..dea8505c49ff
> --- /dev/null
> +++ b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> @@ -0,0 +1,693 @@
> +/** @file
> +
> +  Copyright (c) 2003 - 2012, Rob Riglar, Ultra-Embedded.com. All rights
> reserved<BR>
> +  Copyright (c) 2016, Broadcom. All rights reserved<BR>
> +
> +  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.
> +
> +**/
> +
> +#include "FatFormat.h"
> +
> +//-----------------------------------------------------------------------------
> +// Tables
> +//-----------------------------------------------------------------------------
> +typedef struct
> +{
> +  UINT64  Sectors;
> +  UINT8   SectorsPerCluster;
> +} SectorsPerClusterTable;
> +
> +STATIC SectorsPerClusterTable ClusterSizeTable16[] =
> +{
> +  { 32680, 2 },     // 16MB - 1K
> +  { 262144, 4 },    // 128MB - 2K
> +  { 524288, 8 },    // 256MB - 4K
> +  { 1048576, 16 },  // 512MB - 8K
> +  { 2097152, 32 },  // 1GB - 16K
> +  { 4194304, 64 },  // 2GB - 32K
> +  { 8388608, 128 }, // 2GB - 64K [Warning only supported by Windows XP
> onwards]
> +  { 0, 0 }          // Invalid
> +};
> +
> +STATIC SectorsPerClusterTable ClusterSizeTable32[] =
> +{
> +  { 532480, 1 },      // 260MB - 512b
> +  { 16777216, 8 },    // 8GB - 4K
> +  { 33554432, 16 },   // 16GB - 8K
> +  { 67108864, 32 },   // 32GB - 16K
> +  { 0xFFFFFFFF, 64 }, // >32GB - 32K
> +  { 0, 0 }            // Invalid
> +};
> +
> +/**
> +  Calculates LBA corresponding to the cluster number.
> +
> +  @param  FS             Pointer to the FAT_FS structure
> +  @param  ClusterNumber  Cluster number to get LBA for
> +
> +  @return EFI_LBA        LBA corresponding to the given cluster number
> +**/
> +STATIC
> +EFI_LBA LbaOfCluster (
> +  IN FATFS              *Fs,
> +  IN UINT64             ClusterNumber
> +  )
> +{
> +  if (Fs->FatType == FAT_TYPE_16)
> +    return (Fs->ClusterBeginLba +
> +            (Fs->RootEntryCount * 32 / FAT_SECTOR_SIZE) +
> +            ((ClusterNumber - 2) * Fs->SectorsPerCluster));
> +  else
> +    return ((Fs->ClusterBeginLba +
> +             ((ClusterNumber - 2) * Fs->SectorsPerCluster)));
> +}
> +
> +/**
> +  Calculates the cluster size to be used.
> +
> +  @param  Sectors        Requested number of sectors
> +  @param  IsFat32        Whether FAT32 is to be used
> +
> +  @return UINT8          Cluster size from the table
> +
> +**/
> +STATIC
> +UINT8 CalcClusterSize (
> +  IN UINTN               Sectors,
> +  IN BOOLEAN             IsFat32)
> +{
> +  UINTN Index;
> +
> +  if (!IsFat32) {
> +    for (Index = 0; ClusterSizeTable16[Index].SectorsPerCluster != 0; Index++)
> +      if (Sectors <= ClusterSizeTable16[Index].Sectors)
> +        return ClusterSizeTable16[Index].SectorsPerCluster;
> +  } else {
> +    for (Index = 0; ClusterSizeTable32[Index].SectorsPerCluster != 0; Index++)
> +      if (Sectors <= ClusterSizeTable32[Index].Sectors)
> +        return ClusterSizeTable32[Index].SectorsPerCluster;
> +  }
> +
> +  return 0;
> +}
> +
> +/**
> +  Erase a number of sectors.
> +
> +  @param  FS             Pointer to the FAT_FS structure
> +  @param  LBA            LBA to erase sectors in
> +  @param  Count          Number of sectors to be erased
> +
> +  @return EFI_SUCCESS    Operation succeeded
> +  @return other          Failed to erase fat sectors
> +
> +**/
> +STATIC
> +EFI_STATUS
> +EraseSectors (
> +  IN FATFS           *Fs,
> +  IN EFI_LBA         Lba,
> +  IN UINTN           Count
> +  )
> +{
> +  UINTN Index;
> +  EFI_STATUS Status;
> +
> +  // Zero Sector first
> +  ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE);
> +
> +  for (Index = 0; Index < Count; Index++)
> +    Status = Fs->DiskIo->WriteDisk (
> +      Fs->DiskIo, Fs->BlockIo->Media->MediaId,
> +      MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) +
> +      MultU64x32 ((Lba + Index), FAT_SECTOR_SIZE),
> +      FAT_SECTOR_SIZE, Fs->CurrentSector.Sector);
> +
> +  return Status;
> +}
> +
> +/**
> +  Create the boot sector.
> +
> +  @param  Fs             Pointer to the FAT_FS structure
> +  @param  BootSectorLba  LBA of the boot sector
> +  @param  VolSectors     Number of sectors in the volume
> +  @param  Name           Volume label
> +  @param  IsFat32        Whether it is a FAT32 boot sector
> +
> +  @return EFI_SUCCESS    Boot sector was created successfully
> +  @return other          Failed to create the boot sector
> +
> +**/
> +STATIC
> +EFI_STATUS
> +CreateBootSector (
> +  IN FATFS             *Fs,
> +  IN EFI_LBA           BootSectorLba,
> +  IN UINT64            VolSectors,
> +  IN CONST CHAR8       *Name,
> +  IN BOOLEAN           IsFat32
> +  )
> +{
> +  UINTN TotalClusters;
> +  UINTN Index;
> +  EFI_STATUS Status;
> +
> +  // Zero Sector initially
> +  ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE);
> +
> +  // OEM Name & Jump Code
> +  Fs->CurrentSector.Sector[0] = 0xEB;
> +  Fs->CurrentSector.Sector[1] = 0x3C;
> +  Fs->CurrentSector.Sector[2] = 0x90;
> +  Fs->CurrentSector.Sector[3] = 0x4D;
> +  Fs->CurrentSector.Sector[4] = 0x53;
> +  Fs->CurrentSector.Sector[5] = 0x44;
> +  Fs->CurrentSector.Sector[6] = 0x4F;
> +  Fs->CurrentSector.Sector[7] = 0x53;
> +  Fs->CurrentSector.Sector[8] = 0x35;
> +  Fs->CurrentSector.Sector[9] = 0x2E;
> +  Fs->CurrentSector.Sector[10] = 0x30;
> +
> +  // Bytes per Sector
> +  Fs->CurrentSector.Sector[11] = (FAT_SECTOR_SIZE >> 0) & 0xFF;
> +  Fs->CurrentSector.Sector[12] = (FAT_SECTOR_SIZE >> 8) & 0xFF;
> +
> +  // Get sectors per cluster size for the disk
> +  Fs->SectorsPerCluster = CalcClusterSize (VolSectors, IsFat32);
> +  if (!Fs->SectorsPerCluster)
> +    return 0; // Invalid disk size
> +
> +  // Sectors per cluster
> +  Fs->CurrentSector.Sector[13] = Fs->SectorsPerCluster;
> +
> +  // Reserved Sectors
> +  if (!IsFat32)
> +    Fs->ReservedSectors = 8;
> +  else
> +    Fs->ReservedSectors = 32;
> +  Fs->CurrentSector.Sector[14] = (Fs->ReservedSectors >> 0) & 0xFF;
> +  Fs->CurrentSector.Sector[15] = (Fs->ReservedSectors >> 8) & 0xFF;
> +
> +  // Number of FATS
> +  Fs->NumOfFats = 2;
> +  Fs->CurrentSector.Sector[16] = Fs->NumOfFats;
> +
> +  // Max entries in root dir (FAT16 only)
> +  if (!IsFat32) {
> +    Fs->RootEntryCount = 512;
> +    Fs->CurrentSector.Sector[17] = (Fs->RootEntryCount >> 0) & 0xFF;
> +    Fs->CurrentSector.Sector[18] = (Fs->RootEntryCount >> 8) & 0xFF;
> +  } else {
> +    Fs->RootEntryCount = 0;
> +    Fs->CurrentSector.Sector[17] = 0;
> +    Fs->CurrentSector.Sector[18] = 0;
> +  }
> +
> +  // [FAT16] Total sectors (use FAT32 count instead)
> +  Fs->CurrentSector.Sector[19] = 0x00;
> +  Fs->CurrentSector.Sector[20] = 0x00;
> +
> +  // Media type
> +  Fs->CurrentSector.Sector[21] = 0xF8;
> +
> +
> +  // FAT16 BS Details
> +  if (!IsFat32) {
> +    // Count of sectors used by the FAT table (FAT16 only)
> +    TotalClusters = (VolSectors / Fs->SectorsPerCluster) + 1;
> +    Fs->FatSectors = (TotalClusters / (FAT_SECTOR_SIZE / 2)) + 1;
> +    Fs->CurrentSector.Sector[22] = (UINT8)((Fs->FatSectors >> 0) & 0xFF);
> +    Fs->CurrentSector.Sector[23] = (UINT8)((Fs->FatSectors >> 8) & 0xFF);
> +
> +    // Sectors per track
> +    Fs->CurrentSector.Sector[24] = 0x00;
> +    Fs->CurrentSector.Sector[25] = 0x00;
> +
> +    // Heads
> +    Fs->CurrentSector.Sector[26] = 0x00;
> +    Fs->CurrentSector.Sector[27] = 0x00;
> +
> +    // Hidden sectors
> +    Fs->CurrentSector.Sector[28] = 0x20;
> +    Fs->CurrentSector.Sector[29] = 0x00;
> +    Fs->CurrentSector.Sector[30] = 0x00;
> +    Fs->CurrentSector.Sector[31] = 0x00;
> +
> +    // Total sectors for this volume
> +    Fs->CurrentSector.Sector[32] = (UINT8)((VolSectors >> 0) & 0xFF);
> +    Fs->CurrentSector.Sector[33] = (UINT8)((VolSectors >> 8) & 0xFF);
> +    Fs->CurrentSector.Sector[34] = (UINT8)((VolSectors >> 16) & 0xFF);
> +    Fs->CurrentSector.Sector[35] = (UINT8)((VolSectors >> 24) & 0xFF);
> +
> +    // Drive number
> +    Fs->CurrentSector.Sector[36] = 0x00;
> +
> +    // Reserved
> +    Fs->CurrentSector.Sector[37] = 0x00;
> +
> +    // Boot signature
> +    Fs->CurrentSector.Sector[38] = 0x29;
> +
> +    // Volume ID
> +    Fs->CurrentSector.Sector[39] = 0x12;
> +    Fs->CurrentSector.Sector[40] = 0x34;
> +    Fs->CurrentSector.Sector[41] = 0x56;
> +    Fs->CurrentSector.Sector[42] = 0x78;
> +
> +    // Volume name
> +    for (Index = 0; Index < 11; Index++) {
> +      if (Index < AsciiStrLen (Name))
> +        Fs->CurrentSector.Sector[Index + 43] = Name[Index];
> +      else
> +        Fs->CurrentSector.Sector[Index + 43] = ' ';
> +    }
> +
> +    // File sys type
> +    Fs->CurrentSector.Sector[54] = 'F';
> +    Fs->CurrentSector.Sector[55] = 'A';
> +    Fs->CurrentSector.Sector[56] = 'T';
> +    Fs->CurrentSector.Sector[57] = '1';
> +    Fs->CurrentSector.Sector[58] = '6';
> +    Fs->CurrentSector.Sector[59] = ' ';
> +    Fs->CurrentSector.Sector[60] = ' ';
> +    Fs->CurrentSector.Sector[61] = ' ';
> +
> +    // Signature
> +    Fs->CurrentSector.Sector[510] = 0x55;
> +    Fs->CurrentSector.Sector[511] = 0xAA;
> +  }
> +  // FAT32 BS Details
> +  else {
> +    // Count of sectors used by the FAT table (FAT16 only)
> +    Fs->CurrentSector.Sector[22] = 0;
> +    Fs->CurrentSector.Sector[23] = 0;
> +
> +    // Sectors per track (default)
> +    Fs->CurrentSector.Sector[24] = 0x3F;
> +    Fs->CurrentSector.Sector[25] = 0x00;
> +
> +    // Heads (default)
> +    Fs->CurrentSector.Sector[26] = 0xFF;
> +    Fs->CurrentSector.Sector[27] = 0x00;
> +
> +    // Hidden sectors
> +    Fs->CurrentSector.Sector[28] = 0x00;
> +    Fs->CurrentSector.Sector[29] = 0x00;
> +    Fs->CurrentSector.Sector[30] = 0x00;
> +    Fs->CurrentSector.Sector[31] = 0x00;
> +
> +    // Total sectors for this volume
> +    Fs->CurrentSector.Sector[32] = (UINT8)((VolSectors >> 0) & 0xFF);
> +    Fs->CurrentSector.Sector[33] = (UINT8)((VolSectors >> 8) & 0xFF);
> +    Fs->CurrentSector.Sector[34] = (UINT8)((VolSectors >> 16) & 0xFF);
> +    Fs->CurrentSector.Sector[35] = (UINT8)((VolSectors >> 24) & 0xFF);
> +
> +    TotalClusters = (VolSectors / Fs->SectorsPerCluster) + 1;
> +    Fs->FatSectors = (TotalClusters / (FAT_SECTOR_SIZE / 4)) + 1;
> +
> +    // BPB_FATSz32
> +    Fs->CurrentSector.Sector[36] = (UINT8)((Fs->FatSectors >> 0) & 0xFF);
> +    Fs->CurrentSector.Sector[37] = (UINT8)((Fs->FatSectors >> 8) & 0xFF);
> +    Fs->CurrentSector.Sector[38] = (UINT8)((Fs->FatSectors >> 16) & 0xFF);
> +    Fs->CurrentSector.Sector[39] = (UINT8)((Fs->FatSectors >> 24) & 0xFF);
> +
> +    // BPB_ExtFlags
> +    Fs->CurrentSector.Sector[40] = 0;
> +    Fs->CurrentSector.Sector[41] = 0;
> +
> +    // BPB_FSVer
> +    Fs->CurrentSector.Sector[42] = 0;
> +    Fs->CurrentSector.Sector[43] = 0;
> +
> +    // BPB_RootClus
> +    Fs->CurrentSector.Sector[44] = (UINT8)((Fs->RootdirFirstCluster >> 0) &
> 0xFF);
> +    Fs->CurrentSector.Sector[45] = (UINT8)((Fs->RootdirFirstCluster >> 8) &
> 0xFF);
> +    Fs->CurrentSector.Sector[46] = (UINT8)((Fs->RootdirFirstCluster >> 16) &
> 0xFF);
> +    Fs->CurrentSector.Sector[47] = (UINT8)((Fs->RootdirFirstCluster >> 24) &
> 0xFF);
> +
> +    // BPB_FSInfo
> +    Fs->CurrentSector.Sector[48] = (UINT8)((Fs->FsInfoSector >> 0) & 0xFF);
> +    Fs->CurrentSector.Sector[49] = (UINT8)((Fs->FsInfoSector >> 8) & 0xFF);
> +
> +    // BPB_BkBootSec
> +    Fs->CurrentSector.Sector[50] = 6;
> +    Fs->CurrentSector.Sector[51] = 0;
> +
> +    // Drive number
> +    Fs->CurrentSector.Sector[64] = 0x00;
> +
> +    // Boot signature
> +    Fs->CurrentSector.Sector[66] = 0x29;
> +
> +    // Volume ID
> +    Fs->CurrentSector.Sector[67] = 0x12;
> +    Fs->CurrentSector.Sector[68] = 0x34;
> +    Fs->CurrentSector.Sector[69] = 0x56;
> +    Fs->CurrentSector.Sector[70] = 0x78;
> +
> +    // Volume name
> +    for (Index = 0; Index < 11; Index++) {
> +      if (Index < (int)AsciiStrLen (Name))
> +        Fs->CurrentSector.Sector[Index + 71] = Name[Index];
> +      else
> +        Fs->CurrentSector.Sector[Index + 71] = ' ';
> +    }
> +
> +    // File sys type
> +    Fs->CurrentSector.Sector[82] = 'F';
> +    Fs->CurrentSector.Sector[83] = 'A';
> +    Fs->CurrentSector.Sector[84] = 'T';
> +    Fs->CurrentSector.Sector[85] = '3';
> +    Fs->CurrentSector.Sector[86] = '2';
> +    Fs->CurrentSector.Sector[87] = ' ';
> +    Fs->CurrentSector.Sector[88] = ' ';
> +    Fs->CurrentSector.Sector[89] = ' ';
> +
> +    // Signature
> +    Fs->CurrentSector.Sector[510] = 0x55;
> +    Fs->CurrentSector.Sector[511] = 0xAA;
> +  }
> +
> +  Status = Fs->DiskIo->WriteDisk (
> +    Fs->DiskIo, Fs->BlockIo->Media->MediaId,
> +    MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) +
> +    MultU64x32 (Fs->FatBeginLba, FAT_SECTOR_SIZE),
> +    FAT_SECTOR_SIZE,
> +    Fs->CurrentSector.Sector);
> +
> +  return Status;
> +}
> +/**
> +  Create the FSinfo sector for FAT32
> +
> +  @param  Fs             Pointer to the FAT_FS structure
> +  @param  SectorLba      LBA of the FSInfo sector
> +
> +  @return EFI_SUCCESS    FAT32 FSInfo sector successfully created
> +  @return other          Failed to create the FAT32 FSInfo sector
> +
> +**/
> +STATIC
> +EFI_STATUS
> +CreateFsinfoSector (
> +  IN FATFS               *Fs,
> +  IN EFI_LBA             SectorLba
> +  )
> +{
> +  EFI_STATUS Status;
> +
> +  // Zero Sector initially
> +  ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE);
> +
> +  // FSI_LeadSig
> +  Fs->CurrentSector.Sector[0] = 0x52;
> +  Fs->CurrentSector.Sector[1] = 0x52;
> +  Fs->CurrentSector.Sector[2] = 0x61;
> +  Fs->CurrentSector.Sector[3] = 0x41;
> +
> +  // FSI_StrucSig
> +  Fs->CurrentSector.Sector[484] = 0x72;
> +  Fs->CurrentSector.Sector[485] = 0x72;
> +  Fs->CurrentSector.Sector[486] = 0x41;
> +  Fs->CurrentSector.Sector[487] = 0x61;
> +
> +  // FSI_Free_Count
> +  Fs->CurrentSector.Sector[488] = 0xFF;
> +  Fs->CurrentSector.Sector[489] = 0xFF;
> +  Fs->CurrentSector.Sector[490] = 0xFF;
> +  Fs->CurrentSector.Sector[491] = 0xFF;
> +
> +  // FSI_Nxt_Free
> +  Fs->CurrentSector.Sector[492] = 0xFF;
> +  Fs->CurrentSector.Sector[493] = 0xFF;
> +  Fs->CurrentSector.Sector[494] = 0xFF;
> +  Fs->CurrentSector.Sector[495] = 0xFF;
> +
> +  // Signature
> +  Fs->CurrentSector.Sector[510] = 0x55;
> +  Fs->CurrentSector.Sector[511] = 0xAA;
> +
> +  Status = Fs->DiskIo->WriteDisk (
> +    Fs->DiskIo, Fs->BlockIo->Media->MediaId,
> +    MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) +
> +    MultU64x32 (SectorLba,  FAT_SECTOR_SIZE),
> +    FAT_SECTOR_SIZE,
> +    Fs->CurrentSector.Sector);
> +
> +  return Status;
> +}
> +
> +/**
> +  Erase FAT table
> +
> +  @param  Fs            Pointer to the FAT_FS structure
> +  @param  IsFat32       Whether FAT32 is to be used
> +
> +  @return EFI_SUCCESS   Successfully erased FAT
> +  @return other         Failed to erase FAT
> +
> +**/
> +STATIC
> +EFI_STATUS
> +EraseFat (
> +  IN FATFS            *Fs,
> +  IN BOOLEAN          IsFat32)
> +{
> +  UINTN Index;
> +  EFI_STATUS Status;
> +
> +  // Zero Sector initially
> +  ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE);
> +
> +  // Initialise default allocate / reserved clusters
> +  if (!IsFat32) {
> +    SET_16BIT_WORD (Fs->CurrentSector.Sector, 0, 0xFFF8);
> +    SET_16BIT_WORD (Fs->CurrentSector.Sector, 2, 0xFFFF);
> +  } else {
> +    SET_32BIT_WORD (Fs->CurrentSector.Sector, 0, 0x0FFFFFF8);
> +    SET_32BIT_WORD (Fs->CurrentSector.Sector, 4, 0xFFFFFFFF);
> +    SET_32BIT_WORD (Fs->CurrentSector.Sector, 8, 0x0FFFFFFF);
> +  }
> +
> +  Status = Fs->DiskIo->WriteDisk (
> +    Fs->DiskIo, Fs->BlockIo->Media->MediaId,
> +    MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) +
> +    MultU64x32 (Fs->FatBeginLba, FAT_SECTOR_SIZE),
> +    FAT_SECTOR_SIZE,
> +    Fs->CurrentSector.Sector);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  // Zero remaining FAT sectors
> +  ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE);
> +  for (Index = 1; Index < Fs->FatSectors * Fs->NumOfFats; Index++) {
> +    Status = Fs->DiskIo->WriteDisk (
> +      Fs->DiskIo,
> +      Fs->BlockIo->Media->MediaId,
> +      MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) +
> +      MultU64x32 ((Fs->FatBeginLba + Index), FAT_SECTOR_SIZE),
> +      FAT_SECTOR_SIZE,
> +      Fs->CurrentSector.Sector);
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +  }
> +  return Status;
> +}
> +
> +/**
> +  Format a FAT16 partition
> +
> +  @param  Fs              Pointer to FAT_FS structure
> +  @param  VolumeSectors   Number of sectors in the volume
> +  @param  Name            Volume label
> +
> +  @return EFI_SUCCESS    FAT16 partition was formatted successfully
> +  @return other          Failed to format FAT16 partition
> +
> +**/
> +STATIC
> +EFI_STATUS
> +FormatFat16 (
> +  IN FATFS                 *Fs,
> +  IN UINT64                VolumeSectors,
> +  IN CONST CHAR8           *Name
> +  )
> +{
> +  EFI_STATUS Status;
> +
> +  Fs->CurrentSector.Address = FAT32_INVALID_CLUSTER;
> +  Fs->CurrentSector.Dirty = 0;
> +
> +  Fs->NextFreeCluster = 0; // Invalid
> +
> +  // Volume is FAT16
> +  Fs->FatType = FAT_TYPE_16;
> +
> +  // Not valid for FAT16
> +  Fs->FsInfoSector = 0;
> +  Fs->RootdirFirstCluster = 0;
> +
> +  Fs->LbaBegin = 0;
> +  Status = CreateBootSector (Fs, Fs->LbaBegin, VolumeSectors, Name, 0);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  // For FAT16 (which this may be), RootdirFirstCluster is actuall
> RootdirFirstSector
> +  Fs->RootdirFirstSector = Fs->ReservedSectors + (Fs->NumOfFats * Fs-
> >FatSectors);
> +  Fs->RootdirSectors = ((Fs->RootEntryCount * 32) +
> +                        (FAT_SECTOR_SIZE - 1)) / FAT_SECTOR_SIZE;
> +
> +  // First FAT LBA Address
> +  Fs->FatBeginLba = Fs->LbaBegin + Fs->ReservedSectors;
> +
> +  // The Address of the first data cluster on this volume
> +  Fs->ClusterBeginLba = Fs->FatBeginLba +
> +    (Fs->NumOfFats * Fs->FatSectors);
> +
> +  // Initialise FAT sectors
> +  Status = EraseFat (Fs, 0);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  // Erase Root directory
> +  Status = EraseSectors (
> +    Fs,
> +    Fs->LbaBegin + Fs->RootdirFirstSector,
> +    Fs->RootdirSectors);
> +
> +  return Status;
> +}
> +
> +/**
> +  Format a FAT32 partition
> +
> +  @param  Fs              Pointer to FAT_FS structure
> +  @param  VolumeSectors   Number of sectors in the volume
> +  @param  Name            Volume label
> +
> +  @return EFI_SUCCESS    FAT32 partition was formatted successfully
> +  @return other          Failed to format FAT32 partition
> +
> +**/
> +STATIC
> +EFI_STATUS
> +FormatFat32 (
> +  IN            FATFS *Fs,
> +  IN UINTN      VolumeSectors,
> +  IN CONST      CHAR8 *Name
> +  )
> +{
> +  EFI_STATUS Status;
> +
> +  Fs->CurrentSector.Address = FAT32_INVALID_CLUSTER;
> +  Fs->CurrentSector.Dirty = 0;
> +
> +  Fs->NextFreeCluster = 0; // Invalid
> +
> +  // Volume is FAT32
> +  Fs->FatType = FAT_TYPE_32;
> +
> +  // Basic defaults for normal FAT32 partitions
> +  Fs->FsInfoSector = 1;
> +  Fs->RootdirFirstCluster = 2;
> +
> +  // Sector 0: Boot Sector
> +  // NOTE: We don't need an MBR, it is a waste of a good Sector!
> +  Fs->LbaBegin = 0;
> +  Status = CreateBootSector (Fs, Fs->LbaBegin, VolumeSectors, Name, 1);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  // First FAT LBA address
> +  Fs->FatBeginLba = Fs->LbaBegin + Fs->ReservedSectors;
> +
> +  // The address of the first data cluster on this volume
> +  Fs->ClusterBeginLba = Fs->FatBeginLba + (Fs->NumOfFats * Fs-
> >FatSectors);
> +
> +  // Initialise FSInfo sector
> +  Status = CreateFsinfoSector (Fs, Fs->FsInfoSector);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  // Initialise FAT sectors
> +  Status = EraseFat (Fs, 1);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  // Erase Root directory
> +  Status = EraseSectors (
> +    Fs,
> +    LbaOfCluster (Fs, Fs->RootdirFirstCluster),
> +    Fs->SectorsPerCluster);
> +
> +  return Status;
> +}
> +
> +/**
> +  Format a partition either to FAT16, or FAT32
> +
> +  @param  StartingLBA     Starting LBA of the partition
> +  @param  EndingLBA       Ending LBA of the partition
> +  @param  BlockIo         Pointer to the BlockIo protocol
> +  @param  DiskIo          Pointer to the DiskIo protocol
> +  @param  ForceFat32      Force FAT32 format (even if device can be
> formatted as FAT16)
> +
> +  @return EFI_SUCCESS    Format succeeded
> +  @return other          Format failed
> +
> +**/
> +EFI_STATUS
> +FatFormat (
> +  IN EFI_LBA                 StartingLBA,
> +  IN EFI_LBA                 EndingLBA,
> +  IN EFI_BLOCK_IO_PROTOCOL   *BlockIo,
> +  IN EFI_DISK_IO_PROTOCOL    *DiskIo,
> +  IN CHAR8                   *VolumeName,
> +  IN BOOLEAN                 ForceFat32
> +  )
> +{
> +  FATFS       Fs;
> +  UINT64      VolumeSectors;
> +
> +  if ((StartingLBA > EndingLBA) ||
> +      (BlockIo == NULL) || (DiskIo == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  VolumeSectors = DivU64x32 (
> +    MultU64x32 (
> +      EndingLBA - StartingLBA + 1, BlockIo->Media->BlockSize),
> +    FAT_SECTOR_SIZE);
> +
> +  if (VolumeName == NULL) {
> +    VolumeName = DEFAULT_FAT_LABEL_NAME;
> +  }
> +
> +  ZeroMem (&Fs, sizeof (Fs));
> +
> +  Fs.StartingLBA = StartingLBA;
> +  Fs.EndingLBA = EndingLBA;
> +  Fs.BlockIo = BlockIo;
> +  Fs.DiskIo = DiskIo;
> +  // 2GB - 32K limit for safe behaviour for FAT16
> +  if ((VolumeSectors <= FAT16_MAX_SECTORS) && (!ForceFat32)) {
> +    return FormatFat16 (&Fs, VolumeSectors, VolumeName);
> +  } else {
> +    return FormatFat32 (&Fs, VolumeSectors, VolumeName);
> +  }
> +}
> diff --git a/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> new file mode 100644
> index 000000000000..213ab4df8ebc
> --- /dev/null
> +++ b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> @@ -0,0 +1,115 @@
> +/** @file
> +
> +  Copyright (c) 2003 - 2012, Rob Riglar, Ultra-Embedded.com. All rights
> reserved<BR>
> +  Copyright (c) 2016, Broadcom. All rights reserved<BR>
> +
> +  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 __FAT_FORMAT_H__
> +#define __FAT_FORMAT_H__
> +
> +#include "GptWorker.h"
> +
> +#define FAT_SECTOR_SIZE                     512
> +#define FAT_BUFFER_SECTORS                    1
> +#define FAT16_MAX_SECTORS               4194304
> +#define FAT32_LAST_CLUSTER              0xFFFFFFFF
> +#define FAT32_INVALID_CLUSTER           0xFFFFFFFF
> +#define FAT_DIR_ENTRY_SIZE              32
> +#define FAT_BUFFERS                     1
> +#define DEFAULT_FAT_LABEL_NAME          "EFIVOL"
> +#define FAT_LABEL_LENGTH                11
> +
> +#define FAT32_FORMAT                    L"FAT32"
> +#define FAT16_FORMAT                    L"FAT16"
> +
> +#define GET_32BIT_WORD(Buffer, Location)          (
> ((UINT32)Buffer[Location + 3] << 24) + \
> +                                                  ((UINT32)Buffer[Location + 2] <<16 ) + \
> +                                                  ((UINT32)Buffer[Location + 1] << 8) + \
> +                                                  (UINT32)Buffer[Location+0] )
> +
> +#define GET_16BIT_WORD(Buffer, Location)          (
> ((UINT16)Buffer[Location + 1] << 8) + \
> +                                                  (UINT16)Buffer[Location+0])
> +
> +#define SET_32BIT_WORD(Buffer, Location, Value)   { Buffer[Location + 0] =
> (UINT8)((Value) & 0xFF); \
> +                                                  Buffer[Location + 1] = (UINT8)((Value >> 8) &
> 0xFF); \
> +                                                  Buffer[Location + 2] = (UINT8)((Value >> 16) &
> 0xFF); \
> +                                                  Buffer[Location + 3] = (UINT8)((Value >> 24) &
> 0xFF); }
> +
> +#define SET_16BIT_WORD(Buffer, Location, Value)   { Buffer[Location + 0] =
> (UINT8)((Value) & 0xFF); \
> +                                                  Buffer[Location + 1] = (UINT8)((Value >> 8) &
> 0xFF); }
> +
> +typedef enum eFatType
> +{
> +  FAT_TYPE_16,
> +  FAT_TYPE_32
> +} FAT_FS_TYPE;
> +
> +
> +// Forward declaration
> +typedef struct _FAT_BUFFER FAT_BUFFER;
> +
> +struct _FAT_BUFFER {
> +  UINT8                   Sector[FAT_SECTOR_SIZE * FAT_BUFFER_SECTORS];
> +  UINTN                   Address;
> +  BOOLEAN                 Dirty;
> +  UINT8 *Ptr;
> +
> +  // Next in chain of sector buffers
> +  struct FAT_BUFFER       *NextBuf;
> +};
> +
> +typedef struct
> +{
> +  // Filesystem globals
> +  UINT8                   SectorsPerCluster;
> +  EFI_LBA                 ClusterBeginLba;
> +  UINTN                   RootdirFirstCluster;
> +  UINTN                   RootdirFirstSector;
> +  UINTN                   RootdirSectors;
> +  EFI_LBA                 FatBeginLba;
> +  UINT16                  FsInfoSector;
> +  EFI_LBA                 LbaBegin;
> +  UINTN                   FatSectors;
> +  UINTN                   NextFreeCluster;
> +  UINT16                  RootEntryCount;
> +  UINT16                  ReservedSectors;
> +  UINT8                   NumOfFats;
> +  FAT_FS_TYPE             FatType;
> +
> +  // Working buffer
> +  FAT_BUFFER              CurrentSector;
> +  // FAT Buffer
> +  FAT_BUFFER              *FatBufferHead;
> +  FAT_BUFFER              FatBuffers[FAT_BUFFERS];
> +  EFI_LBA                 StartingLBA;
> +  EFI_LBA                 EndingLBA;
> +  EFI_BLOCK_IO_PROTOCOL   *BlockIo;
> +  EFI_DISK_IO_PROTOCOL    *DiskIo;
> +
> +} FATFS;
> +
> +
> +
> +//-----------------------------------------------------------------------------
> +// Prototypes
> +//-----------------------------------------------------------------------------
> +EFI_STATUS
> +FatFormat (
> +  IN EFI_LBA                   StartingLBA,
> +  IN EFI_LBA                   EndingLBA,
> +  IN EFI_BLOCK_IO_PROTOCOL     *BlockIo,
> +  IN EFI_DISK_IO_PROTOCOL      *DiskIo,
> +  IN CHAR8                     *VolumeName,
> +  IN BOOLEAN                   ForceFat32
> +  );
> +
> +#endif
> diff --git a/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> new file mode 100644
> index 000000000000..31581b3d6172
> --- /dev/null
> +++ b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> @@ -0,0 +1,1922 @@
> +/** @file
> +Copyright (c) 1999 - 2013, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2016, Broadcom. All rights reserved.<BR>
> +
> +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.
> +
> +**/
> +
> +#include "GptWorker.h"
> +
> +#define GPT_DEBUG_LEVEL 0
> +
> +STATIC EFI_PARTITION_TABLE_HEADER   *PrimaryHeader    = NULL;
> +STATIC EFI_PARTITION_TABLE_HEADER   *BackupHeader     = NULL;
> +STATIC EFI_PARTITION_ENTRY          *PartEntry        = NULL;
> +STATIC EFI_PARTITION_ENTRY_STATUS   *PEntryStatus     = NULL;
> +
> +STATIC EFI_BLOCK_IO_PROTOCOL        *BlockIo;
> +STATIC EFI_DISK_IO_PROTOCOL         *DiskIo;
> +
> +STATIC BOOLEAN                      MbrValid;
> +STATIC BOOLEAN                      GptValid;
> +
> +STATIC EFI_KNOWN_PARTITION_TYPE PartitionTypes[] =
> +{
> +  // Known Partition type GUIDs
> +  // Expand this table as needed.
> +  // Starting with EFI System partition
> +  { { 0xC12A7328L, 0xF81F, 0x11D2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E,
> 0xC9, 0x3B } }, L"EFI System" },
> +  // Known Windows partition types
> +  { { 0xE3C9E316L, 0x0B5C, 0x4DB8, { 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02,
> 0x15, 0xAE } }, L"MS Windows Reserved (MSR)" },
> +  { { 0xEBD0A0A2L, 0xB9E5, 0x4433, { 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26,
> 0x99, 0xC7 } }, L"MS Windows Basic Data" },
> +  { { 0x5808C8AAL, 0x7E8F, 0x42E0, { 0x85, 0xD2, 0xE1, 0xE9, 0x04, 0x34, 0xCF,
> 0xB3 } }, L"MS Windows LDM Metadata" },
> +  { { 0xAF9B60A0L, 0x1431, 0x4F62, { 0xBC, 0x68, 0x33, 0x11, 0x71, 0x4A, 0x69,
> 0xAD } }, L"MS Windows LDM Data" },
> +  { { 0xDE94BBA4L, 0x06D1, 0x4D40, { 0xA1, 0x6A, 0xBF, 0xD5, 0x01, 0x79,
> 0xD6, 0xAC } }, L"MS Windows Recovery Environment" },
> +  { { 0xE75CAF8FL, 0xF680, 0x4CEE, { 0xAF, 0xA3, 0xB0, 0x01, 0xE5, 0x6E,
> 0xFC, 0x2D } }, L"MS Windows Storage Spaces" },
> +  // Known Linux partition types
> +  { { 0x0FC63DAFL, 0x8483, 0x4772, { 0x8E, 0x79, 0x3D, 0x69, 0xD8, 0x47,
> 0x7D, 0xE4 } }, L"Linux Filesystem Data" },
> +  { { 0xA19D880FL, 0x05FC, 0x4D3B, { 0xA0, 0x06, 0x74, 0x3F, 0x0F, 0x84,
> 0x91, 0x1E } }, L"Linux RAID" },
> +  { { 0x44479540L, 0xF297, 0x41B2, { 0x9A, 0xF7, 0xD1, 0x31, 0xD5, 0xF0, 0x45,
> 0x8A } }, L"Linux Root (x86)" },
> +  { { 0x4F68BCE3L, 0xE8CD, 0x4DB1, { 0x96, 0xE7, 0xFB, 0xCA, 0xF9, 0x84,
> 0xB7, 0x09 } }, L"Linux Root (x86-64)" },
> +  { { 0x69DAD710L, 0x2CE4, 0x4E3C, { 0xB1, 0x6C, 0x21, 0xA1, 0xD4, 0x9A,
> 0xBe, 0xD3 } }, L"Linux Root (ARM 32-bit)" },
> +  { { 0xB921B045L, 0x1DF0, 0x41C3, { 0xAF, 0x44, 0x4C, 0x6F, 0x28, 0x0D,
> 0x3F, 0xAE } }, L"Linux Root (ARM 64-bit/AARCH64)" },
> +  { { 0x0657FD6DL, 0xA4AB, 0x43C4, { 0x84, 0xE5, 0x09, 0x33, 0xC8, 0x4B,
> 0x4F, 0x4F } }, L"Linux Swap" },
> +  { { 0xE6D6D379L, 0xF507, 0x44C2, { 0xA2, 0x3C, 0x23, 0x8F, 0x2A, 0x3D,
> 0xF9, 0x28 } }, L"Linux Logical Volume Manager (LVM)" },
> +  { { 0x933AC7E1L, 0x2EB4, 0x4F13, { 0xB8, 0x44, 0x0E, 0x14, 0xE2, 0xAE, 0xF9,
> 0x15 } }, L"Linux /home" },
> +  { { 0x3B8F8425L, 0x20E0, 0x4F3B, { 0x90, 0x7F, 0x1A, 0x25, 0xA7, 0x6F, 0x98,
> 0xE8 } }, L"Linux /srv (server data)" },
> +  { { 0x7FFEC5C9L, 0x2D00, 0x49B7, { 0x89, 0x41, 0x3E, 0xA1, 0x0A, 0x55, 0x86,
> 0xB7 } }, L"Linux Plain dm-crypt" },
> +  { { 0xCA7D7CCBL, 0x63ED, 0x4C53, { 0x86, 0x1C, 0x17, 0x42, 0x53, 0x60,
> 0x59, 0xCC } }, L"Linux LUKS" },
> +  { { 0x8DA63339L, 0x0007, 0x60C0, { 0xC4, 0x36, 0x08, 0x3A, 0xC8, 0x23, 0x09,
> 0x08 } }, L"Linux Reserved" },
> +};
> +
> +MASTER_BOOT_RECORD ProtectiveMbrTemplate = {
> +  { 0 },                                                  // BoostStrapCode [440]
> +  { 0 },                                                  // UniqueMbrSignature[4] (unused)
> +  { 0 },                                                  // Unknown[2]
> +
> +  // PARTITIONS
> +  {
> +    // MBR_PARTITION_RECORD
> +    {
> +      0,                                                // BootIndicator
> +      0,                                                // StartHead
> +      0x1,                                              // StartSector
> +      0x1,                                              // StartTrack
> +      PMBR_GPT_PARTITION,                               // OSIndicator
> +      0xff,                                             // EndHead
> +      0xff,                                             // EndSector
> +      0xff,                                             // EndTrack
> +      { 0x1, 0x0, 0x0, 0x0 },                           // StartingLba[4]
> +      { 0xff, 0xff, 0xff, 0xff },                       // SizeInLba[4]
> +    },
> +    { 0 }, { 0 }, { 0 },                                // Unused partitions
> +  },
> +
> +  MBR_SIGNATURE                                         // Signature
> +};
> +
> +STATIC UINT32 CurRand = 1;
> +
> +/**
> +  Get random seed based on the RTC
> +
> +**/
> +
> +STATIC
> +VOID
> +Srand (VOID)
> +{
> +  EFI_TIME                  Time;
> +  UINT32                    Seed;
> +  UINT64                    MonotonicCount;
> +
> +  gRT->GetTime (&Time, NULL);
> +  Seed = (~Time.Hour << 24 | Time.Day << 16 | Time.Minute << 8 |
> Time.Second);
> +  Seed ^= Time.Nanosecond;
> +  Seed ^= Time.Year << 7;
> +
> +  gBS->GetNextMonotonicCount (&MonotonicCount);
> +  Seed += (UINT32)MonotonicCount;
> +
> +  /* Store this seed */
> +  CurRand = (UINT32)Seed;
> +}
> +
> +/**
> +  Get a pseudo-random number
> +
> +  @retval A pseudo-random number in the range 0 - 0x7fff
> +**/
> +
> +STATIC UINTN Rand (
> +  VOID
> +  )
> +{
> +  /* return a pseudo-random in range 0 - 0x7fff */
> +  return ((CurRand = CurRand * 214013L + 2531011L) >> 16) & 0x7fff;
> +}
> +
> +/**
> +  Generate a GUID
> +
> +  @param[in]  Guid  A pointer to a GUID receiving a generated value
> +**/
> +
> +STATIC VOID
> +GenerateGuid (
> +  OUT GUID *Guid
> +  )
> +{
> +  UINTN     Index;
> +  UINT16    Buffer[sizeof (GUID)];
> +
> +  /* Generates 128 random bits for new UUID */
> +  for (Index = 0; Index < sizeof (GUID); Index++) {
> +    UINTN V;
> +
> +    V = Rand () >> 7;
> +    Buffer[Index] = (UINT16)V;
> +  }
> +  /* set variant 10x and version 4 as required by RFC 4122 */
> +  Buffer[8] = 0x80 | (Buffer[8] & 0x3f);
> +  Buffer[6] = 0x40 | (Buffer[6] & 0xf);
> +  CopyGuid (Guid, (CONST GUID *)Buffer);
> +}
> +
> +/**
> +  Clean up globals
> +**/
> +VOID
> +GptCleanupGlobals (
> +  VOID
> +  )
> +{
> +  SHELL_FREE_NON_NULL (PrimaryHeader);
> +  SHELL_FREE_NON_NULL (BackupHeader);
> +  SHELL_FREE_NON_NULL (PartEntry);
> +  SHELL_FREE_NON_NULL (PEntryStatus);
> +  GptValid = FALSE;
> +  MbrValid = FALSE;
> +}
> +
> +/**
> +  Caution: This function may receive untrusted input.
> +  The GPT partition table header is external input, so this routine
> +  will do basic validation for GPT partition table header before return.
> +
> +  @param[in]  Lba         The starting Lba of the Partition Table
> +  @param[out] PartHeader  Stores the partition table that is read
> +
> +  @retval EFI_SUCCESS     The partition table is valid
> +  @retval ERROR           The partition table is not valid
> +
> +**/
> +STATIC
> +EFI_STATUS
> +PartitionValidGptTable (
> +  IN  EFI_LBA                     Lba,
> +  OUT EFI_PARTITION_TABLE_HEADER  *PartHeader
> +  );
> +
> +/**
> +  Check if the CRC field in the Partition table header is valid
> +  for Partition entry array.
> +
> +  @param[in]  PartHeader  Partition table header structure
> +
> +  @retval TRUE      the CRC is valid
> +  @retval FALSE     the CRC is invalid
> +
> +**/
> +STATIC
> +BOOLEAN
> +PartitionCheckGptEntryArrayCRC (
> +  IN  EFI_PARTITION_TABLE_HEADER  *PartHeader
> +  );
> +
> +
> +/**
> +  Restore Partition Table to its alternate place
> +  (Primary -> Backup or Backup -> Primary).
> +
> +  @param[in]  PartHeader  Partition table header structure.
> +
> +  @retval TRUE      Restoring succeeds
> +  @retval FALSE     Restoring failed
> +
> +**/
> +STATIC
> +BOOLEAN
> +PartitionRestoreGptTable (
> +  IN  EFI_PARTITION_TABLE_HEADER  *PartHeader
> +  );
> +
> +
> +/**
> +  This routine will check GPT partition entry and return entry status.
> +
> +  Caution: This function may receive untrusted input.
> +  The GPT partition entry is external input, so this routine
> +  will do basic validation for GPT partition entry and report status.
> +
> +  @param[in]    PartHeader    Partition table header structure
> +  @param[in]    PartEntry     The partition entry array
> +  @param[out]   PEntryStatus  the partition entry status array
> +                              recording the status of each partition
> +
> +**/
> +STATIC
> +VOID
> +PartitionCheckGptEntry (
> +  IN  EFI_PARTITION_TABLE_HEADER  *PartHeader,
> +  IN  EFI_PARTITION_ENTRY         *PartEntry,
> +  OUT EFI_PARTITION_ENTRY_STATUS  *PEntryStatus
> +  );
> +
> +
> +/**
> +  Checks the CRC32 value in the table header.
> +
> +  @param  MaxSize   Max Size limit
> +  @param  Size      The size of the table
> +  @param  Hdr       Table to check
> +
> +  @return TRUE    CRC Valid
> +  @return FALSE   CRC Invalid
> +
> +**/
> +STATIC
> +BOOLEAN
> +PartitionCheckCrcAltSize (
> +  IN UINTN                 MaxSize,
> +  IN UINTN                 Size,
> +  IN OUT EFI_TABLE_HEADER  *Hdr
> +  );
> +
> +
> +/**
> +  Checks the CRC32 value in the table header.
> +
> +  @param  MaxSize   Max Size limit
> +  @param  Hdr       Table to check
> +
> +  @return TRUE      CRC Valid
> +  @return FALSE     CRC Invalid
> +
> +**/
> +STATIC
> +BOOLEAN
> +PartitionCheckCrc (
> +  IN UINTN                 MaxSize,
> +  IN OUT EFI_TABLE_HEADER  *Hdr
> +  );
> +
> +
> +/**
> +  Updates the CRC32 value in the table header.
> +
> +  @param  Size   The size of the table
> +  @param  Hdr    Table to update
> +
> +**/
> +STATIC
> +VOID
> +PartitionSetCrcAltSize (
> +  IN UINTN                 Size,
> +  IN OUT EFI_TABLE_HEADER  *Hdr
> +  );
> +
> +
> +/**
> +  Updates the CRC32 value in the table header.
> +
> +  @param  Hdr    Table to update
> +
> +**/
> +STATIC
> +VOID
> +PartitionSetCrc (
> +  IN OUT EFI_TABLE_HEADER *Hdr
> +  );
> +
> +
> +/**
> +  Get GPT tables.
> +
> +  Caution: This function may receive untrusted input.
> +  The GPT partition table is external input, so this routine
> +  will do basic validation for GPT partition table before install
> +  child handle for each GPT partition.
> +
> +  @param[in]  DiskIoProt     DiskIo interface.
> +  @param[in]  BlockIoProt    BlockIo interface.
> +
> +  @retval EFI_SUCCESS           Valid GPT disk.
> +  @retval EFI_MEDIA_CHANGED     Media changed Detected.
> +  @retval other                 Not a valid GPT disk.
> +
> +**/
> +EFI_STATUS
> +PartitionGetGptTables (
> +  IN  EFI_DISK_IO_PROTOCOL         *DiskIoProt,
> +  IN  EFI_BLOCK_IO_PROTOCOL        *BlockIoProt
> +  )
> +{
> +  EFI_STATUS                  Status;
> +  UINT32                      BlockSize;
> +  EFI_LBA                     LastBlock;
> +  UINTN                       Index;
> +  EFI_STATUS                  GptValidStatus;
> +  UINT32                      MediaId;
> +  MASTER_BOOT_RECORD          *ProtectiveMbr;
> +
> +  // Clear leftovers
> +  GptCleanupGlobals ();
> +
> +  MbrValid = FALSE;
> +  GptValid = FALSE;
> +
> +  ProtectiveMbr = NULL;
> +
> +  BlockIo       = BlockIoProt;
> +  DiskIo        = DiskIoProt;
> +
> +  if (CurRand == 1) {
> +    Srand ();
> +  }
> +
> +  BlockSize     = BlockIo->Media->BlockSize;
> +  LastBlock     = BlockIo->Media->LastBlock;
> +  MediaId       = BlockIo->Media->MediaId;
> +
> +  DEBUG ((EFI_D_VERBOSE, " BlockSize : %d \n", BlockSize));
> +  DEBUG ((EFI_D_VERBOSE, " LastBlock : %lx \n", LastBlock));
> +
> +  GptValidStatus = EFI_NOT_FOUND;
> +  GptValid       = FALSE;
> +  MbrValid       = FALSE;
> +
> +  //
> +  // Allocate a buffer for the Protective MBR
> +  //
> +  ProtectiveMbr = AllocatePool (BlockSize);
> +  if (ProtectiveMbr == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  //
> +  // Read the Protective MBR from LBA #0
> +  //
> +  Status = DiskIo->ReadDisk (
> +    DiskIo,
> +    MediaId,
> +    0,
> +    BlockSize,
> +    ProtectiveMbr
> +    );
> +  if (EFI_ERROR (Status)) {
> +    GptValidStatus = Status;
> +    goto Done;
> +  }
> +
> +  //
> +  // Verify that the Protective MBR is valid
> +  //
> +  for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
> +    if (ProtectiveMbr->Partition[Index].BootIndicator == 0x00 &&
> +        ProtectiveMbr->Partition[Index].OSIndicator ==
> PMBR_GPT_PARTITION &&
> +        UNPACK_UINT32 (ProtectiveMbr->Partition[Index].StartingLBA) == 1
> +       ) {
> +      break;
> +    }
> +  }
> +  if (Index == MAX_MBR_PARTITIONS) {
> +    goto Done;
> +  }
> +
> +  MbrValid = TRUE;
> +
> +  //
> +  // Allocate the GPT structures
> +  //
> +  PrimaryHeader = AllocateZeroPool (sizeof
> (EFI_PARTITION_TABLE_HEADER));
> +  if (PrimaryHeader == NULL) {
> +    goto Done;
> +  }
> +
> +  BackupHeader = AllocateZeroPool (sizeof
> (EFI_PARTITION_TABLE_HEADER));
> +  if (BackupHeader == NULL) {
> +    goto Done;
> +  }
> +
> +  //
> +  // Check primary and backup partition tables
> +  //
> +  Status = PartitionValidGptTable (PRIMARY_PART_HEADER_LBA,
> PrimaryHeader);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((EFI_D_INFO, " Not Valid primary partition table\n"));
> +
> +    Status = PartitionValidGptTable (LastBlock, BackupHeader);
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((EFI_D_INFO, " Not Valid backup partition table\n"));
> +      goto Done;
> +    } else {
> +      DEBUG ((EFI_D_INFO, " Valid backup partition table\n"));
> +      DEBUG ((EFI_D_INFO, " Restore primary partition table by the
> backup\n"));
> +      if (!PartitionRestoreGptTable (BackupHeader)) {
> +        DEBUG ((EFI_D_INFO, " Restore primary partition table error\n"));
> +      }
> +
> +      Status = PartitionValidGptTable (BackupHeader->AlternateLBA,
> PrimaryHeader);
> +      if (!EFI_ERROR (Status)) {
> +        DEBUG ((EFI_D_INFO, " Restore backup partition table success\n"));
> +      }
> +    }
> +  } else if (EFI_ERROR (PartitionValidGptTable (PrimaryHeader-
> >AlternateLBA, BackupHeader))) {
> +    DEBUG ((EFI_D_INFO, " Valid primary and !Valid backup partition
> table\n"));
> +    DEBUG ((EFI_D_INFO, " Restore backup partition table by the
> primary\n"));
> +    if (!PartitionRestoreGptTable (PrimaryHeader)) {
> +      DEBUG ((EFI_D_INFO, " Restore backup partition table error\n"));
> +    }
> +
> +    Status = PartitionValidGptTable (PrimaryHeader->AlternateLBA,
> BackupHeader);
> +    if (!EFI_ERROR (Status)) {
> +      DEBUG ((EFI_D_INFO, " Restore backup partition table success\n"));
> +    }
> +  }
> +
> +  DEBUG ((EFI_D_VERBOSE, " Valid primary and Valid backup partition
> table\n"));
> +
> +  //
> +  // Read the EFI Partition Entries
> +  //
> +  PartEntry = AllocatePool (PrimaryHeader->NumberOfPartitionEntries *
> PrimaryHeader->SizeOfPartitionEntry);
> +  if (PartEntry == NULL) {
> +    DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
> +    goto Done;
> +  }
> +
> +  Status = DiskIo->ReadDisk (
> +    DiskIo,
> +    MediaId,
> +    MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockSize),
> +    PrimaryHeader->NumberOfPartitionEntries * (PrimaryHeader-
> >SizeOfPartitionEntry),
> +    PartEntry
> +    );
> +  if (EFI_ERROR (Status)) {
> +    GptValidStatus = Status;
> +    DEBUG ((EFI_D_ERROR, " Partition Entry ReadDisk error\n"));
> +    goto Done;
> +  }
> +
> +  DEBUG ((EFI_D_VERBOSE, " Partition entries read block success\n"));
> +
> +  DEBUG ((EFI_D_VERBOSE, " Number of partition entries: %d\n",
> PrimaryHeader->NumberOfPartitionEntries));
> +
> +  PEntryStatus = AllocateZeroPool (PrimaryHeader-
> >NumberOfPartitionEntries * sizeof (EFI_PARTITION_ENTRY_STATUS));
> +  if (PEntryStatus == NULL) {
> +    DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
> +    goto Done;
> +  }
> +
> +  //
> +  // Check the integrity of partition entries
> +  //
> +  PartitionCheckGptEntry (PrimaryHeader, PartEntry, PEntryStatus);
> +
> +  //
> +  // If we got this far the GPT layout of the disk is valid and we should return
> true
> +  //
> +  GptValidStatus = EFI_SUCCESS;
> +
> + Done:
> +  SHELL_FREE_NON_NULL (ProtectiveMbr);
> +  if (EFI_ERROR (GptValidStatus)) {
> +    SHELL_FREE_NON_NULL (PrimaryHeader);
> +    SHELL_FREE_NON_NULL (BackupHeader);
> +    SHELL_FREE_NON_NULL (PartEntry);
> +    SHELL_FREE_NON_NULL (PEntryStatus);
> +  } else {
> +    GptValid = TRUE;
> +  }
> +
> +  return GptValidStatus;
> +}
> +
> +/**
> +  This routine will read GPT partition table header and return it.
> +
> +  Caution: This function may receive untrusted input.
> +  The GPT partition table header is external input, so this routine
> +  will do basic validation for GPT partition table header before return.
> +
> +  @param[in]  Lba         The starting Lba of the Partition Table
> +  @param[out] PartHeader  Stores the partition table that is read
> +
> +  @retval TRUE      The partition table is valid
> +  @retval FALSE     The partition table is not valid
> +
> +**/
> +STATIC
> +EFI_STATUS
> +PartitionValidGptTable (
> +  IN  EFI_LBA                     Lba,
> +  OUT EFI_PARTITION_TABLE_HEADER  *PartHeader
> +  )
> +{
> +  EFI_STATUS                  Status;
> +  UINT32                      BlockSize;
> +  EFI_PARTITION_TABLE_HEADER  *PartHdr;
> +  UINT32                      MediaId;
> +
> +  BlockSize = BlockIo->Media->BlockSize;
> +  MediaId   = BlockIo->Media->MediaId;
> +  PartHdr   = AllocateZeroPool (BlockSize);
> +
> +  if (PartHdr == NULL) {
> +    DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +  //
> +  // Read the EFI Partition Table Header
> +  //
> +  Status = DiskIo->ReadDisk (
> +    DiskIo,
> +    MediaId,
> +    MultU64x32 (Lba, BlockSize),
> +    BlockSize,
> +    PartHdr
> +    );
> +  if (EFI_ERROR (Status)) {
> +    FreePool (PartHdr);
> +    return Status;
> +  }
> +
> +  if ((PartHdr->Header.Signature != EFI_PTAB_HEADER_ID) ||
> +      !PartitionCheckCrc (BlockSize, &PartHdr->Header) ||
> +      PartHdr->MyLBA != Lba ||
> +      (PartHdr->SizeOfPartitionEntry < sizeof (EFI_PARTITION_ENTRY))
> +     ) {
> +    DEBUG ((EFI_D_ERROR, "Invalid efi partition table header\n"));
> +    FreePool (PartHdr);
> +    return EFI_VOLUME_CORRUPTED;
> +  }
> +
> +  //
> +  // Ensure the NumberOfPartitionEntries * SizeOfPartitionEntry doesn't
> overflow.
> +  //
> +  if (PartHdr->NumberOfPartitionEntries > DivU64x32 (MAX_UINTN,
> PartHdr->SizeOfPartitionEntry)) {
> +    FreePool (PartHdr);
> +    return EFI_VOLUME_CORRUPTED;
> +  }
> +
> +  CopyMem (PartHeader, PartHdr, sizeof (EFI_PARTITION_TABLE_HEADER));
> +  if (!PartitionCheckGptEntryArrayCRC (PartHeader)) {
> +    FreePool (PartHdr);
> +    return EFI_VOLUME_CORRUPTED;
> +  }
> +
> +  DEBUG ((EFI_D_VERBOSE, " Valid efi partition table header\n"));
> +  FreePool (PartHdr);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Check if the CRC field in the Partition table header is valid
> +  for Partition entry array.
> +
> +  @param[in]  PartHeader  Partition table header structure
> +
> +  @retval TRUE      the CRC is valid
> +  @retval FALSE     the CRC is invalid
> +
> +**/
> +STATIC
> +BOOLEAN
> +PartitionCheckGptEntryArrayCRC (
> +  IN  EFI_PARTITION_TABLE_HEADER  *PartHeader
> +  )
> +{
> +  EFI_STATUS  Status;
> +  UINT8       *Ptr;
> +  UINT32      Crc;
> +  UINTN       Size;
> +
> +  //
> +  // Read the EFI Partition Entries
> +  //
> +  Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader-
> >SizeOfPartitionEntry);
> +  if (Ptr == NULL) {
> +    DEBUG ((EFI_D_ERROR, " Allocate pool error\n"));
> +    return FALSE;
> +  }
> +
> +  Status = DiskIo->ReadDisk (
> +    DiskIo,
> +    BlockIo->Media->MediaId,
> +    MultU64x32 (PartHeader->PartitionEntryLBA, BlockIo->Media-
> >BlockSize),
> +    PartHeader->NumberOfPartitionEntries * PartHeader-
> >SizeOfPartitionEntry,
> +    Ptr
> +    );
> +  if (EFI_ERROR (Status)) {
> +    FreePool (Ptr);
> +    return FALSE;
> +  }
> +
> +  Size    = PartHeader->NumberOfPartitionEntries * PartHeader-
> >SizeOfPartitionEntry;
> +
> +  Status  = gBS->CalculateCrc32 (Ptr, Size, &Crc);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((EFI_D_ERROR, "CheckPEntryArrayCRC: Crc calculation
> failed\n"));
> +    FreePool (Ptr);
> +    return FALSE;
> +  }
> +
> +  FreePool (Ptr);
> +
> +  return (BOOLEAN)(PartHeader->PartitionEntryArrayCRC32 == Crc);
> +}
> +
> +
> +/**
> +  Restore Partition Table to its alternate place
> +  (Primary -> Backup or Backup -> Primary).
> +
> +  @param[in]  PartHeader  Partition table header structure.
> +
> +  @retval TRUE      Restoring succeeds
> +  @retval FALSE     Restoring failed
> +
> +**/
> +STATIC
> +BOOLEAN
> +PartitionRestoreGptTable (
> +  IN  EFI_PARTITION_TABLE_HEADER  *PartHeader
> +  )
> +{
> +  EFI_STATUS                  Status;
> +  UINTN                       BlockSize;
> +  EFI_PARTITION_TABLE_HEADER  *PartHdr;
> +  EFI_LBA                     PEntryLBA;
> +  UINT8                       *Ptr;
> +  UINT32                      MediaId;
> +
> +  PartHdr   = NULL;
> +  Ptr       = NULL;
> +
> +  BlockSize = BlockIo->Media->BlockSize;
> +  MediaId   = BlockIo->Media->MediaId;
> +
> +  PartHdr   = AllocateZeroPool (BlockSize);
> +
> +  if (PartHdr == NULL) {
> +    DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
> +    return FALSE;
> +  }
> +
> +  PEntryLBA = (PartHeader->MyLBA == PRIMARY_PART_HEADER_LBA) ?\
> +    (PartHeader->LastUsableLBA + 1) :\
> +    (PRIMARY_PART_HEADER_LBA + 1);
> +
> +  CopyMem (PartHdr, PartHeader, sizeof (EFI_PARTITION_TABLE_HEADER));
> +
> +  PartHdr->MyLBA              = PartHeader->AlternateLBA;
> +  PartHdr->AlternateLBA       = PartHeader->MyLBA;
> +  PartHdr->PartitionEntryLBA  = PEntryLBA;
> +  PartitionSetCrc ((EFI_TABLE_HEADER *)PartHdr);
> +
> +  Status = DiskIo->WriteDisk (
> +    DiskIo,
> +    MediaId,
> +    MultU64x32 (PartHdr->MyLBA, (UINT32)BlockSize),
> +    BlockSize,
> +    PartHdr
> +    );
> +  if (EFI_ERROR (Status)) {
> +    goto Done;
> +  }
> +
> +  Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader-
> >SizeOfPartitionEntry);
> +  if (Ptr == NULL) {
> +    DEBUG ((EFI_D_ERROR, " Allocate pool error\n"));
> +    Status = EFI_OUT_OF_RESOURCES;
> +    goto Done;
> +  }
> +
> +  Status = DiskIo->ReadDisk (
> +    DiskIo,
> +    MediaId,
> +    MultU64x32 (PartHeader->PartitionEntryLBA, (UINT32)BlockSize),
> +    PartHeader->NumberOfPartitionEntries * PartHeader-
> >SizeOfPartitionEntry,
> +    Ptr
> +    );
> +  if (EFI_ERROR (Status)) {
> +    goto Done;
> +  }
> +
> +  Status = DiskIo->WriteDisk (
> +    DiskIo,
> +    MediaId,
> +    MultU64x32 (PEntryLBA, (UINT32)BlockSize),
> +    PartHeader->NumberOfPartitionEntries * PartHeader-
> >SizeOfPartitionEntry,
> +    Ptr
> +    );
> +
> + Done:
> +  FreePool (PartHdr);
> +
> +  if (Ptr != NULL) {
> +    FreePool (Ptr);
> +  }
> +
> +  if (EFI_ERROR (Status)) {
> +    return FALSE;
> +  }
> +
> +  return TRUE;
> +}
> +
> +/**
> +  This routine will check GPT partition entry and return entry status.
> +
> +  Caution: This function may receive untrusted input.
> +  The GPT partition entry is external input, so this routine
> +  will do basic validation for GPT partition entry and report status.
> +
> +  @param[in]    PartHeader    Partition table header structure
> +  @param[in]    PartEntry     The partition entry array
> +  @param[out]   PEntryStatus  the partition entry status array
> +                              recording the status of each partition
> +
> +**/
> +STATIC
> +VOID
> +PartitionCheckGptEntry (
> +  IN  EFI_PARTITION_TABLE_HEADER  *PartHeader,
> +  IN  EFI_PARTITION_ENTRY         *PartEntry,
> +  OUT EFI_PARTITION_ENTRY_STATUS  *PEntryStatus
> +  )
> +{
> +  EFI_LBA              StartingLBA;
> +  EFI_LBA              EndingLBA;
> +  EFI_PARTITION_ENTRY  *Entry;
> +  UINTN                Index1;
> +  UINTN                Index2;
> +
> +  DEBUG ((EFI_D_VERBOSE, " start check partition entries\n"));
> +  for (Index1 = 0; Index1 < PartHeader->NumberOfPartitionEntries;
> Index1++) {
> +    Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index1 *
> PartHeader->SizeOfPartitionEntry);
> +    if (CompareGuid (&Entry->PartitionTypeGUID,
> &gEfiPartTypeUnusedGuid)) {
> +      continue;
> +    }
> +
> +    StartingLBA = Entry->StartingLBA;
> +    EndingLBA   = Entry->EndingLBA;
> +    if (StartingLBA > EndingLBA ||
> +        StartingLBA < PartHeader->FirstUsableLBA ||
> +        StartingLBA > PartHeader->LastUsableLBA ||
> +        EndingLBA < PartHeader->FirstUsableLBA ||
> +        EndingLBA > PartHeader->LastUsableLBA
> +       ) {
> +      PEntryStatus[Index1].OutOfRange = TRUE;
> +      continue;
> +    }
> +
> +    if ((Entry->Attributes & BIT1) != 0) {
> +      //
> +      // If Bit 1 is set, this indicate that this is an OS specific GUID partition.
> +      //
> +      PEntryStatus[Index1].OsSpecific = TRUE;
> +    }
> +
> +    for (Index2 = Index1 + 1; Index2 < PartHeader-
> >NumberOfPartitionEntries; Index2++) {
> +      Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index2 *
> PartHeader->SizeOfPartitionEntry);
> +      if (CompareGuid (&Entry->PartitionTypeGUID,
> &gEfiPartTypeUnusedGuid)) {
> +        continue;
> +      }
> +
> +      if (Entry->EndingLBA >= StartingLBA && Entry->StartingLBA <=
> EndingLBA) {
> +        //
> +        // This region overlaps with the Index1'th region
> +        //
> +        PEntryStatus[Index1].Overlap  = TRUE;
> +        PEntryStatus[Index2].Overlap  = TRUE;
> +        continue;
> +      }
> +    }
> +  }
> +
> +  DEBUG ((EFI_D_VERBOSE, " End check partition entries\n"));
> +}
> +
> +
> +/**
> +  Updates the CRC32 value in the table header.
> +
> +  @param  Hdr    Table to update
> +
> +**/
> +STATIC
> +VOID
> +PartitionSetCrc (
> +  IN OUT EFI_TABLE_HEADER *Hdr
> +  )
> +{
> +  PartitionSetCrcAltSize (Hdr->HeaderSize, Hdr);
> +}
> +
> +
> +/**
> +  Updates the CRC32 value in the table header.
> +
> +  @param  Size   The size of the table
> +  @param  Hdr    Table to update
> +
> +**/
> +STATIC
> +VOID
> +PartitionSetCrcAltSize (
> +  IN UINTN                 Size,
> +  IN OUT EFI_TABLE_HEADER  *Hdr
> +  )
> +{
> +  UINT32  Crc;
> +
> +  Hdr->CRC32 = 0;
> +  gBS->CalculateCrc32 ((UINT8 *)Hdr, Size, &Crc);
> +  Hdr->CRC32 = Crc;
> +}
> +
> +
> +/**
> +  Checks the CRC32 value in the table header.
> +
> +  @param  MaxSize   Max Size limit
> +  @param  Hdr       Table to check
> +
> +  @return TRUE      CRC Valid
> +  @return FALSE     CRC Invalid
> +
> +**/
> +STATIC
> +BOOLEAN
> +PartitionCheckCrc (
> +  IN UINTN                 MaxSize,
> +  IN OUT EFI_TABLE_HEADER  *Hdr
> +  )
> +{
> +  return PartitionCheckCrcAltSize (MaxSize, Hdr->HeaderSize, Hdr);
> +}
> +
> +
> +/**
> +  Checks the CRC32 value in the table header.
> +
> +  @param  MaxSize   Max Size limit
> +  @param  Size      The size of the table
> +  @param  Hdr       Table to check
> +
> +  @return TRUE    CRC Valid
> +  @return FALSE   CRC Invalid
> +
> +**/
> +STATIC
> +BOOLEAN
> +PartitionCheckCrcAltSize (
> +  IN UINTN                 MaxSize,
> +  IN UINTN                 Size,
> +  IN OUT EFI_TABLE_HEADER  *Hdr
> +  )
> +{
> +  UINT32      Crc;
> +  UINT32      OrgCrc;
> +  EFI_STATUS  Status;
> +
> +  Crc = 0;
> +
> +  if (Size == 0) {
> +    //
> +    // If header size is 0 CRC will pass so return FALSE here
> +    //
> +    return FALSE;
> +  }
> +
> +  if ((MaxSize != 0) && (Size > MaxSize)) {
> +    DEBUG ((EFI_D_ERROR, "CheckCrc32: Size > MaxSize\n"));
> +    return FALSE;
> +  }
> +  //
> +  // clear old crc from header
> +  //
> +  OrgCrc      = Hdr->CRC32;
> +  Hdr->CRC32  = 0;
> +
> +  Status      = gBS->CalculateCrc32 ((UINT8 *)Hdr, Size, &Crc);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc calculation failed\n"));
> +    return FALSE;
> +  }
> +  //
> +  // set results
> +  //
> +  Hdr->CRC32 = Crc;
> +
> +  //
> +  // return status
> +  //
> +  DEBUG_CODE_BEGIN ();
> +  if (OrgCrc != Crc) {
> +    DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc check failed\n"));
> +  }
> +  DEBUG_CODE_END ();
> +
> +  return (BOOLEAN)(OrgCrc == Crc);
> +}
> +
> +/**
> +  Converts a GUID into a unicode string.
> +
> +  @param  [in] Guid             A GUID to be converted
> +  @param  [out] Buffer          A pointer to a buffer receiving the string
> +  @param  [in] BufferSize       Size of the buffer
> +
> +  @return EFI_SUCCESS           Successful conversion
> +  @return EFI_INVALID_PARAMETER Conversion failed
> +
> +**/
> +
> +STATIC
> +EFI_STATUS
> +GuidToString (
> +  IN  EFI_GUID  *Guid,
> +  OUT CHAR16    *Buffer,
> +  IN  UINTN     BufferSize
> +  )
> +{
> +  UINTN        Size;
> +  EFI_STATUS   Status;
> +
> +  Status = EFI_SUCCESS;
> +
> +  Size = UnicodeSPrint (
> +    Buffer,
> +    BufferSize,
> +    L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
> +    (UINTN)Guid->Data1,
> +    (UINTN)Guid->Data2,
> +    (UINTN)Guid->Data3,
> +    (UINTN)Guid->Data4[0],
> +    (UINTN)Guid->Data4[1],
> +    (UINTN)Guid->Data4[2],
> +    (UINTN)Guid->Data4[3],
> +    (UINTN)Guid->Data4[4],
> +    (UINTN)Guid->Data4[5],
> +    (UINTN)Guid->Data4[6],
> +    (UINTN)Guid->Data4[7]
> +    );
> +  if (!Size) {
> +    Status = EFI_INVALID_PARAMETER;
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Get a string representation of a known
> +  partition type GUID. If partition GUID is not
> +  known, gets a string representation of the GUID
> +
> +  @param  GUID          Guid to be searched for
> +  @param  PartTypeStr   Buffer receiving the string
> +  @param  NoGuidStr     Do not convert GUID to string
> +                        for an unknown partition type
> +
> +  @return EFI_SUCCESS   GUID type is known
> +  @return EFI_NOT_FOUND Unknown GUID partition type
> +
> +**/
> +EFI_STATUS
> +GetPartitionTypeStr (
> +  IN EFI_GUID Guid,
> +  OUT CHAR16 *PartTypeStr,
> +  IN BOOLEAN NoGuidStr)
> +{
> +  UINTN       Index;
> +  EFI_STATUS  Status;
> +
> +  Status = EFI_SUCCESS;
> +  for (Index = 0; Index < ARRAY_SIZE (PartitionTypes); Index++) {
> +    if (CompareGuid (&Guid, &PartitionTypes[Index].TypeGuid)) {
> +      StrnCpy (PartTypeStr, PartitionTypes[Index].TypeName,
> MAX_PARTITION_NAME_LENGTH);
> +      return Status;
> +    }
> +  }
> +  if (!NoGuidStr) {
> +    GuidToString (&Guid, PartTypeStr, (MAX_PARTITION_NAME_LENGTH +
> 1) * sizeof (CHAR16));
> +  }
> +  return EFI_NOT_FOUND;
> +}
> +
> +/**
> +  Lists partitions on a block device.
> +
> +  @return   Number of partitions used
> +**/
> +
> +UINTN
> +PartitionListGptEntries (VOID)
> +{
> +  IN UINTN                Index;
> +  IN EFI_PARTITION_ENTRY  *Entry;
> +  IN EFI_LBA              Length;
> +  IN UINTN                NumEntries; // Used entries
> +  IN UINTN                BlockSize;
> +  IN BOOLEAN              FirstTime;
> +  IN UINT64               BlocksOccupied;
> +
> +  NumEntries = 0;
> +  BlockSize = BlockIo->Media->BlockSize;
> +  FirstTime = TRUE;
> +
> +  if (!GptValid) {
> +    return 0;
> +  }
> +
> +  BlocksOccupied = 0;
> +
> +  for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries;
> Index++) {
> +
> +    BOOLEAN   Specific;
> +    CHAR16    PartTypeStr[MAX_PARTITION_NAME_LENGTH + 1];
> +
> +    Specific = FALSE;
> +
> +    Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index *
> PrimaryHeader->SizeOfPartitionEntry);
> +
> +    Length = Entry->EndingLBA - Entry->StartingLBA + 1;
> +
> +    if (CompareGuid (&Entry->PartitionTypeGUID,
> &gEfiPartTypeUnusedGuid)) {
> +      continue;
> +    }
> +
> +    if (FirstTime) {
> +      Print (L"  No \t%-36s\tStart (LBA)\tEnd (LBA)\tSize (MiB)\t Partition
> Type\r\n", L"Name");
> +      Print (L" ----  --------------------------------------   -----------     -----------     -----
> -----       -------------------------------\r\n");
> +      FirstTime = FALSE;
> +    }
> +    NumEntries++;
> +    if (PEntryStatus[Index].OutOfRange ||
> +        PEntryStatus[Index].Overlap ||
> +        PEntryStatus[Index].OsSpecific) {
> +      Specific = TRUE;
> +    }
> +
> +    BlocksOccupied += Length;
> +
> +    GetPartitionTypeStr (Entry->PartitionTypeGUID, (CHAR16
> *)&PartTypeStr, FALSE);
> +
> +    Print (L"%1s %-3d\t%-36s\t0x%09llx\t0x%09llx\t%06llu\t         %s\r\n",
> +           Specific ? L"S" : L"",
> +           Index + 1,
> +           Entry->PartitionName,
> +           (UINT64)Entry->StartingLBA,
> +           (UINT64)Entry->EndingLBA,
> +           (MultU64x32 (Length, BlockSize)) >> 20,
> +           PartTypeStr);
> +  }
> +
> +  // This code block is to provide additional info
> +  {
> +    UINT64   DiskSizeMiB;
> +    UINT64   SizeOccupiedMiB;
> +
> +    DiskSizeMiB = MultU64x32 (PrimaryHeader->LastUsableLBA -
> PrimaryHeader->FirstUsableLBA + 1, BlockIo->Media->BlockSize) >> 20;
> +    SizeOccupiedMiB = MultU64x32 (BlocksOccupied, BlockIo->Media-
> >BlockSize) >> 20;
> +    Print (L"\r\n%d partition(s) used out of %d\r\n", NumEntries,
> PrimaryHeader->NumberOfPartitionEntries);
> +    Print (L"Total device capacity (minus GPT service blocks): %llu
> MiB\r\nPartitioned space: %llu MiB\r\n",
> +           DiskSizeMiB,
> +           SizeOccupiedMiB);
> +    Print (L"Unpartitioned space available: %llu MiB (%d%%)\n",
> +           DiskSizeMiB - SizeOccupiedMiB,
> +           (100 * (DiskSizeMiB - SizeOccupiedMiB)) / DiskSizeMiB);
> +  }
> +
> +  return NumEntries;
> +}
> +
> +/**
> +  Locate a partition by criteria
> +
> +  @param  Name         Partition name (or ordinal represented a string)
> +  @param  StartLba     StartLba of the partition to search for
> +  @param  EndingLba    EndingLba of the partition to search for
> +  @param  SearchType   A combination (OR) of search options.
> +                       Options are:
> +                        SRC_BY_NAME    = search by partition name
> +                        SRC_BY_LBA     = search by Start/Ending lba
> +                        SRC_ANY        = returns a first used partition
> +                        SRC_BY_NUM     = search by ordinal
> +
> +
> +  @return Non-NULL    Pointer to the partition found
> +  @return NULL        No partition found
> +
> +**/
> +EFI_PARTITION_ENTRY *
> +PartitionFindPartitionByCriteria (
> +  IN OPTIONAL CONST CHAR16   *Name,
> +  IN OPTIONAL EFI_LBA        StartLba,
> +  IN OPTIONAL EFI_LBA        EndingLba,
> +  IN SEARCH_TYPE             SearchType
> +  )
> +{
> +  UINTN                Index;
> +  EFI_PARTITION_ENTRY  *Entry;
> +
> +  if (!GptValid) {
> +    return NULL;
> +  }
> +
> +  if (!Name && (SearchType & SRC_BY_NAME)) {
> +    return NULL;
> +  }
> +
> +  for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries;
> Index++) {
> +    Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index *
> PrimaryHeader->SizeOfPartitionEntry);
> +
> +    if (CompareGuid (&Entry->PartitionTypeGUID,
> &gEfiPartTypeUnusedGuid)) {
> +      continue;
> +    }
> +
> +    if (SearchType & SRC_ANY) {
> +      return Entry;
> +    }
> +
> +    if (SearchType & SRC_BY_NAME) {
> +      if (!StrCmp (Name, Entry->PartitionName)) {
> +        return Entry;
> +      }
> +    }
> +    if (SearchType & SRC_BY_NUM) {
> +      UINTN Ordinal;
> +
> +      Ordinal = ShellStrToUintn (Name);
> +      if (Index == (Ordinal - 1)) {
> +        return Entry;
> +      }
> +    }
> +    if (SearchType & SRC_BY_LBA) {
> +      if (
> +          ((StartLba >= Entry->StartingLBA) &&
> +           (StartLba <= Entry->EndingLBA)
> +          ) ||
> +          ((EndingLba >= Entry->StartingLBA) &&
> +           (EndingLba <= Entry->EndingLBA)
> +          )
> +         ) {
> +        return Entry;
> +      }
> +    }
> +  }
> +  return NULL;
> +}
> +
> +/**
> +  Prints information on a given partition.
> +
> +  @param  Entry   Pointer to the Partition of interest
> +**/
> +
> +VOID
> +PartitionPrintGptPartInfo (
> +  IN EFI_PARTITION_ENTRY *Entry
> +  )
> +{
> +  CONST CHAR16      PartStr[MAX_PARTITION_NAME_LENGTH + 1];
> +  CONST CHAR16      *StrUnknown;
> +  EFI_STATUS        Status;
> +  EFI_LBA           Length;
> +
> +  ASSERT (Entry);
> +
> +  ZeroMem ((VOID *)PartStr, sizeof (PartStr));
> +  StrUnknown = GPT_PART_UNKNOWN_STR;
> +
> +  Status = GetPartitionTypeStr (Entry->PartitionTypeGUID, (CHAR16
> *)&PartStr, TRUE);
> +  if (EFI_ERROR (Status)) {
> +    StrCpy ((CHAR16 *)&PartStr, StrUnknown);
> +  }
> +
> +  Length = Entry->EndingLBA - Entry->StartingLBA + 1;
> +
> +  Print (L"Partition name: %s\r\n", Entry->PartitionName);
> +  Print (L"Starting LBA  : 0x%09llx\r\nEnding LBA    : 0x%09llx\r\n",
> +         (UINT64)Entry->StartingLBA, (UINT64)Entry->EndingLBA);
> +  Print (L"Partition Size: %llu MiB (0x%llx blocks)\n",
> +         (MultU64x32 (Length, BlockIo->Media->BlockSize)) >> 20, Length);
> +  Print (L"Attributes    : 0x%09llx\r\n", Entry->Attributes);
> +  Print (L"Type/GUID     : %s/%g\r\n", PartStr, &Entry->PartitionTypeGUID);
> +  Print (L"Unique GUID   : %g\n", &Entry->UniquePartitionGUID);
> +}
> +
> +/**
> +  Writes protective MBR to a block device.
> +
> +  @return EFI_SUCCESS    MBR written successfully
> +  @return other          Failed to write an MBR
> +
> +**/
> +
> +STATIC
> +EFI_STATUS
> +WriteProtectiveMbr (
> +  VOID
> +  )
> +{
> +  UINT32               BlockSize;
> +  UINT64               DiskSize;
> +  EFI_STATUS           Status;
> +  MBR_PARTITION_RECORD *Partition;
> +  MASTER_BOOT_RECORD   *ProtectiveMbr;
> +
> +  BlockSize = BlockIo->Media->BlockSize;
> +
> +  ProtectiveMbr = NULL;
> +  ProtectiveMbr = AllocateZeroPool (BlockSize);
> +  if (ProtectiveMbr == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  DiskSize = BlockIo->Media->LastBlock + 1;
> +  if (DiskSize > 0xffffffff) {
> +    DiskSize = 0xffffffff;
> +  }
> +
> +  CopyMem (ProtectiveMbr, &ProtectiveMbrTemplate, sizeof
> (MASTER_BOOT_RECORD));
> +
> +  Partition = &ProtectiveMbr->Partition[0];
> +
> +  Partition->BootIndicator = 0;
> +  Partition->StartSector = 1;
> +
> +  //
> +  // We don't actually know this data, so we'll make up
> +  // something that seems likely.
> +  //
> +
> +  //
> +  // Old software is expecting the Partition to start on
> +  // a Track boundary, so we'll set track to 1 to avoid "overlay"
> +  // with the MBR
> +  //
> +
> +  Partition->StartTrack = 1;
> +
> +  Status = DiskIo->WriteDisk (
> +    DiskIo,
> +    BlockIo->Media->MediaId,
> +    0,
> +    BlockSize,
> +    ProtectiveMbr
> +    );
> +
> +  MbrValid = !EFI_ERROR (Status);
> +
> +  SHELL_FREE_NON_NULL (ProtectiveMbr);
> +
> +  return Status;
> +}
> +
> +/**
> +  Write GPT tables to the block device.
> +
> +  @return EFI_SUCCESS    GPT tables were successfully written/updated
> +  @return other          Failed to write/update GPT tables
> +
> +**/
> +
> +STATIC
> +EFI_STATUS
> +WriteGPT (
> +  VOID
> +  )
> +/*
> +    CALLER is expected to fill in:
> +            FirstUseableLBA
> +            LastUseableLBA
> +            EntryCount
> +            DiskGUID
> +
> +    We fill in the rest, and blast it out.
> +
> +    Returns a status.
> +
> +*/
> +{
> +  UINT32      BlockSize;
> +  UINT32      TableSize;
> +  EFI_STATUS  Status = EFI_SUCCESS;
> +
> +  BlockSize = BlockIo->Media->BlockSize;
> +  TableSize = PrimaryHeader->NumberOfPartitionEntries * sizeof
> (EFI_PARTITION_ENTRY);
> +
> +  if (!MbrValid) {
> +    WriteProtectiveMbr ();
> +  }
> +  //
> +  // Write out the primary header...
> +  //
> +  PrimaryHeader->Header.Signature = EFI_PTAB_HEADER_ID;
> +  PrimaryHeader->Header.Revision = GPT_REVISION_1_0;
> +  PrimaryHeader->Header.HeaderSize = sizeof
> (EFI_PARTITION_TABLE_HEADER);
> +
> +  PrimaryHeader->AlternateLBA = BackupHeader->MyLBA;
> +
> +  PrimaryHeader->SizeOfPartitionEntry = sizeof (EFI_PARTITION_ENTRY);
> +
> +  Status = gBS->CalculateCrc32 ((UINT8 *)PartEntry, TableSize,
> &PrimaryHeader->PartitionEntryArrayCRC32);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  // Write primary header
> +  PartitionSetCrc (&PrimaryHeader->Header);
> +
> +  Status = DiskIo->WriteDisk (
> +    DiskIo,
> +    BlockIo->Media->MediaId,
> +    MultU64x32 (PrimaryHeader->MyLBA, (UINT32)BlockSize),
> +    BlockSize,
> +    PrimaryHeader
> +    );
> +
> +
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  //
> +  // Write out the primary table ...
> +  //
> +  Status = DiskIo->WriteDisk (
> +    DiskIo,
> +    BlockIo->Media->MediaId,
> +    MultU64x32 (PrimaryHeader->PartitionEntryLBA, (UINT32)BlockSize),
> +    TableSize,
> +    PartEntry
> +    );
> +
> +
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  //
> +  // Write out the secondary header and table by calling restore
> +  //
> +
> +  if (!PartitionRestoreGptTable (PrimaryHeader)) {
> +    return EFI_VOLUME_CORRUPTED;
> +  }
> +  BlockIo->FlushBlocks (BlockIo);
> +  GptValid = !EFI_ERROR (Status);
> +
> +  return Status;
> +}
> +
> +/**
> +  (Re)initialize GPT tables on the block device
> +
> +  @return EFI_SUCCESS    Successfully (re)initialized GPT Tables
> +  @return other          Failed to (re)initialize GPT tables
> +
> +**/
> +STATIC
> +EFI_STATUS
> +TableCreateEmptyGpt (
> +  VOID
> +  )
> +{
> +  UINTN       EntryCount;
> +  UINTN       BlockFit;
> +  UINTN       BlockSize;
> +  UINTN       EntryBlocks;
> +  UINT64      DiskSize;
> +  UINTN       TableSize;
> +  EFI_LBA     Header1_LBA;
> +  EFI_LBA     Table1_LBA;
> +  EFI_LBA     Header2_LBA;
> +  EFI_LBA     Table2_LBA;
> +  EFI_LBA     FirstUsableLBA;
> +  EFI_LBA     LastUsableLBA;
> +  EFI_STATUS  Status;
> +
> +  EntryCount = ENTRY_DEFAULT;
> +  BlockSize = BlockIo->Media->BlockSize;
> +  BlockFit =  BlockSize / sizeof (EFI_PARTITION_ENTRY);
> +
> +  if (BlockFit > ENTRY_DEFAULT) {
> +    EntryCount = BlockFit;
> +  }
> +  EntryBlocks = EntryCount / BlockFit;
> +
> +  if ((EntryBlocks * BlockFit) != EntryCount) {
> +    Status = EFI_VOLUME_CORRUPTED;
> +    PrintErr (L"Invalid Entry blocks and Entry count combination\n", Status);
> +    return Status;
> +  }
> +
> +  DiskSize = BlockIo->Media->LastBlock + 1;
> +
> +  SHELL_FREE_NON_NULL (PrimaryHeader);
> +  SHELL_FREE_NON_NULL (BackupHeader);
> +  SHELL_FREE_NON_NULL (PartEntry);
> +
> +  PrimaryHeader = AllocateZeroPool (BlockSize);
> +  if (PrimaryHeader == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  BackupHeader = AllocateZeroPool (BlockSize);
> +  if (BackupHeader == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  Header1_LBA = 1;
> +  Table1_LBA = 2;
> +  FirstUsableLBA = Table1_LBA + EntryBlocks;
> +
> +  Header2_LBA = DiskSize - 1;
> +  Table2_LBA = Header2_LBA - EntryBlocks;
> +  LastUsableLBA = Table2_LBA - 1;
> +
> +  TableSize = EntryBlocks * BlockSize;
> +
> +  if (TableSize != (EntryCount * sizeof (EFI_PARTITION_ENTRY))) {
> +    Status = EFI_VOLUME_CORRUPTED;
> +    PrintErr (L"Invalid Table size and Entry count combination\n", Status);
> +    return Status;
> +  }
> +
> +  if (GPT_DEBUG_LEVEL) {
> +    Print (L"DiskSize = %lx\n", DiskSize);
> +    Print (L"BlockSize = %x\n", BlockSize);
> +    Print (L"Header1_LBA = %lx\n", Header1_LBA);
> +    Print (L"Table1_LBA = %lx\n", Table1_LBA);
> +    Print (L"FirstUsableLBA = %lx\n", FirstUsableLBA);
> +    Print (L"Header2_LBA = %lx\n", Header2_LBA);
> +    Print (L"Table2_LBA = %lx\n", Table2_LBA);
> +    Print (L"LastUsableLBA = %lx\n", LastUsableLBA);
> +    Print (L"EntryCount = %x\n", EntryCount);
> +    Print (L"EntryBlocks = %x\n", EntryBlocks);
> +  }
> +
> +  //
> +  // Since we're making empty tables, we just write zeros...
> +  //
> +
> +  PartEntry = AllocateZeroPool (TableSize);
> +  if (PartEntry == NULL) {
> +    SHELL_FREE_NON_NULL (PrimaryHeader);
> +    SHELL_FREE_NON_NULL (BackupHeader);
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  PEntryStatus = AllocateZeroPool (TableSize);
> +
> +  PrimaryHeader->FirstUsableLBA = FirstUsableLBA;
> +  PrimaryHeader->LastUsableLBA = LastUsableLBA;
> +  PrimaryHeader->NumberOfPartitionEntries = (UINT32)EntryCount;
> +  GenerateGuid (&PrimaryHeader->DiskGUID);
> +
> +  PrimaryHeader->MyLBA             = Header1_LBA;
> +  BackupHeader->MyLBA              = Header2_LBA;
> +  PrimaryHeader->PartitionEntryLBA = Table1_LBA;
> +  BackupHeader->PartitionEntryLBA  = Table2_LBA;
> +
> +  Status = WriteGPT ();
> +
> +  return Status;
> +}
> +
> +/**
> +  Clear GPT partitions.
> +
> +  @return EFI_SUCCESS    Cleared successfully
> +  @return FALSE          Failed to clear
> +
> +**/
> +
> +EFI_STATUS
> +PartitionGptClearAll (
> +  VOID
> +  )
> +{
> +  GptCleanupGlobals ();
> +  GptValid = FALSE;
> +  MbrValid = FALSE;
> +  return TableCreateEmptyGpt ();
> +}
> +
> +/**
> +  Create a GPT partition.
> +
> +  @param  PartName              Partition Name
> +  @param  StartLba              Starting LBA of the partition.
> +                                if zero, will be calculated
> +  @param  SizeInMegaBytes       Size of the partition in MB
> +  @param  Attributes            Partition attributes
> +  @param  PartTypeGuid          a Type GUID to be assigned to the partition
> (not a partition unique GUID)
> +
> +
> +  @return EFI_SUCCESS           Partition successfully created
> +  @return EFI_INVALID_PARAMETER Either partition exists, or wrong
> parameters specified
> +  @return other                 Failed to create a partition
> +**/
> +EFI_STATUS
> +PartitionGptCreatePartition (
> +  IN CONST CHAR16     *PartName,
> +  IN EFI_LBA          StartLba,
> +  IN UINT64           SizeInMegabytes,
> +  IN UINT64           Attributes,
> +  IN EFI_GUID         PartTypeGuid
> +  )
> +{
> +  EFI_GUID    Guid;
> +  EFI_GUID    PartitionIdGuid;
> +  EFI_STATUS  Status;
> +  UINT64      StartBlock;
> +  UINT64      EndBlock;
> +  UINT64      SizeInBytes;
> +  UINT32      BlockSize;
> +  UINT64      DiskSizeBlocks;
> +  UINT8       *p;
> +  BOOLEAN     OffsetSpecified;
> +  BOOLEAN     AllZeros;
> +  INTN        AllZeroEntry;
> +  INTN        OldFreeEntry;
> +  UINT64      AvailBlocks;
> +  UINT64      BlocksToAllocate;
> +  UINT64      HighSeen;
> +  UINTN       Slot;
> +  UINT64      LowestAlignedLba;
> +  UINT32      OptimalTransferBlocks;
> +  UINTN       i;
> +  UINTN       j;
> +  CHAR16      PartNameUsed[MAX_PARTITION_NAME_LENGTH + 1];
> +  EFI_PARTITION_ENTRY *Entry;
> +
> +  SizeInBytes = 0;
> +  OffsetSpecified = FALSE;
> +  ZeroMem (PartNameUsed, sizeof (PartNameUsed));
> +  LowestAlignedLba = 0;
> +  OptimalTransferBlocks = 1;
> +
> +  AllZeroEntry = -1;
> +  OldFreeEntry = -1;
> +
> +  BlockSize = BlockIo->Media->BlockSize;
> +  OffsetSpecified = (StartLba != 0);
> +  CopyMem (&PartNameUsed, PartName, sizeof (CHAR16) * StrSize
> (PartName));
> +
> +  GenerateGuid (&Guid);
> +
> +  // Creating a new partition
> +  if (!GptValid) {
> +    // Creating a GPT for the first time
> +    Status = TableCreateEmptyGpt ();
> +    if (!EFI_ERROR (Status)) {
> +      // Fill in the structures
> +      Status = PartitionGetGptTables (DiskIo, BlockIo);
> +    }
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +  }
> +
> +  Entry = PartitionFindPartitionByCriteria (PartName, 0, 0, SRC_BY_NAME);
> +  if (Entry) {
> +    Status = EFI_INVALID_PARAMETER;
> +    PrintErr (L"Partition with this name already exists", Status);
> +    return Status;
> +  }
> +  HighSeen     = PrimaryHeader->FirstUsableLBA - 1;
> +
> +  if (StartLba) {
> +    //
> +    // if offset is specified, compute the start and end blocks
> +    //
> +    StartBlock = StartLba;
> +    //
> +    // StartBlock should be aligned to OptimalTransferBlocks, the least
> common multiple of:
> +    // a). the physical block boundary, if any
> +    // b). the optimal transfer length granularity, if any
> +    //
> +    if (StartBlock < LowestAlignedLba) {
> +      StartBlock = LowestAlignedLba;
> +    } else {
> +      while (((StartBlock - LowestAlignedLba) % OptimalTransferBlocks) != 0) {
> +        StartBlock++;
> +      }
> +    }
> +
> +    if (StartBlock < PrimaryHeader->FirstUsableLBA ||
> +        StartBlock > PrimaryHeader->LastUsableLBA) {
> +      //
> +      // Offset specified is too large
> +      //
> +      Status = EFI_INVALID_PARAMETER;
> +      PrintErr (L"Specified offset is too large", EFI_INVALID_PARAMETER);
> +      goto Exit;
> +    }
> +
> +    SizeInBytes = MultU64x32 (SizeInMegabytes, (1024 * 1024));
> +    if (SizeInBytes < SizeInMegabytes || SizeInBytes == 0) {
> +      //
> +      // If size is not specified or too large,
> +      // try to make the partition as big as it can be
> +      //
> +      BlocksToAllocate = EndBlock = SizeInBytes = 0xffffffffffffffff;
> +    } else {
> +      BlocksToAllocate = DivU64x32 (SizeInBytes, BlockSize);
> +      EndBlock = StartBlock + BlocksToAllocate - 1;
> +      if (EndBlock > PrimaryHeader->LastUsableLBA) {
> +        EndBlock = PrimaryHeader->LastUsableLBA;
> +        BlocksToAllocate = EndBlock - StartBlock + 1;
> +      }
> +    }
> +  }
> +
> +  for (i = 0; i < PrimaryHeader->NumberOfPartitionEntries; i++) {
> +    Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + i *
> PrimaryHeader->SizeOfPartitionEntry);
> +    if (!CompareGuid (&Entry->PartitionTypeGUID,
> &gEfiPartTypeUnusedGuid)) {
> +
> +      //
> +      // Type not null, so it's allocated
> +      //
> +      if (Entry->EndingLBA > HighSeen) {
> +        HighSeen = Entry->EndingLBA;
> +      }
> +      if (OffsetSpecified) {
> +        //
> +        // make sure new partition does not overlap with existing partitions
> +        //
> +        if (Entry->StartingLBA <= StartBlock &&
> +            StartBlock <= Entry->EndingLBA) {
> +          //
> +          // starting block is inside an existing partition
> +          //
> +          Status = EFI_INVALID_PARAMETER;
> +          PrintErr (L"Starting block is inside an existing partition", Status);
> +          goto Exit;
> +        }
> +        if ((Entry->StartingLBA <= EndBlock &&
> +             EndBlock <= Entry->EndingLBA) ||
> +            (StartBlock <= Entry->StartingLBA &&
> +             Entry->StartingLBA <= EndBlock) ||
> +            (StartBlock <= Entry->EndingLBA &&
> +             Entry->EndingLBA <= EndBlock)) {
> +          //
> +          // new partition overlaps with an existing partition
> +          // readjust new partition size to avoid overlapping
> +          //
> +          EndBlock = Entry->StartingLBA - 1;
> +          if (EndBlock < StartBlock) {
> +            Status = EFI_INVALID_PARAMETER;
> +            PrintErr (L"Cannot readjust new partition size - overlapping", Status);
> +            goto Exit;
> +          } else {
> +            BlocksToAllocate = EndBlock - StartBlock + 1;
> +          }
> +        }
> +      }
> +    } else {
> +      p = (UINT8 *)(Entry);
> +      AllZeros = TRUE;
> +      for (j = 0; j < sizeof (EFI_PARTITION_ENTRY); j++) {
> +        if (p[j] != 0) {
> +          AllZeros = FALSE;
> +        }
> +      }
> +      if (AllZeros) {
> +        if (AllZeroEntry == -1) {
> +          AllZeroEntry = i;
> +        }
> +      } else if (OldFreeEntry == -1) {
> +        OldFreeEntry = i;
> +      }
> +    }
> +  }
> +
> +  //
> +  // AllZeroEntry - if not -1, is pointer to a never before used entry (free)
> +  // OldFreeEntry - if not -1, is pointer to some pre-used free entry
> +  //
> +  if ((AllZeroEntry == -1) && (OldFreeEntry == -1)) {
> +    //
> +    // TABLE IS FULL!!
> +    //
> +    Status = EFI_OUT_OF_RESOURCES;
> +    PrintErr (L"Table is full", Status);
> +    goto Exit;
> +  }
> +
> +  if (OffsetSpecified) {
> +    //
> +    // the user haven't specified the new partition size and we haven't
> +    // run into any partition that will limit the size of this new partition.
> +    // So, use the max it can
> +    //
> +    if (BlocksToAllocate == -1) {
> +      EndBlock = PrimaryHeader->LastUsableLBA;
> +      BlocksToAllocate = EndBlock - StartBlock + 1;
> +    }
> +  } else {
> +    //
> +    // Because HighSeen is the last LBA of the used blocks, let HighSeen align
> to the least common multiple of:
> +    // a). the physical block boundary, if any
> +    // b). the optimal transfer length granularity, if any
> +    //
> +    if (HighSeen + 1 < LowestAlignedLba) {
> +      HighSeen = LowestAlignedLba - 1;
> +    } else {
> +      while (((HighSeen + 1 - LowestAlignedLba) % OptimalTransferBlocks) !=
> 0) {
> +        HighSeen++;
> +      }
> +    }
> +
> +    if (PrimaryHeader->LastUsableLBA <= HighSeen) {
> +      Status = EFI_OUT_OF_RESOURCES;
> +      PrintErr (L"Disk has no free blocks (FULL) cannot create", Status);
> +      goto Exit;
> +    }
> +    //
> +    // [HighSeen+1 ... LastUsableLBA] is available...
> +    // avail = (LastUsableLBA - (HighSeen+1)) + 1 => LastUsabbleLBA -
> HighSeen
> +    //
> +    AvailBlocks = PrimaryHeader->LastUsableLBA - HighSeen;
> +
> +    SizeInBytes = MultU64x32 (SizeInMegabytes, (1024 * 1024));
> +    if (SizeInBytes < SizeInMegabytes) {
> +      //
> +      // overflow, force a very big answer
> +      //
> +      SizeInBytes = 0xffffffffffffffff;
> +    }
> +
> +    if  ((SizeInBytes == 0) ||
> +         (SizeInBytes > (MultU64x32 (AvailBlocks, BlockSize)))) {
> +      //
> +      // User asked for zero, or for more than we've got,
> +      // so give them all that is left
> +      //
> +      BlocksToAllocate = AvailBlocks;
> +
> +    } else {
> +
> +      //
> +      // We would have to have a BlockSize > 1mb for Remainder to
> +      // not be 0.  Since we cannot actually test this case, we
> +      // ingore it...
> +      //
> +      BlocksToAllocate = DivU64x32 (SizeInBytes, BlockSize);
> +
> +    }
> +  }
> +
> +  //
> +  // We have a name
> +  // We have a type guid
> +  // We have a size in blocks
> +  // We have an attribute mask
> +  //
> +
> +  if (BlocksToAllocate < ((1024 * 1024) / BlockSize)) {
> +    Status = EFI_OUT_OF_RESOURCES;
> +    PrintErr (L"Partition is too small to be created", Status);
> +    goto Exit;
> +  }
> +
> +  if (GPT_DEBUG_LEVEL) {
> +    Print (L"Requested SizeInMegaBytes = %ld\n", SizeInMegabytes);
> +    Print (L"Resulting size in Blocks = %ld\n", BlocksToAllocate);
> +    Print (L"Results size in Bytes = %ld\n", MultU64x32 (BlocksToAllocate,
> BlockSize));
> +  }
> +
> +  if (AllZeroEntry != -1) {
> +    Slot = AllZeroEntry;
> +  } else {
> +    Slot = OldFreeEntry;
> +  }
> +
> +  GenerateGuid (&PartitionIdGuid);
> +  Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Slot *
> PrimaryHeader->SizeOfPartitionEntry);
> +
> +  CopyMem (&Entry->PartitionTypeGUID, &PartTypeGuid, sizeof
> (EFI_GUID));
> +  CopyMem (&Entry->UniquePartitionGUID, &PartitionIdGuid, sizeof
> (EFI_GUID));
> +  if (OffsetSpecified) {
> +    PartEntry[Slot].StartingLBA = StartBlock;
> +    PartEntry[Slot].EndingLBA = EndBlock;
> +  } else {
> +    PartEntry[Slot].StartingLBA = HighSeen + 1;
> +    PartEntry[Slot].EndingLBA = HighSeen + BlocksToAllocate;
> +  }
> +
> +  if (!(((Entry->EndingLBA - Entry->StartingLBA) + 1) == BlocksToAllocate)) {
> +    PrintErr (L"Wrong Size for new partiton", EFI_INVALID_PARAMETER);
> +    goto Exit;
> +  }
> +
> +  if ((Entry->StartingLBA < PrimaryHeader->FirstUsableLBA) ||
> +      (Entry->EndingLBA > PrimaryHeader->LastUsableLBA)) {
> +    PrintErr (L"New Partition out of bounds", EFI_INVALID_PARAMETER);
> +    goto Exit;
> +  }
> +
> +  Entry->Attributes = Attributes;
> +  CopyMem (&(Entry->PartitionName[0]), PartName,
> MAX_PARTITION_NAME_LENGTH * sizeof (CHAR16));
> +
> +  DiskSizeBlocks = BlockIo->Media->LastBlock + 1;
> +  if (DiskSizeBlocks > 0xffffffff) {
> +    DiskSizeBlocks = 0xffffffff;
> +  }
> +
> +  Status = WriteGPT ();
> +
> +  if (EFI_ERROR (Status)) {
> +    PrintErr (L"Attempt to Write out partition table failed", Status);
> +  }
> +
> + Exit:
> +  return Status;
> +}
> +
> +/**
> +  Modifiy a partition based on parameters.
> +
> +  @param  Entry      Pointer to an existing partition
> +  @param  Params     Parameters to be modified
> +  @param  Flags      Which parameter is to be modified
> +
> +  @return EFI_SUCCESS  Successfully modified the partition
> +  @return other        Failed to modify a partition
> +
> +**/
> +
> +EFI_STATUS
> +PartitionGptModifyPartition (
> +  IN EFI_PARTITION_ENTRY  *Entry,
> +  IN MOD_PARAMS           *Params,
> +  IN MOD_FLAGS            Flags
> +  )
> +{
> +  EFI_STATUS Status;
> +
> +  ASSERT (Entry);
> +
> +  Status = EFI_INVALID_PARAMETER;
> +
> +  switch (Flags) {
> +    case MOD_DELETE:
> +      ZeroMem (Entry, sizeof (EFI_PARTITION_ENTRY));
> +      break;
> +    case MOD_ATTR:
> +      Entry->Attributes = Params->Attributes;
> +      break;
> +    case MOD_TYPE:
> +      Entry->PartitionTypeGUID = Params->PartTypeGuid;
> +      break;
> +    case MOD_RENAME:
> +      StrCpy (Entry->PartitionName, Params->NewName);
> +      break;
> +    default:
> +      PrintErr (L"Unknown modification flag(s)", Status);
> +      return Status;
> +  }
> +
> +  return WriteGPT ();
> +}
> +
> +EFI_KNOWN_PARTITION_TYPE *PartitionGetKnownType (
> +  IN UINTN                Index,
> +  IN OUT OPTIONAL UINTN   *NumEntries
> +  )
> +{
> +  if (NumEntries) {
> +    *NumEntries = ARRAY_SIZE (PartitionTypes);
> +  }
> +  if (Index > ARRAY_SIZE (PartitionTypes)) {
> +    return NULL;
> +  }
> +
> +  return &PartitionTypes[Index];
> +}
> +
> diff --git a/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> new file mode 100644
> index 000000000000..048377d883e7
> --- /dev/null
> +++ b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> @@ -0,0 +1,188 @@
> +/*
> + *  BSD LICENSE
> + *
> + *  Copyright(c) 2016 Broadcom.  All rights reserved.
> + *
> + *  Redistribution and use in source and binary forms, with or without
> + *  modification, are permitted provided that the following conditions
> + *  are met:
> + *
> + *    * Redistributions of source code must retain the above copyright
> + *      notice, this list of conditions and the following disclaimer.
> + *    * Redistributions in binary form must reproduce the above copyright
> + *      notice, this list of conditions and the following disclaimer in
> + *      the documentation and/or other materials provided with the
> + *      distribution.
> + *    * Neither the name of Broadcom nor the names of its
> + *      contributors may be used to endorse or promote products derived
> + *      from this software without specific prior written permission.
> + *
> + *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> CONTRIBUTORS
> + *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
> NOT
> + *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
> FITNESS FOR
> + *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
> COPYRIGHT
> + *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> INCIDENTAL,
> + *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> NOT
> + *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
> OF USE,
> + *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
> AND ON ANY
> + *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> TORT
> + *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
> THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> DAMAGE.
> + */
> +
> +/* GPT partitioner header file */
> +
> +#ifndef _GPTWORKER_H_
> +#define _GPTWORKER_H_
> +
> +#include <Uefi.h>
> +
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/ShellCommandLib.h>
> +#include <Library/ShellLib.h>
> +#include <Library/UefiLib.h>
> +#include <Library/UefiShellLib/UefiShellLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiRuntimeServicesTableLib.h>
> +#include <Library/PrintLib.h>
> +#include <Library/ShellCEntryLib.h>
> +#include <Library/HiiLib.h>
> +#include <Library/FileHandleLib.h>
> +#include <Protocol/DevicePath.h>
> +#include <Library/DevicePathLib.h>
> +#include <Protocol/BlockIo.h>
> +#include <Protocol/DiskIo.h>
> +#include <IndustryStandard/Mbr.h>
> +
> +typedef enum {
> +  MOD_NAME   = BIT0,
> +  MOD_ATTR   = BIT1,
> +  MOD_TYPE   = BIT2,
> +  MOD_DELETE = BIT3,
> +  MOD_RENAME = BIT4
> +} MOD_FLAGS;
> +
> +typedef struct {
> +  UINTN Attributes;
> +  EFI_GUID PartTypeGuid;
> +  CONST CHAR16 *PartName;
> +  CONST CHAR16 *NewName;
> +} MOD_PARAMS;
> +
> +typedef enum {
> +  SRC_BY_NAME = BIT0,
> +  SRC_BY_LBA  = BIT1,
> +  SRC_BY_NUM  = BIT2,
> +  SRC_ANY     = BIT3
> +} SEARCH_TYPE;
> +
> +#define MAX_PARTITION_NAME_LENGTH 36
> +#define ENTRY_DEFAULT             128
> +#define GPT_REVISION_1_0          0x00010000
> +
> +#define ARRAY_SIZE(x) \
> +  (sizeof(x) / sizeof((x)[0]))
> +
> +//
> +// Extract INT32 from char array
> +//
> +#define UNPACK_INT32(a) (INT32)( (((UINT8 *) a)[0] <<  0) |    \
> +                                 (((UINT8 *) a)[1] <<  8) |    \
> +                                 (((UINT8 *) a)[2] << 16) |    \
> +                                 (((UINT8 *) a)[3] << 24) )
> +
> +//
> +// Extract UINT32 from char array
> +//
> +#define UNPACK_UINT32(a) (UINT32)( (((UINT8 *) a)[0] <<  0) |    \
> +                                   (((UINT8 *) a)[1] <<  8) |    \
> +                                   (((UINT8 *) a)[2] << 16) |    \
> +                                   (((UINT8 *) a)[3] << 24) )
> +#define GPT_PART_UNKNOWN_STR     L"Unknown";
> +
> +//
> +// GPT Partition Entry Status
> +//
> +typedef struct {
> +  BOOLEAN OutOfRange;
> +  BOOLEAN Overlap;
> +  BOOLEAN OsSpecific;
> +} EFI_PARTITION_ENTRY_STATUS;
> +
> +typedef struct {
> +  CONST EFI_GUID TypeGuid;
> +  CONST CHAR16 *TypeName;
> +
> +} EFI_KNOWN_PARTITION_TYPE;
> +
> +EFI_KNOWN_PARTITION_TYPE *PartitionGetKnownType (
> +  IN UINTN Index,
> +  IN OUT OPTIONAL UINTN *NumEntries
> +  );
> +
> +EFI_STATUS
> +PartitionGetGptTables (
> +  IN  EFI_DISK_IO_PROTOCOL         *DiskIoProt,
> +  IN  EFI_BLOCK_IO_PROTOCOL        *BlockIoProt
> +  );
> +
> +UINTN
> +PartitionListGptEntries (
> +  VOID
> +  );
> +
> +VOID
> +PartitionPrintGptPartInfo (
> +  IN EFI_PARTITION_ENTRY *Entry
> +  );
> +
> +EFI_STATUS
> +GetPartitionTypeStr (
> +  IN EFI_GUID Guid,
> +  OUT CHAR16 *PartTypeStr,
> +  IN BOOLEAN NoGuidStr
> +  );
> +
> +
> +EFI_STATUS
> +PartitionGptClearAll (
> +  VOID
> +  );
> +
> +EFI_STATUS
> +PartitionGptCreatePartition (
> +  IN CONST CHAR16 *PartName,
> +  IN EFI_LBA StartLba,
> +  IN EFI_LBA PartitionSize,
> +  IN UINT64 Attributes,
> +  IN EFI_GUID PartTypeGuid);
> +
> +EFI_STATUS
> +PartitionGptModifyPartition (
> +  IN EFI_PARTITION_ENTRY *Entry,
> +  IN MOD_PARAMS *Params,
> +  IN MOD_FLAGS Flags
> +  );
> +
> +VOID
> +GptCleanupGlobals (
> +  VOID
> +  );
> +
> +EFI_PARTITION_ENTRY *
> +PartitionFindPartitionByCriteria (
> +  IN CONST CHAR16   *Name,
> +  IN EFI_LBA        StartLba,
> +  IN EFI_LBA        EndingLba,
> +  IN SEARCH_TYPE    SearchType);
> +
> +VOID
> +PrintErr (
> +  IN CONST CHAR16 *Message,
> +  IN EFI_STATUS Status
> +  );
> +
> +#endif //_GPTWORKER_H_
> diff --git
> a/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> new file mode 100644
> index 000000000000..b2d562443ae3
> --- /dev/null
> +++
> b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> @@ -0,0 +1,1267 @@
> +/*********************************************************
> **********************
> +Copyright (C) 2016, Marvell International Ltd. All rights reserved.
> +Copyright (C) 2016, Broadcom. All rights reserved.
> +
> +Redistribution and use in source and binary forms, with or without
> modification,
> +are permitted provided that the following conditions are met:
> +
> +* Redistributions of source code must retain the above copyright notice,
> +  this list of conditions and the following disclaimer.
> +
> +* Redistributions in binary form must reproduce the above copyright
> +  notice, this list of conditions and the following disclaimer in the
> +  documentation and/or other materials provided with the distribution.
> +
> +* Neither the name of Marvell nor the names of its contributors may be
> +  used to endorse or promote products derived from this software without
> +  specific prior written permission.
> +
> +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> CONTRIBUTORS "AS IS" AND
> +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
> THE IMPLIED
> +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> PURPOSE ARE
> +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> CONTRIBUTORS BE LIABLE FOR
> +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> CONSEQUENTIAL DAMAGES
> +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
> OR SERVICES;
> +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
> CAUSED AND ON
> +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> TORT
> +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
> THE USE OF THIS
> +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +
> +*********************************************************
> **********************/
> +
> +#include "FatFormat.h"
> +#include
> <Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.h>
> +#include <Library/TimerLib.h>
> +
> +CONST CHAR16 gShellGptFileName[] = L"ShellCommand";
> +STATIC CONST CHAR16 gAppName[] = L"gpt";
> +EFI_HANDLE gShellGptHiiHandle = NULL;
> +
> +STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
> +  // Partition-related operations
> +  { L"clear", TypeFlag },                  // Clears all partitions
> +  { L"create", TypeFlag },                 // Creates a partition
> +  { L"delete", TypeFlag },                 // Deletes a partition
> +  { L"list", TypeFlag },                   // Lists all partitions
> +  { L"rename", TypeFlag },                 // Renames a partition
> +  { L"setattr", TypeFlag },                // Set attributes for a partition in partition
> table
> +  { L"settype", TypeFlag },
> +  { L"sync", TypeFlag },                   // Synchronizes either master or alternative
> partition table
> +  { L"typesinfo", TypeFlag },                 // Verifies correctness of master and
> alternative partition tables
> +                                              // BlockIo-related operations
> +  { L"read", TypeFlag },                   // Reads n bytes into memory address from
> a partition starting from a certain lba
> +  { L"readfile", TypeFlag },               // Same as above, but instead of store it in
> memory saves into a file system
> +  { L"write", TypeFlag },                  // Writes n bytes from memory into a
> partition starting from a certain lba
> +  { L"writefile", TypeFlag },              // Same as above, but instead of getting
> data from memory reads a file
> +  { L"info", TypeFlag },                   // Get information on a certain partition
> (startLba, lastLba, attributes)
> +  { L"fatformat", TypeFlag },              // FAT format of a partition
> +  { L"-type", TypeValue },                 // Set GUID type to either an arbitrary
> GUID, or to a GUID from a know partition type
> +  { L"-yes", TypeFlag },                   // Warn, but do not prompt on potentially
> destructive operations,
> +                                           // assume all YES. Potentially dangerous
> +  { L"-verbose", TypeFlag },               // Print additional information on the
> operation
> +  { L"-fat16", TypeFlag },                 // Do FAT16 format if possible (by default
> format is FAT32)
> +  { NULL, TypeMax }
> +};
> +
> +typedef enum {
> +  // Not requires presence
> +  CLEAR       = BIT0,
> +  CREATE      = BIT1,
> +  LIST        = BIT2,
> +  SYNC        = BIT3,
> +  TYPES_INFO  = BIT4,
> +
> +  // Requires presence
> +  DELETE      = BIT5,
> +  INFO        = BIT6,
> +  READ        = BIT7,
> +  READ_FILE   = BIT8,
> +  RENAME      = BIT9,
> +  SETATTR     = BIT10,
> +  SETTYPE     = BIT11,
> +  WRITE       = BIT12,
> +  WRITE_FILE  = BIT13,
> +  FAT_FORMAT  = BIT14,
> +} Flags;
> +
> +/**
> +  Return the file name of the help text file if not using HII.
> +
> +  @return The string pointer to the file name.
> +**/
> +CONST CHAR16 *
> +EFIAPI
> +ShellCommandGetManFileNameGpt (
> +  VOID
> +  )
> +{
> +
> +  return gShellGptFileName;
> +}
> +
> +/**
> +  Open a file for read or write
> +
> +  @param [in]  FilePath     The path to the file to be opened/created
> +  @param [out] FileHandle   The handle of the file on successful open/create
> +  @param [in]  WriteNeeded  Indicates that the file is being opened for
> write
> +
> +  @return EFI_SUCCESS    File opened/created successfully
> +  @return other          Failed to open/create the file
> +
> +**/
> +STATIC
> +EFI_STATUS
> +OpenAndPrepareFile (
> +  IN CHAR16                 *FilePath,
> +  OUT SHELL_FILE_HANDLE     *FileHandle,
> +  IN BOOLEAN                WriteNeeded
> +  )
> +{
> +  EFI_STATUS Status;
> +  UINT64 OpenMode;
> +
> +  OpenMode = EFI_FILE_MODE_READ;
> +
> +  if (WriteNeeded) {
> +    OpenMode |= EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE;
> +  }
> +
> +  Status = ShellOpenFileByName (FilePath, FileHandle, OpenMode, 0);
> +  if (EFI_ERROR (Status)) {
> +    ShellPrintHiiEx (-1, -1,
> +                     NULL, STRING_TOKEN (STR_GPT_ERROR),
> +                     gShellGptHiiHandle,
> +                     gAppName,
> +                     Status,
> +                     L"Cannot open file"
> +                    );
> +    return Status;
> +  }
> +
> +  Status = FileHandleSetPosition (*FileHandle, 0);
> +
> +  if (EFI_ERROR (Status)) {
> +    ShellPrintHiiEx (-1, -1,
> +                     NULL, STRING_TOKEN (STR_GPT_ERROR),
> +                     gShellGptHiiHandle,
> +                     gAppName,
> +                     Status,
> +                     "Cannot set file position to the first byte"
> +                    );
> +
> +    ShellCloseFile (FileHandle);
> +    return Status;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Print error using generic HII format string
> +
> +  @param [in]  Message     Error message to be displayed
> +  @param [in]  Status      Status from the previous operation
> +
> +**/
> +VOID
> +PrintErr (
> +  IN CONST CHAR16 *Message,
> +  IN EFI_STATUS Status
> +  )
> +{
> +  ShellPrintHiiEx (-1, -1,
> +                   NULL, STRING_TOKEN (STR_GPT_ERROR),
> +                   gShellGptHiiHandle,
> +                   gAppName,
> +                   Status,
> +                   Message
> +                  );
> +}
> +
> +/**
> +  Find out if this is a partitionable device by Device Path
> +
> +  @param [in]  DevicePath   Device path of the block device
> +
> +  @return TRUE    Block device is partitionable
> +  @return FALSE   Block device is not partitionable
> +
> +**/
> +
> +STATIC
> +BOOLEAN
> +IsPartitionableDevicePath (
> +  IN EFI_DEVICE_PATH        *DevicePath
> +  )
> +{
> +  UINTN PathSize;
> +  EFI_DEVICE_PATH *PathInstance;
> +  BOOLEAN Partitionable;
> +
> +  Partitionable = TRUE;
> +  while (DevicePath != NULL) {
> +    PathInstance = GetNextDevicePathInstance (&DevicePath, &PathSize);
> +
> +    while (!IsDevicePathEnd (PathInstance)) {
> +      if ((DevicePathType (PathInstance) == MEDIA_DEVICE_PATH)) {
> +        Partitionable = FALSE;
> +      }
> +
> +      PathInstance = NextDevicePathNode (PathInstance);
> +    }
> +  }
> +  return Partitionable;
> +}
> +
> +/**
> +  Prompt a user with HII prompt and get answer (Yes, or No)
> +
> +  @param [in]  HiiFormatStringId     ID of the HII string in the .uni file
> +
> +  @return EFI_SUCCESS    A user answered "Yes"
> +  @return EFI_ABORTED    A user answered "No"
> +
> +**/
> +STATIC
> +EFI_STATUS
> +GptPromptYesNo (
> +  IN CONST EFI_STRING_ID HiiFormatStringId
> +  )
> +{
> +  EFI_STATUS Status;
> +  VOID       *Response;
> +
> +  Status = ShellPromptForResponseHii (ShellPromptResponseTypeYesNo,
> HiiFormatStringId, gShellGptHiiHandle, &Response);
> +  if ((EFI_ERROR (Status)) || (*(SHELL_PROMPT_RESPONSE *)Response) !=
> ShellPromptResponseYes) {
> +    return EFI_ABORTED;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Format a size in human-readable format
> +
> +  @param [in]  Size         The size to be formatted
> +  @param [out] Buffer       Buffer receiving the format string
> +
> +  The size is formatted so that it represents a unit and a metric.
> +  Thus, for 1967128576 bytes it would be 1.8G;
> +  for 33554432 bytes it would be 32M, etc.
> +
> +**/
> +STATIC
> +VOID FormatSize (
> +  IN UINT64            Size,
> +  IN CHAR16            *Buffer
> +  )
> +{
> +#define MAX_SIZE_BUF_SIZE 32
> +  UINT64            Base;
> +  UINT64            Frac;
> +  CHAR16            Metric;
> +
> +  Metric = L'B';
> +  Frac = 0;
> +  if (Size < SIZE_1KB) {
> +    Base = Size;
> +  } else if (Size < SIZE_1MB) {
> +    Base = Size / SIZE_1KB;
> +    Frac = ((Size % SIZE_1KB) * 10) >> 10;
> +    Metric = L'K';
> +  } else if (Size < SIZE_1GB) {
> +    Base = Size / SIZE_1MB;
> +    Frac = ((Size % SIZE_1MB) * 10) >> 20;
> +    Metric = L'M';
> +  } else if (Size < SIZE_1TB) {
> +    Base = Size / SIZE_1GB;
> +    Frac = ((Size % SIZE_1GB) * 10) >> 30;
> +    Metric = L'G';
> +  } else {
> +    Base = Size / SIZE_1TB;
> +    Frac = ((Size % SIZE_1TB) * 10) >> 40;
> +    Metric = L'T';
> +  }
> +  if (Frac) {
> +    UnicodeSPrint (Buffer, MAX_SIZE_BUF_SIZE, L"%d.%d%c", Base, Frac,
> Metric);
> +  } else {
> +    UnicodeSPrint (Buffer, MAX_SIZE_BUF_SIZE, L"%d%c", Base, Metric);
> +  }
> +}
> +
> +/**
> +  Find and print a table of all partitionable devices
> +
> +  @return EFI_SUCCESS           Successfully obtained a list
> +  @return EFI_OUT_OF_RESOURCES  Could not allocate memory
> +  @return other                 Error obtaining the list of devices
> +
> +**/
> +
> +STATIC
> +EFI_STATUS
> +FindAndPrintPartitionableDevices (
> +  VOID
> +  )
> +{
> +  UINTN Index;
> +  IN EFI_HANDLE   *HandlePointer;
> +  UINTN           HandleCount;
> +  UINTN           DevCount;
> +  EFI_STATUS      Status;
> +  BOOLEAN         FirstTime;
> +  CHAR16          *BufferForSize;
> +
> +  Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid,
> NULL, &HandleCount, &HandlePointer);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  DevCount = 0;
> +  FirstTime = TRUE;
> +  BufferForSize = NULL;
> +
> +  for (Index = 0; Index < HandleCount; Index++) {
> +    EFI_DEVICE_PATH       *DevicePath;
> +    CONST CHAR16          *MapPath;
> +    CHAR16                *Match;
> +    EFI_BLOCK_IO          *BlkIo;
> +    EFI_DISK_IO           *DiskIo;
> +
> +    Status = gBS->HandleProtocol (HandlePointer[Index],
> &gEfiBlockIoProtocolGuid, (VOID **)&BlkIo);
> +    if (EFI_ERROR (Status)) {
> +      continue;
> +    }
> +
> +    DevicePath = DevicePathFromHandle (HandlePointer[Index]);
> +    if (!IsPartitionableDevicePath (DevicePath)) {
> +      continue;
> +    }
> +    MapPath = gEfiShellProtocol->GetMapFromDevicePath (&DevicePath);
> +    if (MapPath == NULL) {
> +      continue;
> +    }
> +
> +    Status = gBS->HandleProtocol (HandlePointer[Index],
> &gEfiDiskIoProtocolGuid, (VOID **)&DiskIo);
> +    if (EFI_ERROR (Status)) {
> +      continue;
> +    }
> +
> +    Match = StrStr (MapPath, L";BLK");
> +    if (Match) {
> +      MapPath = Match;
> +      MapPath++;
> +    }
> +
> +    if (FirstTime) {
> +      BufferForSize = AllocateZeroPool (MAX_SIZE_BUF_SIZE * sizeof
> (CHAR16));
> +      if (BufferForSize == NULL) {
> +        Status = EFI_OUT_OF_RESOURCES;
> +        PrintErr (L"Could not allocate memory for size buffer\n", Status);
> +        return Status;
> +      }
> +      Print (L" Device\t     Size  Comments\n");
> +      Print (L" ------   -------  ------------------------------------------------------------
> \n");
> +      FirstTime = FALSE;
> +    }
> +    GptCleanupGlobals ();
> +    FormatSize (MultU64x32 (BlkIo->Media->LastBlock + 1, BlkIo->Media-
> >BlockSize), BufferForSize);
> +    ShellPrintHiiEx (-1, -1,
> +                     NULL, STRING_TOKEN (STR_GPT_LIST_DEVS),
> +                     gShellGptHiiHandle,
> +                     MapPath,
> +                     BufferForSize);
> +    if (BlkIo->Media->ReadOnly) {
> +      Print (L"Read-Only! ");
> +    }
> +    if (!BlkIo->Media->MediaPresent) {
> +      Print (L"No Media! ");
> +    }
> +    if (!EFI_ERROR (PartitionGetGptTables (DiskIo, BlkIo))) {
> +      Print (L"Valid GPT. ");
> +    }
> +    if (BlkIo->Media->RemovableMedia) {
> +      Print (L"Removable device.");
> +    }
> +    Print (L"\n");
> +    DevCount++;
> +  }
> +  Print (L"\r\n");
> +  if (DevCount) {
> +    Print (L"%d potentially partitionable device(s) found\n", DevCount);
> +  } else {
> +    Print (L"No potentially partitionable device(s) found\n");
> +  }
> +
> +  GptCleanupGlobals ();
> +  SHELL_FREE_NON_NULL (BufferForSize);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +SHELL_STATUS
> +EFIAPI
> +ShellCommandRunGpt (
> +  IN EFI_HANDLE             ImageHandle,
> +  IN EFI_SYSTEM_TABLE       *SystemTable
> +  )
> +{
> +  EFI_STATUS                Status;
> +  LIST_ENTRY                *CheckPackage;
> +  EFI_PHYSICAL_ADDRESS      Address;
> +  EFI_PHYSICAL_ADDRESS      Offset;
> +  UINT64                    PartAttributes;
> +  EFI_GUID                  PartTypeGuid;
> +  SHELL_FILE_HANDLE         FileHandle;
> +  UINT64                    ByteCount;
> +  UINT64                    FileSize;
> +  UINTN                     I;
> +  UINT8                     *Buffer;
> +  UINT8                     *FileBuffer;
> +
> +  CHAR16                    *ProblemParam;
> +  CHAR16                    *FilePath;
> +  CONST CHAR16              *AddressStr;
> +  CONST CHAR16              *OffsetStr;
> +  CONST CHAR16              *PartName;
> +  CONST CHAR16              *NewPartName;
> +  CONST CHAR16              *AttrStr;
> +  CONST CHAR16              *GuidStr;
> +  CONST CHAR16              *VolumeName;
> +  CONST CHAR16              *LengthStr;
> +  CONST CHAR16              *FileStr;
> +
> +  BOOLEAN                   AddrFlag;
> +  BOOLEAN                   LengthFlag;
> +  BOOLEAN                   FileFlag;
> +  BOOLEAN                   GuidFlag;
> +  BOOLEAN                   OffsetFlag;
> +  BOOLEAN                   PartNameFlag;
> +  BOOLEAN                   NewPartNameFlag;
> +  BOOLEAN                   AttrFlag;
> +
> +  UINTN                     Flag;
> +  UINTN                     CheckFlag;
> +
> +  CONST CHAR16              *BlockName;
> +
> +  EFI_DEVICE_PATH_PROTOCOL  *DevPath;
> +  EFI_BLOCK_IO_PROTOCOL     *BlockIo;
> +  EFI_DISK_IO_PROTOCOL      *DiskIo;
> +  EFI_HANDLE                BlockIoHandle;
> +  MOD_PARAMS                ModParams;
> +  EFI_PARTITION_ENTRY       *Entry;
> +
> +  UINTN                     NumKnownPartTypesEntries;
> +
> +  BOOLEAN                   TableNotEmpty;
> +  BOOLEAN                   GptIsValid;
> +  BOOLEAN                   NoPrompt;
> +  BOOLEAN                   Quiet;
> +  BOOLEAN                   ForceFat16;
> +
> +  UINT64                    TimeStampB;
> +  UINT64                    TimeStampE;
> +  UINT64                    SpeedKB;
> +  UINT64                    Freq;
> +
> +  // Initialization
> +  Address = Offset = 0;
> +  PartAttributes = Flag = 0;
> +  ZeroMem (&PartTypeGuid, sizeof (EFI_GUID));
> +  FileHandle = NULL;
> +  Buffer = FileBuffer = NULL;
> +  AddressStr = OffsetStr = PartName = NewPartName = AttrStr = GuidStr =
> +    VolumeName = LengthStr = FileStr = NULL;
> +  AddrFlag = FileFlag = GuidFlag = NewPartNameFlag = AttrFlag = FALSE;
> +  LengthFlag = OffsetFlag = PartNameFlag = TRUE;
> +  NoPrompt = ForceFat16 = FALSE;
> +  Quiet = TRUE;
> +  TimeStampB = 0;
> +  TimeStampE = 0;
> +  GptIsValid = FALSE;
> +
> +  // Parse Shell command line
> +  Status = ShellInitialize ();
> +  if (EFI_ERROR (Status)) {
> +    PrintErr (L"Cannot initialize Shell", Status);
> +    ASSERT_EFI_ERROR (Status);
> +    return SHELL_ABORTED;
> +  }
> +
> +  Status = ShellCommandLineParse (ParamList, &CheckPackage,
> &ProblemParam, TRUE);
> +  if (EFI_ERROR (Status)) {
> +    PrintErr (L"Error while parsing command line", Status);
> +    return SHELL_ABORTED;
> +  }
> +
> +  NoPrompt = ShellCommandLineGetFlag (CheckPackage, L"-yes");
> +  Quiet = !ShellCommandLineGetFlag (CheckPackage, L"-verbose");
> +  ForceFat16 = ShellCommandLineGetFlag (CheckPackage, L"-fat16");
> +
> +  Freq = GetPerformanceCounterProperties (NULL, NULL);
> +
> +  // Check flags provided by user
> +  Flag |= (ShellCommandLineGetFlag (CheckPackage, L"clear") << 0);
> +  Flag |= (ShellCommandLineGetFlag (CheckPackage, L"create") << 1);
> +  Flag |= (ShellCommandLineGetFlag (CheckPackage, L"list") << 2);
> +  Flag |= (ShellCommandLineGetFlag (CheckPackage, L"sync") << 3);
> +  Flag |= (ShellCommandLineGetFlag (CheckPackage, L"typesinfo") << 4);
> +  Flag |= (ShellCommandLineGetFlag (CheckPackage, L"delete") << 5);
> +  Flag |= (ShellCommandLineGetFlag (CheckPackage, L"info") << 6);
> +  Flag |= (ShellCommandLineGetFlag (CheckPackage, L"read") << 7);
> +  Flag |= (ShellCommandLineGetFlag (CheckPackage, L"readfile") << 8);
> +  Flag |= (ShellCommandLineGetFlag (CheckPackage, L"rename") << 9);
> +  Flag |= (ShellCommandLineGetFlag (CheckPackage, L"setattr") << 10);
> +  Flag |= (ShellCommandLineGetFlag (CheckPackage, L"settype") << 11);
> +  Flag |= (ShellCommandLineGetFlag (CheckPackage, L"write") << 12);
> +  Flag |= (ShellCommandLineGetFlag (CheckPackage, L"writefile") << 13);
> +  Flag |= (ShellCommandLineGetFlag (CheckPackage, L"fatformat") << 14);
> +
> +  PartitionGetKnownType ((UINTN)(-1), &NumKnownPartTypesEntries);
> +
> +  if (Flag & TYPES_INFO) {
> +    UINTN Index;
> +
> +    Print (L"  No\t%-36s\tGUID\r\n", L"Type name");
> +    Print (L" ----   ----------------------------------      ------------------------------------
> \n");
> +    for (Index = 0; Index < NumKnownPartTypesEntries; Index++) {
> +      EFI_KNOWN_PARTITION_TYPE *PartType;
> +
> +      PartType = PartitionGetKnownType (Index, NULL);
> +      if (PartType == NULL) {
> +        break;
> +      }
> +      Print (L" %3d\t%-36s\t%g\n", Index, PartType->TypeName, &PartType-
> >TypeGuid);
> +    }
> +    if (Flag == TYPES_INFO) {
> +      return SHELL_SUCCESS;
> +    }
> +  }
> +
> +  // Start parsing the command.
> +  BlockName = ShellCommandLineGetRawValue (CheckPackage, 1);
> +  if (BlockName == NULL) {
> +    if (Flag & LIST) {
> +      Status = FindAndPrintPartitionableDevices ();
> +      if (EFI_ERROR (Status)) {
> +        PrintErr (L"Error getting list of partitionable devices", Status);
> +        goto CleanUp;
> +      }
> +      return Status;
> +    }
> +    PrintErr (L"Missing block device name", EFI_INVALID_PARAMETER);
> +    return SHELL_INVALID_PARAMETER;
> +  }
> +
> +  // Find device handle by mapped name
> +  if (gEfiShellProtocol->GetDevicePathFromMap (BlockName) == NULL) {
> +    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
> gShellGptHiiHandle, gAppName, BlockName);
> +    Status = SHELL_INVALID_PARAMETER;
> +  } else {
> +    DevPath = (EFI_DEVICE_PATH_PROTOCOL *)gEfiShellProtocol-
> >GetDevicePathFromMap (BlockName);
> +    if (gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &DevPath, NULL)
> == EFI_NOT_FOUND) {
> +      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN
> (STR_GEN_MAP_PROTOCOL), gShellGptHiiHandle, gAppName, BlockName,
> L"BlockIo");
> +      Status = SHELL_INVALID_PARAMETER;
> +    }
> +  }
> +
> +  if (Status) {
> +    return SHELL_INVALID_PARAMETER;
> +  }
> +
> +  BlockIoHandle = 0;
> +
> +  Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid,
> (EFI_DEVICE_PATH_PROTOCOL **)&DevPath, &BlockIoHandle);
> +  if (EFI_ERROR (Status)) {
> +    goto CleanUp;
> +  }
> +
> +  Status = gBS->OpenProtocol (BlockIoHandle, &gEfiBlockIoProtocolGuid,
> (VOID **)&BlockIo, gImageHandle, NULL,
> EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> +  if (EFI_ERROR (Status)) {
> +    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN
> (STR_GEN_MAP_PROTOCOL), gShellGptHiiHandle, gAppName, BlockName,
> L"BlockIo");
> +    goto CleanUp;
> +  }
> +
> +  Status = gBS->HandleProtocol (
> +    BlockIoHandle,
> +    &gEfiDiskIoProtocolGuid,
> +    (VOID **)&DiskIo
> +    );
> +  if (EFI_ERROR (Status)) {
> +    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN
> (STR_GEN_MAP_PROTOCOL), gShellGptHiiHandle, gAppName, BlockName,
> L"DiskIo");
> +    goto CleanUp;
> +  }
> +
> +  CheckFlag = Flag;
> +  for (I = 0; CheckFlag; CheckFlag >>= 1) {
> +    I += CheckFlag & 1;
> +    if (I > 1) {
> +      PrintErr (L"Too many flags", EFI_INVALID_PARAMETER);
> +      Status = SHELL_INVALID_PARAMETER;
> +      goto CleanUp;
> +    }
> +  }
> +
> +  if (Flag & SYNC) {
> +    // Let the Partition table driver know that
> +    // we want to reread the tables
> +    Status = gBS->ReinstallProtocolInterface (
> +      BlockIoHandle,
> +      &gEfiBlockIoProtocolGuid,
> +      BlockIo,
> +      BlockIo
> +      );
> +    Status = SHELL_SUCCESS;
> +    goto CleanUp;
> +  }
> +
> +  if (!IsPartitionableDevicePath (DevicePathFromHandle (BlockIoHandle))) {
> +    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
> gShellGptHiiHandle, gAppName, BlockName);
> +    Print (L"%s is not a raw block device\n", BlockName);
> +    Status = SHELL_INVALID_PARAMETER;
> +    goto CleanUp;
> +  }
> +
> +  if (!BlockIo->Media->MediaPresent) {
> +    PrintErr (L"Media is not present!\n", EFI_NO_MEDIA);
> +    Status = EFI_NO_MEDIA;
> +    goto CleanUp;
> +  }
> +
> +  // Preload GPT tables with validation
> +  Status = PartitionGetGptTables (DiskIo, BlockIo);
> +  if (EFI_ERROR (Status)) {
> +    BOOLEAN CanContinue;
> +
> +    CanContinue = (Flag & CREATE) || (Flag & CLEAR) || (Flag &
> FAT_FORMAT);
> +    if (Status != EFI_NOT_FOUND) {
> +      PrintErr (L"Unexpected error getting GPT tables", Status);
> +      goto CleanUp;
> +    } else {
> +      if (!CanContinue) {
> +        PrintErr (L"No GPT table found. Create first", Status);
> +        goto CleanUp;
> +      }
> +    }
> +  } else {
> +    GptIsValid = TRUE;
> +  }
> +
> +  // Do we have any partitions already?
> +  TableNotEmpty = (PartitionFindPartitionByCriteria (NULL, 0, 0, SRC_ANY) !=
> NULL);
> +
> +  Status = SHELL_INVALID_PARAMETER;
> +
> +  if ((Flag < LIST) ||
> +      (Flag & DELETE) ||
> +      (Flag > READ_FILE)
> +     ) {
> +    if (BlockIo->Media->ReadOnly) {
> +      PrintErr (L"Cannot write to a read-only device",
> EFI_INVALID_PARAMETER);
> +      Status = SHELL_INVALID_PARAMETER;
> +      goto CleanUp;
> +    }
> +  }
> +
> +  if (BlockIo->Media->RemovableMedia) {
> +    Print (L"%s is a removable device. Just a note\n", BlockName);
> +  }
> +
> +  switch (Flag) {
> +    case INFO:
> +      PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
> +      OffsetFlag = FALSE;
> +      LengthFlag = FALSE;
> +      break;
> +    case LIST:
> +    {
> +      UINTN NumEntries;
> +
> +      NumEntries = PartitionListGptEntries ();
> +      if (NumEntries == 0) {
> +        Print (L"GPT is valid on %s, but no partition(s) defined yet\r\nUse
> create command to create a GPT partition\n", BlockName);
> +      }
> +      Status = SHELL_SUCCESS;
> +      goto CleanUp;
> +      break;
> +    }
> +    case CLEAR:
> +      if (TableNotEmpty) {
> +        // Tell the user what he/she is doing...
> +        ShellPrintHiiEx (-1, -1,
> +                         NULL, STRING_TOKEN (STR_GPT_NOT_EMPTY),
> +                         gShellGptHiiHandle,
> +                         BlockName
> +                        );
> +      }
> +
> +      // Even if GPT tables do not exist, there might be something.
> +      // Warn the user and double sure it is the intention,
> +      // to prevent a user from bricking a device (JTAG would be needed to
> recover)
> +      // by overwriting an ATF boot device. However with NoPrompt on, the
> user is
> +      // responsible for operation because there is no confirmation (assuming
> yes on all queries).
> +      if ((NoPrompt) || (!GptPromptYesNo (STRING_TOKEN
> (STR_GPT_CLEAR_SURE)) &&
> +                         (!GptPromptYesNo (STRING_TOKEN
> (STR_GPT_ABSOLUTELY_SURE))))
> +         ) {
> +        PartitionGptClearAll ();
> +      }
> +      Status = SHELL_SUCCESS;
> +      goto CleanUp;
> +      break;
> +    case CREATE:
> +      PartName    = ShellCommandLineGetRawValue (CheckPackage, 2);
> +      OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 3);
> +      LengthStr   = ShellCommandLineGetRawValue (CheckPackage, 4);
> +      AttrStr     = ShellCommandLineGetRawValue (CheckPackage, 5);
> +      GuidStr     = ShellCommandLineGetValue    (CheckPackage, L"-type");
> +      GuidFlag = TRUE;
> +      break;
> +    case DELETE:
> +      PartName    = ShellCommandLineGetRawValue (CheckPackage, 2);
> +      LengthFlag  = FALSE;
> +      OffsetFlag = FALSE;
> +      break;
> +    case RENAME:
> +      PartName    = ShellCommandLineGetRawValue (CheckPackage, 2);
> +      NewPartName = ShellCommandLineGetRawValue (CheckPackage, 3);
> +      NewPartNameFlag = TRUE;
> +      LengthFlag = FALSE;
> +      OffsetFlag = FALSE;
> +      break;
> +    case SETATTR:
> +      PartName    = ShellCommandLineGetRawValue (CheckPackage, 2);
> +      AttrStr     = ShellCommandLineGetRawValue (CheckPackage, 3);
> +      AttrFlag    = TRUE;
> +      LengthFlag  = FALSE;
> +      OffsetFlag  = FALSE;
> +      break;
> +    case SETTYPE:
> +      PartName    = ShellCommandLineGetRawValue (CheckPackage, 2);
> +      GuidStr     = ShellCommandLineGetValue    (CheckPackage, L"-type");
> +      GuidFlag = TRUE;
> +      LengthFlag = FALSE;
> +      OffsetFlag = FALSE;
> +      break;
> +    case FAT_FORMAT:
> +      PartName     = ShellCommandLineGetRawValue (CheckPackage, 2);
> +      VolumeName   = ShellCommandLineGetRawValue (CheckPackage, 3);
> +      LengthFlag   = FALSE;
> +      OffsetFlag   = FALSE;
> +      PartNameFlag = (PartName != NULL);
> +      if (!PartNameFlag && TableNotEmpty) {
> +        // Tell the user what he/she is doing...
> +        ShellPrintHiiEx (-1, -1,
> +                         NULL, STRING_TOKEN (STR_GPT_NOT_EMPTY),
> +                         gShellGptHiiHandle,
> +                         BlockName
> +                        );
> +      }
> +      break;
> +      // Fall through
> +    case READ:
> +    case WRITE:
> +      AddressStr = ShellCommandLineGetRawValue (CheckPackage, 2);
> +      PartName  = ShellCommandLineGetRawValue (CheckPackage, 3);
> +      OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 4);
> +      LengthStr = ShellCommandLineGetRawValue (CheckPackage, 5);
> +      AddrFlag = TRUE;
> +      break;
> +    case READ_FILE:
> +      FileStr = ShellCommandLineGetRawValue (CheckPackage, 2);
> +      PartName  = ShellCommandLineGetRawValue (CheckPackage, 3);
> +      OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 4);
> +      LengthStr = ShellCommandLineGetRawValue (CheckPackage, 5);
> +      FileFlag = TRUE;
> +      break;
> +    case WRITE_FILE:
> +      FileStr = ShellCommandLineGetRawValue (CheckPackage, 2);
> +      PartName  = ShellCommandLineGetRawValue (CheckPackage, 3);
> +      OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 4);
> +      LengthFlag = FALSE;
> +      FileFlag = TRUE;
> +      break;
> +    default:
> +      PrintErr (L"Unsupported or missing command. Try \"help gpt\"",
> EFI_INVALID_PARAMETER);
> +      Status = SHELL_INVALID_PARAMETER;
> +      goto CleanUp;
> +  }
> +
> +  // Read address parameter
> +  if ((AddressStr == NULL) & AddrFlag) {
> +    PrintErr (L"No address parameter", EFI_INVALID_PARAMETER);
> +    goto CleanUp;
> +  } else if (AddrFlag) {
> +    Address = ShellHexStrToUintn (AddressStr);
> +    if (Address == (UINTN)(-1)) {
> +      PrintErr (L"Wrong address parameter", EFI_INVALID_PARAMETER);
> +      goto CleanUp;
> +    }
> +  }
> +
> +  if ((PartName == NULL) & PartNameFlag) {
> +    PrintErr (L"Missing partition name", EFI_INVALID_PARAMETER);
> +    goto CleanUp;
> +  } else if (PartNameFlag) {
> +    if (StrSize (PartName) > MAX_PARTITION_NAME_LENGTH) {
> +      PrintErr (L"Partition name is too long (max 36 chars)",
> EFI_INVALID_PARAMETER);
> +      goto CleanUp;
> +    }
> +  }
> +
> +  // Read offset parameter
> +  if ((OffsetStr == NULL) & OffsetFlag) {
> +    PrintErr (L"No offset Parameter", EFI_INVALID_PARAMETER);
> +    goto CleanUp;
> +  } else if (OffsetFlag) {
> +    Offset = ShellHexStrToUintn (OffsetStr);
> +    if (Offset < 0) {
> +      Print (L"%s: Wrong offset parameter: %s\n", gAppName, OffsetStr);
> +      goto CleanUp;
> +    }
> +  }
> +
> +  // Read length parameter
> +  if ((LengthStr == NULL) & LengthFlag) {
> +    PrintErr (L"No length parameter", EFI_INVALID_PARAMETER);
> +    goto CleanUp;
> +  } else if (LengthFlag) {
> +    ByteCount = (UINT64)ShellStrToUintn (LengthStr);
> +    if (ByteCount < 0) {
> +      Print (L"%s: Wrong length parameter %s!\n", gAppName, LengthStr);
> +      goto CleanUp;
> +    }
> +  }
> +
> +  if ((NewPartName == NULL) & NewPartNameFlag) {
> +    PrintErr (L"Missing name to be assigned to partition",
> EFI_INVALID_PARAMETER);
> +    goto CleanUp;
> +  } else if (NewPartNameFlag) {
> +    if (StrSize (NewPartName) > MAX_PARTITION_NAME_LENGTH) {
> +      PrintErr (L"Partition name is too long (max 36 chars)",
> EFI_INVALID_PARAMETER);
> +      goto CleanUp;
> +    }
> +  }
> +
> +  if ((AttrStr == NULL) & AttrFlag) {
> +    PrintErr (L"Missing attributes parameter", EFI_INVALID_PARAMETER);
> +    goto CleanUp;
> +  } else if (AttrStr) {
> +    PartAttributes = (UINT64)ShellStrToUintn (AttrStr);
> +  }
> +
> +  if ((GuidStr == NULL) & GuidFlag) {
> +    PrintErr (L"Missing partition type GUID parameter",
> EFI_INVALID_PARAMETER);
> +    goto CleanUp;
> +  } else if (GuidFlag) {
> +    Status = SHELL_INVALID_PARAMETER;
> +    if (InternalShellIsHexOrDecimalNumber (GuidStr, FALSE, TRUE, FALSE)) {
> +      UINTN Ordinal;
> +
> +      Ordinal = ShellStrToUintn (GuidStr);
> +      if (Ordinal < NumKnownPartTypesEntries) {
> +        PartTypeGuid = PartitionGetKnownType (Ordinal, NULL)->TypeGuid;
> +        Status = SHELL_SUCCESS;
> +      } else {
> +        ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
> gShellGptHiiHandle, gAppName, GuidStr);
> +        goto CleanUp;
> +      }
> +    } else {
> +      Status = ConvertStringToGuid (GuidStr, &PartTypeGuid);
> +      if ((EFI_ERROR (Status)) || (IsZeroGuid (&PartTypeGuid))) {
> +        ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
> gShellGptHiiHandle, gAppName, GuidStr);
> +        Status = SHELL_INVALID_PARAMETER;
> +        goto CleanUp;
> +      }
> +    }
> +  }
> +
> +  if (FileFlag) {
> +    // Read FilePath parameter
> +    if (FileStr == NULL) {
> +      PrintErr (L"No FilePath parameter", EFI_INVALID_PARAMETER);
> +      goto CleanUp;
> +    } else {
> +      FilePath = (CHAR16 *)FileStr;
> +      Status = ShellIsFile (FilePath);
> +      // When read file into flash, file doesn't have to exist
> +      if (EFI_ERROR (Status && !(Flag & READ_FILE))) {
> +        PrintErr (L"Wrong FilePath parameter", Status);
> +        Status = SHELL_INVALID_PARAMETER;
> +        goto CleanUp;
> +      }
> +    }
> +
> +    Status = OpenAndPrepareFile (FilePath, &FileHandle, ((Flag & READ_FILE)
> != 0));
> +    if (EFI_ERROR (Status)) {
> +      Print (L"Error %r while preparing file %s", Status, FilePath);
> +      goto CleanUp;
> +    }
> +
> +    // Get file size in order to check correctness at the end of transfer
> +    if (Flag & (WRITE_FILE)) {
> +      Status = FileHandleGetSize (FileHandle, &FileSize);
> +      if (EFI_ERROR (Status)) {
> +        PrintErr (L"Cannot get file size", Status);
> +        goto CleanUp;
> +      }
> +      ByteCount = (UINT64)FileSize;
> +    }
> +
> +    FileBuffer = AllocateZeroPool ((UINTN)ByteCount);
> +    if (FileBuffer == NULL) {
> +      PrintErr (L"Cannot allocate memory", EFI_OUT_OF_RESOURCES);
> +      Status = SHELL_OUT_OF_RESOURCES;
> +      goto Error_Close_File;
> +    }
> +
> +    // Read file content and store it in FileBuffer
> +    if (Flag & (WRITE_FILE)) {
> +      if (!Quiet) {
> +        Print (L"Reading %s...\r", FilePath);
> +      }
> +      Status = FileHandleRead (FileHandle, &ByteCount, FileBuffer);
> +      if (EFI_ERROR (Status)) {
> +        PrintErr (L"Read from file error", Status);
> +        goto Error_Free_Buffer;
> +      } else if (ByteCount != (UINTN)FileSize) {
> +        PrintErr (L"Not whole file read. Abort", EFI_DEVICE_ERROR);
> +        Status = SHELL_DEVICE_ERROR;
> +        goto Error_Free_Buffer;
> +      }
> +      if (!Quiet) {
> +        Print (L"Writing %s into device %s, partition %s...\n", FilePath,
> BlockName, PartName);
> +      }
> +    }
> +  }
> +
> +  Buffer = (UINT8 *)Address;
> +  if (FileFlag) {
> +    Buffer = FileBuffer;
> +  }
> +
> +  if (Flag > TYPES_INFO) {
> +    Entry = PartitionFindPartitionByCriteria (PartName, 0, 0, SRC_BY_NAME);
> +    if (!Entry && PartName && (InternalShellIsHexOrDecimalNumber
> (PartName, FALSE, TRUE, FALSE))) {
> +      Entry = PartitionFindPartitionByCriteria (PartName, 0, 0, SRC_BY_NUM);
> +    }
> +    if ((!Entry) && (PartNameFlag)) {
> +      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
> gShellGptHiiHandle, gAppName, PartName);
> +      Print (L"Could not find partition %s (case-sensitive). Make sure the name
> is spelled properly\n", PartName);
> +      Status = SHELL_NOT_FOUND;
> +      goto CleanUp;
> +    }
> +  }
> +
> +  switch (Flag) {
> +    case CREATE:
> +      if (!TableNotEmpty && !GptIsValid) {
> +        if (!NoPrompt) {
> +          // Ask a user to confirm re-init of the GPT if
> +          // It was not present before create was invoked
> +          if ((GptPromptYesNo (STRING_TOKEN (STR_GPT_CLEAR_SURE))) ||
> +            (GptPromptYesNo (STRING_TOKEN (STR_GPT_ABSOLUTELY_SURE))))
> {
> +            goto CleanUp;
> +          }
> +        }
> +      }
> +
> +      Status = PartitionGptCreatePartition (
> +        PartName,
> +        Offset,  // Lba. If 0, the next available is assumed
> +        ByteCount, // in MegaBytes. If 0 the whole remaining space is assumed
> +        PartAttributes,
> +        PartTypeGuid);
> +      break;
> +    case DELETE:
> +      ModParams.PartName = PartName;
> +      ShellPrintHiiEx (-1, -1,
> +                       NULL, STRING_TOKEN (STR_GPT_DELETE_WARNING),
> +                       gShellGptHiiHandle,
> +                       Entry->PartitionName
> +                      );
> +      if ((NoPrompt) || (!GptPromptYesNo (STRING_TOKEN
> (STR_GPT_ABSOLUTELY_SURE)))) {
> +        Status = PartitionGptModifyPartition (
> +          Entry, &ModParams, MOD_DELETE);
> +        if (EFI_ERROR (Status)) {
> +          PrintErr (L"Error deleting the partition", Status);
> +          goto CleanUp;
> +        }
> +        Status = SHELL_SUCCESS;
> +      } else {
> +        Status = SHELL_ABORTED;
> +      }
> +      break;
> +    case FAT_FORMAT:
> +    {
> +      EFI_LBA   StartingLBA;
> +      EFI_LBA   EndingLBA;
> +      CHAR8     LabelName[12];
> +      CHAR16    *FormatType;
> +
> +      if (VolumeName) {
> +        if (StrLen (VolumeName) > FAT_LABEL_LENGTH) {
> +          Status = EFI_INVALID_PARAMETER;
> +          PrintErr (L"The volume label is too long", Status);
> +          Status = SHELL_INVALID_PARAMETER;
> +          goto CleanUp;
> +        }
> +        UnicodeStrToAsciiStr (VolumeName, (CHAR8 *)LabelName);
> +      }
> +      ShellPrintHiiEx (-1, -1,
> +                       NULL, STRING_TOKEN (STR_GPT_FORMAT_WARNING),
> +                       gShellGptHiiHandle,
> +                       Entry ? Entry->PartitionName : BlockName
> +                      );
> +
> +      if ((NoPrompt) || (!GptPromptYesNo (STRING_TOKEN
> (STR_GPT_FORMAT_SURE)) &&
> +                         (!GptPromptYesNo (STRING_TOKEN
> (STR_GPT_ABSOLUTELY_SURE))))
> +         ) {
> +        StartingLBA = 0;
> +        EndingLBA = BlockIo->Media->LastBlock;
> +        if (Entry) {
> +          StartingLBA = Entry->StartingLBA;
> +          EndingLBA = Entry->EndingLBA;
> +        }
> +        FormatType = FAT32_FORMAT;
> +        if (ForceFat16) {
> +          UINT64 VolumeSectors;
> +
> +          FormatType = FAT16_FORMAT;
> +          VolumeSectors = DivU64x32 (
> +            MultU64x32 (
> +              EndingLBA - StartingLBA + 1, BlockIo->Media->BlockSize),
> +            FAT_SECTOR_SIZE);
> +          if (VolumeSectors > FAT16_MAX_SECTORS) {
> +            FormatType = FAT32_FORMAT;
> +            Print (L"Note: this volume will be formatted as FAT32 (too many
> sectors for FAT16)\n");
> +          }
> +        }
> +        if (!Quiet) {
> +          Print (L"Formatting %s to %s...\r", PartNameFlag ? Entry-
> >PartitionName : BlockName, FormatType);
> +        }
> +        Status = FatFormat (StartingLBA, EndingLBA, BlockIo, DiskIo,
> VolumeName ? LabelName : NULL, !ForceFat16);
> +        if (EFI_ERROR (Status)) {
> +          PrintErr (L"Error formatting the partition                 ", Status);
> +          goto CleanUp;
> +        } else if (!Quiet) {
> +          Print (L"%s successfully formatted to %s. Formatted size %llu MiB\n",
> +                 PartNameFlag ? Entry->PartitionName : BlockName,
> +                 FormatType,
> +                 MultU64x32 (EndingLBA - StartingLBA + 1, BlockIo->Media-
> >BlockSize) >> 20
> +                );
> +        }
> +      } else {
> +        Status = SHELL_ABORTED;
> +      }
> +    }
> +      break;
> +    case RENAME:
> +      ModParams.PartName = PartName;
> +      ModParams.NewName  = NewPartName;
> +      Status = PartitionGptModifyPartition (
> +        Entry, &ModParams, MOD_RENAME);
> +      break;
> +    case SETATTR:
> +      ModParams.Attributes = PartAttributes;
> +      Status = PartitionGptModifyPartition (
> +        Entry, &ModParams, MOD_ATTR);
> +      break;
> +    case SETTYPE:
> +      ModParams.PartTypeGuid = PartTypeGuid;
> +      Status = PartitionGptModifyPartition (
> +        Entry, &ModParams, MOD_TYPE);
> +      break;
> +    case INFO:
> +      PartitionPrintGptPartInfo (Entry);
> +      Status = SHELL_SUCCESS;
> +      break;
> +    case READ:
> +    case READ_FILE:
> +    case WRITE:
> +    case WRITE_FILE:
> +    {
> +      UINT64     MaxBytes;
> +      BOOLEAN    OpRead;
> +
> +      OpRead = ((Flag & READ) || (Flag & READ_FILE));
> +      MaxBytes = MultU64x32 (
> +        Entry->EndingLBA - Entry->StartingLBA,
> +        BlockIo->Media->BlockSize) +
> +        BlockIo->Media->BlockSize -
> +        MultU64x32 (Offset, BlockIo->Media->BlockSize);
> +      if (ByteCount > MaxBytes) {
> +        Status = EFI_INVALID_PARAMETER;
> +        ShellPrintHiiEx (-1, -1,
> +                         NULL, (OpRead) ?
> +                         STRING_TOKEN (STR_GPT_READ_BOUNDARY) :
> +                         STRING_TOKEN (STR_GPT_WRITE_BOUNDARY),
> +                         gShellGptHiiHandle,
> +                         gAppName,
> +                         Entry->PartitionName,
> +                         MaxBytes,
> +                         ByteCount
> +                        );
> +        Status = SHELL_INVALID_PARAMETER;
> +        goto CleanUp;
> +      }
> +
> +      TimeStampB = GetPerformanceCounter ();
> +      if (OpRead) {
> +        Status = DiskIo->ReadDisk (DiskIo,
> +                                   BlockIo->Media->MediaId,
> +                                   MultU64x32 (Offset + Entry->StartingLBA, BlockIo-
> >Media->BlockSize), ByteCount, Buffer);
> +      } else {
> +        Status = DiskIo->WriteDisk (DiskIo, BlockIo->Media->MediaId,
> +                                    MultU64x32 (Offset + Entry->StartingLBA, BlockIo-
> >Media->BlockSize), ByteCount, Buffer);
> +      }
> +    }
> +      break;
> +    default:
> +      Status = SHELL_INVALID_PARAMETER;
> +      PrintErr (L"Unknown command. Try \"help gpt\"",
> EFI_INVALID_PARAMETER);
> +      goto CleanUp;
> +  }
> +
> +  if (EFI_ERROR (Status)) {
> +    PrintErr (L"Error while performing transfer\n", Status);
> +    goto CleanUp;
> +  }
> +
> +  TimeStampE = ((GetPerformanceCounter () - TimeStampB) * 1000) / Freq;
> +  SpeedKB = TimeStampE ? (ByteCount / (TimeStampE / 1000)) >> 10 : 0;
> +
> +  switch (Flag) {
> +    case WRITE:
> +    case WRITE_FILE:
> +      if (!Quiet) {
> +        ShellPrintHiiEx (-1, -1,
> +                         NULL,
> +                         STRING_TOKEN (STR_GPT_WRITE_OK),
> +                         gShellGptHiiHandle,
> +                         ByteCount,
> +                         Offset,
> +                         Entry->PartitionName,
> +                         TimeStampE,
> +                         SpeedKB
> +                        );
> +      }
> +      break;
> +    case READ:
> +      if (!Quiet) {
> +        ShellPrintHiiEx (-1, -1,
> +                         NULL,
> +                         STRING_TOKEN (STR_GPT_READ_OK),
> +                         gShellGptHiiHandle,
> +                         ByteCount,
> +                         Offset,
> +                         Entry->PartitionName,
> +                         TimeStampE,
> +                         SpeedKB
> +                        );
> +      }
> +      break;
> +    case READ_FILE:
> +      Status = FileHandleWrite (FileHandle, &ByteCount, FileBuffer);
> +      if (EFI_ERROR (Status)) {
> +        ShellPrintHiiEx (-1, -1,
> +                         NULL,
> +                         STRING_TOKEN (STR_GPT_FILE_WRITE_FAIL),
> +                         gShellGptHiiHandle,
> +                         gAppName,
> +                         FilePath,
> +                         Status
> +                        );
> +        Status = SHELL_DEVICE_ERROR;
> +        goto Error_Free_Buffer;
> +      }
> +
> +      if (!Quiet) {
> +        ShellPrintHiiEx (-1, -1,
> +                         NULL,
> +                         STRING_TOKEN (STR_GPT_READFILE_OK),
> +                         gShellGptHiiHandle,
> +                         ByteCount,
> +                         Offset,
> +                         Entry->PartitionName,
> +                         FilePath,
> +                         TimeStampE,
> +                         SpeedKB
> +                        );
> +      }
> +      break;
> +  }
> +
> +  if (FileFlag) {
> +    SHELL_FREE_NON_NULL (FileBuffer);
> +    if (FileHandle != NULL) {
> +      ShellCloseFile (&FileHandle);
> +      FileHandle = NULL;
> +    }
> +  }
> +
> +  Status =  SHELL_SUCCESS;
> +
> + Error_Free_Buffer:
> +  SHELL_FREE_NON_NULL (FileBuffer);
> + Error_Close_File:
> +  if (FileHandle) {
> +    ShellCloseFile (&FileHandle);
> +  }
> + CleanUp:
> +  if (BlockIoHandle) {
> +    // By UEFI Spec blocks must be flushed
> +    BlockIo->FlushBlocks (BlockIo);
> +    gBS->CloseProtocol (BlockIoHandle, &gEfiBlockIoProtocolGuid,
> gImageHandle, NULL);
> +  }
> +
> +  GptCleanupGlobals ();
> +
> +  ShellCommandLineFreeVarList (CheckPackage);
> +
> +  if (EFI_ERROR (Status)) {
> +    Status = SHELL_ABORTED;
> +  }
> +
> +  return Status;
> +}
> +
> +EFI_STATUS
> +EFIAPI
> +ShellGptLibConstructor (
> +  IN EFI_HANDLE        ImageHandle,
> +  IN EFI_SYSTEM_TABLE  *SystemTable
> +  )
> +{
> +  gShellGptHiiHandle = NULL;
> +
> +  gShellGptHiiHandle = HiiAddPackages (
> +    &gShellGptHiiGuid, gImageHandle,
> +    UefiShellGptCommandLibStrings, NULL
> +    );
> +  if (gShellGptHiiHandle == NULL) {
> +    return EFI_DEVICE_ERROR;
> +  }
> +
> +  ShellCommandRegisterCommandName (
> +    gAppName, ShellCommandRunGpt, ShellCommandGetManFileNameGpt,
> 0,
> +    gAppName, TRUE, gShellGptHiiHandle, STRING_TOKEN
> (STR_GET_HELP_GPT)
> +    );
> +
> +  return EFI_SUCCESS;
> +}
> +
> +EFI_STATUS
> +EFIAPI
> +ShellGptLibDestructor (
> +  IN EFI_HANDLE        ImageHandle,
> +  IN EFI_SYSTEM_TABLE  *SystemTable
> +  )
> +{
> +
> +  if (gShellGptHiiHandle != NULL) {
> +    HiiRemovePackages (gShellGptHiiHandle);
> +  }
> +  return EFI_SUCCESS;
> +}
> diff --git
> a/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> new file mode 100644
> index 000000000000..9b3a6f56c9b7
> --- /dev/null
> +++
> b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> @@ -0,0 +1,74 @@
> +#
> +# Copyright (C) 2016, Marvell International Ltd. All rights reserved.
> +# Copyright (C) 2016, Broadcom. All rights reserved
> +#
> +# Redistribution and use in source and binary forms, with or without
> +# modification, are permitted provided that the following conditions are
> met:
> +#
> +# * Redistributions of source code must retain the above copyright notice,
> +# this list of conditions and the following disclaimer.
> +#
> +# * Redistributions in binary form must reproduce the above copyright
> +# notice, this list of conditions and the following disclaimer in the
> +# documentation and/or other materials provided with the distribution.
> +#
> +# * Neither the name of Marvell nor the names of its contributors may be
> +# used to endorse or promote products derived from this software without
> +# specific prior written permission.
> +#
> +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> CONTRIBUTORS "AS IS"
> +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> LIMITED TO, THE
> +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
> PARTICULAR PURPOSE ARE
> +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> CONTRIBUTORS BE LIABLE
> +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> CONSEQUENTIAL
> +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
> SUBSTITUTE GOODS OR
> +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
> HOWEVER
> +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
> STRICT LIABILITY,
> +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
> OUT OF THE USE
> +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> DAMAGE.
> +#
> +
> +[Defines]
> + INF_VERSION                = 0x00010006
> + BASE_NAME                  = UefiShellGptCommandLib
> + FILE_GUID                  = F62ACF25-0D15-22F5-E642-FFB6515E00D7
> + MODULE_TYPE                = UEFI_APPLICATION
> + VERSION_STRING             = 0.1
> + LIBRARY_CLASS              = NULL|UEFI_APPLICATION UEFI_DRIVER
> + CONSTRUCTOR                = ShellGptLibConstructor
> + DESTRUCTOR                 = ShellGptLibDestructor
> +
> +[Sources]
> + FatFormat.c
> + GptWorker.c
> + UefiShellGptCommandLib.c
> + UefiShellGptCommandLib.uni
> +
> +[Packages]
> + MdeModulePkg/MdeModulePkg.dec
> + MdePkg/MdePkg.dec
> + ShellPkg/ShellPkg.dec
> +
> +[LibraryClasses]
> + BaseLib
> + BaseMemoryLib
> + DebugLib
> + DevicePathLib
> + FileHandleLib
> + HiiLib
> + MemoryAllocationLib
> + PcdLib
> + ShellCommandLib
> + ShellLib
> + UefiBootServicesTableLib
> + UefiRuntimeServicesTableLib
> + UefiLib
> +
> +[Protocols]
> +  gEfiBlockIoProtocolGuid
> +  gEfiDevicePathProtocolGuid
> +  gEfiDiskIoProtocolGuid
> +
> +[Guids]
> + gShellGptHiiGuid
> + gEfiPartTypeUnusedGuid                        ## SOMETIMES_CONSUMES ## GUID
> diff --git
> a/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
> b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
> new file mode 100644
> index 000000000000..c0ad20a7f7cd
> --- /dev/null
> +++
> b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
> @@ -0,0 +1,113 @@
> +/*********************************************************
> **********************
> +Copyright (C) 2016 Marvell International Ltd. All rights reserved
> +Copyright (C) 2016, Broadcom. All rights reserved */
> +
> +Redistribution and use in source and binary forms, with or without
> modification,
> +are permitted provided that the following conditions are met:
> +
> +        * Redistributions of source code must retain the above copyright
> notice,
> +          this list of conditions and the following disclaimer.
> +
> +        * Redistributions in binary form must reproduce the above copyright
> +          notice, this list of conditions and the following disclaimer in the
> +          documentation and/or other materials provided with the distribution.
> +
> +        * Neither the name of Marvell nor the names of its contributors may be
> +          used to endorse or promote products derived from this software
> without
> +          specific prior written permission.
> +
> +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> CONTRIBUTORS "AS IS" AND
> +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
> THE IMPLIED
> +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> PURPOSE ARE
> +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> CONTRIBUTORS BE LIABLE FOR
> +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> CONSEQUENTIAL DAMAGES
> +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
> OR SERVICES;
> +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
> CAUSED AND ON
> +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> TORT
> +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
> THE USE OF THIS
> +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +
> +*********************************************************
> **********************/
> +
> +/=#
> +
> +#langdef   en-US "english"
> +
> +#string STR_GEN_PARAM_INV         #language en-US "%H%s%N: Invalid
> argument - '%H%s%N'\r\n"
> +#string STR_GEN_MAP_PROTOCOL      #language en-US "%H%s%N:
> Mapped device '%B%s%N' does not have protocol %B%s%N\r\n"
> +
> +#string STR_GPT_ERROR            #language en-US "%H%s%N: %r - %s\r\n"
> +#string STR_GPT_NOT_EMPTY        #language en-US "%H%s%N:
> WARNING!!! This device has valid GPT partition tables!\r\n"
> +#string STR_GPT_CLEAR_SURE       #language en-US "Are you sure you want
> to (re)inintialize GPT tables on this device? %BY%Nes, %BN%No "
> +#string STR_GPT_ABSOLUTELY_SURE  #language en-US "\r\nAre you ***
> ABSOLUTELY SURE *** you want to perform this operation ? %BY%Nes,
> %BN%No "
> +#string STR_GPT_FORMAT_WARNING   #language en-US "%H%s%N:
> WARNING!!! Formatting of this partition will destroy all data on it!\r\n"
> +#string STR_GPT_FORMAT_SURE      #language en-US "Are you sure you
> want to format this partition and destroy all data on it ? %BY%Nes, %BN%No
> "
> +#string STR_GPT_DELETE_WARNING   #language en-US "%H%s%N: Deleting
> of this partition will make data on it unreachable!\r\n"
> +#string STR_GPT_READ_BOUNDARY    #language en-US "%H%s%N: Attempt
> to read beyond %H%s%N partition boundary (can read upto %llu bytes from
> the given offset, requested %llu bytes)\r\n"
> +#string STR_GPT_WRITE_BOUNDARY   #language en-US "%H%s%N:
> Attempt to write beyond %H%s%N partition boundary (can write upto %llu
> bytes from the given offset, requested %llu bytes)\r\n"
> +#string STR_GPT_FILE_WRITE_FAIL  #language en-US "%H%s%N: Failed to
> write to the file %s, error %r\r\n"
> +
> +#string STR_GPT_WRITE_OK         #language en-US "Written %llu bytes at
> offset 0x%x, partition %s. Elapsed time %llums (%llu KB/s)\r\n"
> +#string STR_GPT_READ_OK          #language en-US "Read %llu bytes from
> offset 0x%x, partition %s. Elapsed time %llums (%llu KB/s)\r\n"
> +#string STR_GPT_READFILE_OK      #language en-US "Read %llu bytes from
> offset 0x%x, partition %s into file %s. Elapsed time %llums (%llu KB/s)\r\n"
> +#string STR_GPT_LIST_DEVS        #language en-US " %H%+6s%N  %+8s  "
> +
> +#string STR_GET_HELP_GPT         #language en-US ""
> +".TH gpt 0 "GPT partition manager."\r\n"
> +".SH NAME\r\n"
> +"Manages GPT partitions on a block device.\r\n"
> +".SH SYNOPSIS\r\n"
> +" \r\n"
> +"gpt [read | readfile | write | writefile | list | info | clear |\r\n"
> +"     create | delete | rename | setattrs | sync | fatformat | -typesinfo | -
> yes] \r\n"
> +"This is a complex utility. Please see examples for usage info\r\n"
> +".SH OPTIONS\r\n"
> +" \r\n"
> +"   Device        - Block device to be used for the operation\r\n"
> +"   Length        - Number of bytes to transfer (for read/write))\r\n"
> +"   Address       - Address in RAM to store/load data\r\n"
> +"   Offset        - Offset (in blocks) from beggining of the specifie partition to
> store/load data\r\n"
> +"   FilePath      - Path to file to read data into or write/update data from\r\n"
> +"   -yes          - Assume yes for all queries, do not prompt\r\n
> +"   -verbose      - Print additional information on operation\r\n"
> +"   -fat16        - (For format only, has no effect for anything else) - Format to
> FAT16 if possible\r\n\r\n"
> +".SH EXAMPLES\r\n"
> +" \r\n"
> +"EXAMPLES:\r\n"
> +"Get info on the particular partition with name PartitionName on the block
> device blk0:\r\n"
> +"  gpt %Hinfo%N blk0: PartitionName\r\n"
> +"List all available GPT partitions on the block device blk0:\r\n"
> +"  gpt %Hlist%N blk0:\r\n"
> +"Note: the ordinal number shown by this command can be used as a
> partition name in any command requiring partition name\r\n"
> +"Thus gpt info blk0: 1 is valid if there is a partition with ordinal 1 present in
> the output of gpt list command\r\n"
> +"Get information on all recognized partition types\r\n"
> +"  gpt %Htypesinfo%N\r\n"
> +"Clear partitions information and install empty GPT tables for a block device
> blk0:\r\n"
> +"  gpt %Hclear%N blk0:\r\n"
> +"Create a GPT partition with name PartitionName and type EFI SYSTEM in
> the GPT table, using the next available LBA, with size\r\n"
> +"64MiB, with system attribute, on block device blk0:\r\n"
> +"  gpt %Hcreate%N blk0: PartitionName 0 64 1 -type 0\r\n"
> +"Same as above, but now the partition type is not known to the gpt utility,
> so use some GUID known to a 3rd party\r\n"
> +"  gpt create blk0: PartitionName 0 64 1 -type 44581A4A-C834-D1A6-2602-
> 9D522A8F2307\r\n"
> +"Rename the GPT partition PartitionName on blk0: to
> NewPartitionName\r\n"
> +"  gpt %Hrename%N blk0: PartitionName NewPartitionName\r\n"
> +"Have the PartitionDxe driver to re-read GPT tables on a block device
> blk0:(after they were updated with gpt utility)\r\n"
> +"  gpt %Hsync%N blk0:\r\n"
> +"Read 4K from block offset 0x0e000 in Partition named PartitionName of
> the block device at blk0: into RAM at address 0x100000\r\n"
> +"  gpt %Hread%N blk0: 0x100000 PartitionName 0xe000 4096\r\n"
> +"Write 512 bytes from 0x200000 at RAM into the block device at blk0:
> partition PartitionName at offset 0x1000\r\n"
> +"  gpt %Hwrite%N blk0: 0x200000 PartitionName 0x1000 512\r\n"
> +"Read 0x3000 bytes from 0x0 offset of Partition PartitionName at the block
> device blk0: into file fs2:file.bin\r\n"
> +"  gpt %Hreadfile%N blk0: fs2:file.bin PartitionName 0x0 0x3000\r\n"
> +"Write contents of file fs2:file.bin into partition named PartitionName with
> offset (in lba) 0x10 on a block device blk0:\r\n"
> +"  gpt %Hwritefile%N blk0: fs2:file.bin PartitionName 0x10\r\n"
> +"FAT Format the partition PartitionName on block device blk0:\r\n"
> +"  gpt %Hfatformat%N blk0: PartitionName\r\n"
> +"FAT Format the whole device blk0:\r\n"
> +"  gpt fatformat blk0:\r\n"
> +
> +".SH RETURNVALUES\r\n"
> +" \r\n"
> +"RETURN VALUES:\r\n"
> +"  SHELL_SUCCESS         The action was completed as requested.\r\n"
> +"  Specific Shell error  Error while processing command\r\n"
> diff --git a/ShellPkg/ShellPkg.dec b/ShellPkg/ShellPkg.dec
> index bb31c2df8cb3..5f73379f9eec 100644
> --- a/ShellPkg/ShellPkg.dec
> +++ b/ShellPkg/ShellPkg.dec
> @@ -56,6 +56,7 @@ [Guids]
>    gShellNetwork2HiiGuid           = {0x174b2b5, 0xf505, 0x4b12, {0xaa, 0x60,
> 0x59, 0xdf, 0xf8, 0xd6, 0xea, 0x37}}
>    gShellTftpHiiGuid               = {0x738a9314, 0x82c1, 0x4592, {0x8f, 0xf7, 0xc1,
> 0xbd, 0xf1, 0xb2, 0x0e, 0xd4}}
>    gShellBcfgHiiGuid               = {0x5f5f605d, 0x1583, 0x4a2d, {0xa6, 0xb2, 0xeb,
> 0x12, 0xda, 0xb4, 0xa2, 0xb6}}
> +  gShellGptHiiGuid                = {0x5a1ed739, 0x5ef1, 0x429a, {0x8d, 0xf8, 0x28,
> 0xc9, 0x92, 0x64, 0xd7, 0xf8}}
> 
>  [Protocols]
>    gEfiShellEnvironment2Guid           = {0x47c7b221, 0xc42a, 0x11d2, {0x8e,
> 0x57, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}}
> diff --git a/ShellPkg/ShellPkg.dsc b/ShellPkg/ShellPkg.dsc
> index 6b7864bac395..b6a8072dedb5 100644
> --- a/ShellPkg/ShellPkg.dsc
> +++ b/ShellPkg/ShellPkg.dsc
> @@ -91,6 +91,7 @@ [Components]
> 
> ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib
> .inf
> 
> ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib
> .inf
> 
> ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsL
> ib.inf
> +  ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> 
> ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLi
> b.inf
> 
> ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1Commands
> Lib.inf
> 
> ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1Comm
> andsLib.inf
> @@ -121,6 +122,9 @@ [Components]
>  !ifdef $(INCLUDE_TFTP_COMMAND)
> 
> NULL|ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib
> .inf
>  !endif #$(INCLUDE_TFTP_COMMAND)
> +!ifdef $(INCLUDE_GPT_COMMAND)
> +
> NULL|ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.
> inf
> +!endif #$(INCLUDE_GPT_COMMAND)
>  !endif #$(NO_SHELL_PROFILES)
>    }
> 
> --
> 1.9.1
> 
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel


      reply	other threads:[~2016-10-20 20:48 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-10-20  1:31 [PATCH] ShellPkg: Added GPT Shell Application/Library Vladimir Olovyannikov
2016-10-20 20:48 ` Carsey, Jaben [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CB6E33457884FA40993F35157061515C54AA2A6D@FMSMSX103.amr.corp.intel.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox