public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH] ShellPkg: Added GPT Shell Application/Library
@ 2016-10-20  1:31 Vladimir Olovyannikov
  2016-10-20 20:48 ` Carsey, Jaben
  0 siblings, 1 reply; 2+ messages in thread
From: Vladimir Olovyannikov @ 2016-10-20  1:31 UTC (permalink / raw)
  To: edk2-devel; +Cc: Vladimir Olovyannikov, Carsey Jaben, Ni Ruiyu

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/UefiShellDriver1CommandsLib.inf
+  ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
   ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLib.inf
   ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf
   ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.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



^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] ShellPkg: Added GPT Shell Application/Library
  2016-10-20  1:31 [PATCH] ShellPkg: Added GPT Shell Application/Library Vladimir Olovyannikov
@ 2016-10-20 20:48 ` Carsey, Jaben
  0 siblings, 0 replies; 2+ messages in thread
From: Carsey, Jaben @ 2016-10-20 20:48 UTC (permalink / raw)
  To: Vladimir Olovyannikov, edk2-devel@lists.01.org,
	Shah, Tapan (tapandshah@hpe.com), Ni, Ruiyu
  Cc: Ni, Ruiyu, Carsey, Jaben

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


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2016-10-20 20:48 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-10-20  1:31 [PATCH] ShellPkg: Added GPT Shell Application/Library Vladimir Olovyannikov
2016-10-20 20:48 ` Carsey, Jaben

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox