public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH] GPT Shell Application/Library
@ 2016-10-16  5:23 Vladimir Olovyannikov
  2016-10-16 20:05 ` Laszlo Ersek
  2016-10-18  1:45 ` Ni, Ruiyu
  0 siblings, 2 replies; 20+ messages in thread
From: Vladimir Olovyannikov @ 2016-10-16  5:23 UTC (permalink / raw)
  To: jaben.carsey, edk2-devel, ruiyu.ni; +Cc: Vladimir Olovyannikov

This allows managing (create, delete, modify, fat format) of GPT
partitions from within UEFI Shell.
Syntax:
gpt <command> [device_mapped_name] [parameters...]
See usage examples in the .uni file
---
 .../Library/UefiShellGptCommandLib/FatFormat.c     |  611 +++++++
 .../Library/UefiShellGptCommandLib/FatFormat.h     |  111 ++
 .../Library/UefiShellGptCommandLib/GptWorker.c     | 1902 ++++++++++++++++++++
 .../Library/UefiShellGptCommandLib/GptWorker.h     |  186 ++
 .../UefiShellGptCommandLib.c                       | 1135 ++++++++++++
 .../UefiShellGptCommandLib.inf                     |   79 +
 .../UefiShellGptCommandLib.uni                     |  117 ++
 ShellPkg/ShellPkg.dec                              |    1 +
 ShellPkg/ShellPkg.dsc                              |    4 +
 9 files changed, 4146 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..ba7904e6be28
--- /dev/null
+++ b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
@@ -0,0 +1,611 @@
+/** @file
+
+  Copyright (c) 2003 - 2012, Rob Riglar, Ultra-Embedded.com. 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.
+
+**/
+
+/* Portions Copyright (c) 2016, Broadcom. All rights reserved */
+
+#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
+};
+
+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)));
+}
+
+//-----------------------------------------------------------------------------
+// fatfs_calc_cluster_size: Calculate what cluster size should be used
+//-----------------------------------------------------------------------------
+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;
+}
+//-----------------------------------------------------------------------------
+// fatfs_erase_sectors: Erase a number of 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;
+}
+//-----------------------------------------------------------------------------
+// fatfs_create_boot_sector: 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;
+}
+//-----------------------------------------------------------------------------
+// fatfs_create_fsinfo_sector: Create the FSInfo Sector (FAT32)
+//-----------------------------------------------------------------------------
+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;
+}
+//-----------------------------------------------------------------------------
+// fatfs_erase_fat: Erase FAT table using fs details in fs struct
+//-----------------------------------------------------------------------------
+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;
+}
+//-----------------------------------------------------------------------------
+// fatfs_format_fat16: Format a 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;
+}
+//-----------------------------------------------------------------------------
+// fatfs_format_fat32: Format a 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;
+}
+//-----------------------------------------------------------------------------
+// fatfs_format: Format a partition with either FAT16 or FAT32 based on size
+//-----------------------------------------------------------------------------
+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;
+
+  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 <= 4194304) && (!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..d1a325a57abe
--- /dev/null
+++ b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
@@ -0,0 +1,111 @@
+/** @file
+
+  Copyright (c) 2003 - 2012, Ultra-Embedded.com. 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.
+
+**/
+
+/* Portions Copyright (c) 2016, Broadcom. All rights reserved */
+
+#ifndef __FAT_FORMAT_H__
+#define __FAT_FORMAT_H__
+
+#include "GptWorker.h"
+
+#define FAT_SECTOR_SIZE                     512
+#define FAT_BUFFER_SECTORS                    1
+#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 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..0546c94488b0
--- /dev/null
+++ b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
@@ -0,0 +1,1902 @@
+/** @file
+Copyright (c) 2006 - 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)
+{
+  UINTN                Index;
+  EFI_PARTITION_ENTRY  *Entry;
+  EFI_LBA              Length;
+  UINTN                NumEntries; // Used entries
+  UINTN                BlockSize;
+  BOOLEAN              FirstTime;
+  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, 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 th 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] = { L'\0' };
+  CONST CHAR16 *StrUnknown = L"Unknown";
+  EFI_STATUS Status;
+  EFI_LBA Length;
+
+  ASSERT (Entry);
+
+  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, PartitionIdGuid;
+  EFI_STATUS  Status;
+  UINT64      StartBlock;
+  UINT64      EndBlock;
+  UINT64      SizeInBytes = 0;
+  UINT32      BlockSize;
+  UINT64      DiskSizeBlocks;
+  UINT8       *p;
+  BOOLEAN     OffsetSpecified = FALSE;
+  BOOLEAN     AllZeros;
+  INTN        AllZeroEntry;
+  INTN        OldFreeEntry;
+  UINT64      AvailBlocks;
+  UINT64      BlocksToAllocate;
+  UINT64      HighSeen;
+  UINTN       Slot;
+  UINT64      LowestAlignedLba;
+  UINT32      OptimalTransferBlocks;
+  UINTN       i, j;
+  CHAR16      PartNameUsed[MAX_PARTITION_NAME_LENGTH + 1] = { L'\0' };
+  EFI_PARTITION_ENTRY *Entry;
+
+  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..9efec5cefe94
--- /dev/null
+++ b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
@@ -0,0 +1,186 @@
+/*
+ *  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 <ShellBase.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) )
+
+
+//
+// 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 (
+  EFI_GUID Guid,
+  CHAR16 *PartTypeStr,
+  BOOLEAN NoGuidStr
+  );
+
+
+EFI_STATUS
+PartitionGptClearAll (
+  VOID
+  );
+
+EFI_STATUS
+PartitionGptCreatePartition (
+  CONST CHAR16 *PartName,
+  EFI_LBA StartLba,
+  EFI_LBA PartitionSize,
+  UINT64 Attributes,
+  EFI_GUID PartTypeGuid);
+
+EFI_STATUS
+PartitionGptModifyPartition (
+  EFI_PARTITION_ENTRY *Entry,
+  MOD_PARAMS *Params,
+  MOD_FLAGS Flags
+  );
+
+VOID
+GptCleanupGlobals (
+  VOID
+  );
+
+EFI_PARTITION_ENTRY *
+PartitionFindPartitionByCriteria (
+  CONST CHAR16   *Name,
+  EFI_LBA        StartLba,
+  EFI_LBA        EndingLba,
+  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..a9d74a780911
--- /dev/null
+++ b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
@@ -0,0 +1,1135 @@
+/*******************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+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.
+
+*******************************************************************************/
+
+/* Portions Copyright (C) 2016 Broadcom */
+
+#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 },
+  { L"-yes", TypeFlag },
+  { L"-verbose", TypeFlag },
+  { 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;
+}
+
+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;
+}
+
+VOID
+PrintErr (
+  IN CONST CHAR16 *Message,
+  IN EFI_STATUS Status
+  )
+{
+  ShellPrintHiiEx (-1, -1,
+                   NULL, STRING_TOKEN (STR_GPT_ERROR),
+                   gShellGptHiiHandle,
+                   gAppName,
+                   Status,
+                   Message
+                  );
+}
+
+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;
+}
+
+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;
+}
+
+STATIC
+VOID FormatSize(
+  UINT64 Size, CHAR16 *Buffer)
+{
+#define MAX_SIZE_BUF_SIZE 32
+  UINT64 Base, 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);
+  }
+}
+
+STATIC
+EFI_STATUS
+FindAndPrintPartitionableDevices (VOID)
+{
+  UINTN Index;
+  EFI_HANDLE      *HandlePointer;
+  UINTN           HandleCount;
+  UINTN           DevCount;
+  EFI_STATUS      Status;
+  BOOLEAN         FirstTime;
+
+  Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &HandleCount, &HandlePointer);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  DevCount = 0;
+  FirstTime = TRUE;
+
+  for (Index = 0; Index < HandleCount; Index++) {
+    EFI_DEVICE_PATH       *DevicePath;
+    CONST CHAR16          *MapPath;
+    CHAR16                *Match;
+    EFI_BLOCK_IO          *BlkIo;
+    EFI_DISK_IO           *DiskIo;
+    CHAR16                *BufferForSize;
+
+    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));
+      ASSERT (BufferForSize);
+      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 ();
+  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 = 0, Offset = 0;
+  UINT64                    PartAttributes = 0;
+  EFI_GUID                  PartTypeGuid = { 0 };
+  SHELL_FILE_HANDLE         FileHandle = NULL;
+  UINT64                    ByteCount, FileSize;
+  UINTN                     I;
+  UINT8                     *Buffer = NULL, *FileBuffer = NULL;
+
+  CHAR16                    * ProblemParam,*FilePath;
+  CONST CHAR16              *AddressStr = NULL, *OffsetStr = NULL;
+  CONST CHAR16              *PartName = NULL, *NewPartName = NULL, *AttrStr = NULL,
+    *GuidStr = NULL, *VolumeName = NULL;
+  CONST CHAR16              *LengthStr = NULL, *FileStr = NULL;
+  BOOLEAN                   AddrFlag = FALSE, LengthFlag = TRUE, FileFlag = FALSE, GuidFlag = FALSE, OffsetFlag = TRUE;
+  BOOLEAN                   PartNameFlag = TRUE, NewPartNameFlag = FALSE, AttrFlag = FALSE;
+  UINTN                     Flag = 0, CheckFlag = 0;
+  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, NoPrompt = FALSE, Quiet = TRUE;
+  UINT64                    TimeStampB, TimeStampE, SpeedKB, Freq;
+
+  // 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;
+  }
+
+  TimeStampB = 0;
+  TimeStampE = 0;
+
+  NoPrompt = ShellCommandLineGetFlag (CheckPackage, L"-yes");
+  Quiet = !ShellCommandLineGetFlag (CheckPackage, L"-verbose");
+
+  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.
+  // Generally command is:
+  // block_name:bootpart_no addr or filename offset
+
+  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);
+        Status = SHELL_ABORTED;
+      }
+      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;
+      }
+    }
+  }
+
+  // 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) {
+      Status = EFI_INVALID_PARAMETER;
+      PrintErr (L"Cannot write to a read-only device", Status);
+      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: GPT is valid on %s, but no partition(s) defined yet. Use create\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:
+      Print (L"%s: Unsupported command. Try \"help %s\"", gAppName);
+      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);
+      Status = SHELL_ABORTED;
+      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);
+        Status = SHELL_ABORTED;
+        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);
+        Status = SHELL_ABORTED;
+        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:
+      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);
+          Status = SHELL_ABORTED;
+          goto CleanUp;
+        }
+        Status = SHELL_SUCCESS;
+      } else {
+        Status = SHELL_ABORTED;
+      }
+      break;
+    case FAT_FORMAT:
+    {
+      EFI_LBA StartingLBA, EndingLBA;
+      CHAR8                LabelName[12];
+
+      if (VolumeName) {
+        if (StrLen (VolumeName) > 11) {
+          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;
+        }
+        if (!Quiet) {
+          Print (L"Formatting %s to FAT32...\r", PartNameFlag ? Entry->PartitionName : BlockName);
+        }
+        Status = FatFormat (StartingLBA, EndingLBA, BlockIo, DiskIo, VolumeName ? LabelName : NULL, TRUE);
+        if (EFI_ERROR (Status)) {
+          PrintErr (L"Error formatting the partition to FAT             ", Status);
+          Status = SHELL_ABORTED;
+          goto CleanUp;
+        } else if (!Quiet) {
+          Print (L"%s successfully formatted to FAT. Formatted size %llu MiB\n",
+                 PartNameFlag ? Entry->PartitionName : BlockName,
+                 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);
+    Status = SHELL_ABORTED;
+    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..1be4b1ab0f11
--- /dev/null
+++ b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
@@ -0,0 +1,79 @@
+#
+# Marvell BSD License Option
+#
+# If you received this File from Marvell, you may opt to use, redistribute
+# and/or modify this File under the following licensing terms.
+# 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.
+#
+
+#
+# Portions Copyright (C) 2016 Broadcom
+#
+
+[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..55bcb42cfeb3
--- /dev/null
+++ b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
@@ -0,0 +1,117 @@
+/*******************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+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.
+
+*******************************************************************************/
+
+/* Portions Copyright (C) 2016 Broadcom */
+/=#
+
+#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 clear the 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 to FAT32 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\r\n"
+".SH EXAMPLES\r\n"
+" \r\n"
+"EXAMPLES:\r\n"
+"Get the list of available partitionable block device(s)\r\n"
+"  gpt %Hlist%N\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 list 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 39f8012b98c1..5374a2a62d5f 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]
   gEfiShellProtocolGuid               = {0x6302d008, 0x7f9b, 0x4f30, {0x87, 0xac, 0x60, 0xc9, 0xfe, 0xf5, 0xda, 0x4e}}
diff --git a/ShellPkg/ShellPkg.dsc b/ShellPkg/ShellPkg.dsc
index 809bd4220af2..984c1d0ad48b 100644
--- a/ShellPkg/ShellPkg.dsc
+++ b/ShellPkg/ShellPkg.dsc
@@ -89,6 +89,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
@@ -119,6 +120,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] 20+ messages in thread

* Re: [PATCH] GPT Shell Application/Library
  2016-10-16  5:23 [PATCH] GPT Shell Application/Library Vladimir Olovyannikov
@ 2016-10-16 20:05 ` Laszlo Ersek
       [not found]   ` <CACmgjazi_K4Qo5=TeO_tCGK2cB26d0rqOEZh6TthP1UYbo6J6w@mail.gmail.com>
  2016-10-18  1:45 ` Ni, Ruiyu
  1 sibling, 1 reply; 20+ messages in thread
From: Laszlo Ersek @ 2016-10-16 20:05 UTC (permalink / raw)
  To: Vladimir Olovyannikov; +Cc: jaben.carsey, edk2-devel, ruiyu.ni

On 10/16/16 07:23, Vladimir Olovyannikov wrote:
> This allows managing (create, delete, modify, fat format) of GPT
> partitions from within UEFI Shell.
> Syntax:
> gpt <command> [device_mapped_name] [parameters...]
> See usage examples in the .uni file
> ---
>  .../Library/UefiShellGptCommandLib/FatFormat.c     |  611 +++++++
>  .../Library/UefiShellGptCommandLib/FatFormat.h     |  111 ++
>  .../Library/UefiShellGptCommandLib/GptWorker.c     | 1902 ++++++++++++++++++++
>  .../Library/UefiShellGptCommandLib/GptWorker.h     |  186 ++
>  .../UefiShellGptCommandLib.c                       | 1135 ++++++++++++
>  .../UefiShellGptCommandLib.inf                     |   79 +
>  .../UefiShellGptCommandLib.uni                     |  117 ++
>  ShellPkg/ShellPkg.dec                              |    1 +
>  ShellPkg/ShellPkg.dsc                              |    4 +
>  9 files changed, 4146 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

This looks like a supremely welcome, long-awaited addition (latest
request:
<https://lists.01.org/pipermail/edk2-devel/2016-October/002667.html>),
but it really needs your Signed-off-by, and the Contributed-under line
above it:

ShellPkg/Contributions.txt

I would also suggest (simply based on what I've seen elsewhere in edk2)
to keep the copyright notices tightly collected in the file headings.

Someone will have to go over all the licenses too -- does the "Marvell
BSD License Option" for example correspond to the 3-clause BSDL?

On the technical side, I believe that as long as a shell command (or a
command option) is not standardized (in the shell spec), it usually
starts with an underscore (_), so as to prevent future name collisions.
(I could be wrong about this -- I now recall the TFTP command, which is
also not in the 2.2 spec.)

Just my two cents.

Thanks
Laszlo


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

* Re: [PATCH] GPT Shell Application/Library
       [not found]     ` <CACmgjaziUEF2EsSn73HY5JvL2rmRWrXS+rHMtOQ1HaRwPpXS+g@mail.gmail.com>
@ 2016-10-17  6:49       ` Vladimir Olovyannikov
  2016-10-17  7:24         ` Michael Zimmermann
  2016-10-17  9:43         ` Laszlo Ersek
  0 siblings, 2 replies; 20+ messages in thread
From: Vladimir Olovyannikov @ 2016-10-17  6:49 UTC (permalink / raw)
  To: Laszlo Ersek; +Cc: edk2-devel@lists.01.org, Jaben Carsey, ruiyu.ni

Thank you Laszlo,

Sorry, I missed the fields; it is my first contribution, I will add the
required lines, review the source according to your comments and will
resubmit the patch.
So do you think the command should be _gpt instead of gpt? I was following
TFTP and SF commands as a template.

Thank you,
Vladimir

On Oct 16, 2016 1:05 PM, "Laszlo Ersek" <lersek@redhat.com> wrote:
>
> On 10/16/16 07:23, Vladimir Olovyannikov wrote:
> > This allows managing (create, delete, modify, fat format) of GPT
> > partitions from within UEFI Shell.
> > Syntax:
> > gpt <command> [device_mapped_name] [parameters...]
> > See usage examples in the .uni file
> > ---
> >  .../Library/UefiShellGptCommandLib/FatFormat.c     |  611 +++++++
> >  .../Library/UefiShellGptCommandLib/FatFormat.h     |  111 ++
> >  .../Library/UefiShellGptCommandLib/GptWorker.c     | 1902
++++++++++++++++++++
> >  .../Library/UefiShellGptCommandLib/GptWorker.h     |  186 ++
> >  .../UefiShellGptCommandLib.c                       | 1135 ++++++++++++
> >  .../UefiShellGptCommandLib.inf                     |   79 +
> >  .../UefiShellGptCommandLib.uni                     |  117 ++
> >  ShellPkg/ShellPkg.dec                              |    1 +
> >  ShellPkg/ShellPkg.dsc                              |    4 +
> >  9 files changed, 4146 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
>
> This looks like a supremely welcome, long-awaited addition (latest
> request:
> <https://lists.01.org/pipermail/edk2-devel/2016-October/002667.html>),
> but it really needs your Signed-off-by, and the Contributed-under line
> above it:
>
> ShellPkg/Contributions.txt
>
> I would also suggest (simply based on what I've seen elsewhere in edk2)
> to keep the copyright notices tightly collected in the file headings.
>
> Someone will have to go over all the licenses too -- does the "Marvell
> BSD License Option" for example correspond to the 3-clause BSDL?
>
> On the technical side, I believe that as long as a shell command (or a
> command option) is not standardized (in the shell spec), it usually
> starts with an underscore (_), so as to prevent future name collisions.
> (I could be wrong about this -- I now recall the TFTP command, which is
> also not in the 2.2 spec.)
>
> Just my two cents.
>
> Thanks
> Laszlo


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

* Re: [PATCH] GPT Shell Application/Library
  2016-10-17  6:49       ` Vladimir Olovyannikov
@ 2016-10-17  7:24         ` Michael Zimmermann
  2016-10-17 17:52           ` Vladimir Olovyannikov
  2016-10-17  9:43         ` Laszlo Ersek
  1 sibling, 1 reply; 20+ messages in thread
From: Michael Zimmermann @ 2016-10-17  7:24 UTC (permalink / raw)
  To: Vladimir Olovyannikov
  Cc: Laszlo Ersek, Jaben Carsey, Ni, Ruiyu, edk2-devel@lists.01.org

Hi,

wouldn't it be better to make a generic gpt parsing library which is
independent of the shell so both the shell and PartitionDxe can use it?
It may also be useful for other applications which need additional
information like the gpt partition names.

Thanks
Michael

On Mon, Oct 17, 2016 at 8:49 AM, Vladimir Olovyannikov <
vladimir.olovyannikov@broadcom.com> wrote:

> Thank you Laszlo,
>
> Sorry, I missed the fields; it is my first contribution, I will add the
> required lines, review the source according to your comments and will
> resubmit the patch.
> So do you think the command should be _gpt instead of gpt? I was following
> TFTP and SF commands as a template.
>
> Thank you,
> Vladimir
>
> On Oct 16, 2016 1:05 PM, "Laszlo Ersek" <lersek@redhat.com> wrote:
> >
> > On 10/16/16 07:23, Vladimir Olovyannikov wrote:
> > > This allows managing (create, delete, modify, fat format) of GPT
> > > partitions from within UEFI Shell.
> > > Syntax:
> > > gpt <command> [device_mapped_name] [parameters...]
> > > See usage examples in the .uni file
> > > ---
> > >  .../Library/UefiShellGptCommandLib/FatFormat.c     |  611 +++++++
> > >  .../Library/UefiShellGptCommandLib/FatFormat.h     |  111 ++
> > >  .../Library/UefiShellGptCommandLib/GptWorker.c     | 1902
> ++++++++++++++++++++
> > >  .../Library/UefiShellGptCommandLib/GptWorker.h     |  186 ++
> > >  .../UefiShellGptCommandLib.c                       | 1135 ++++++++++++
> > >  .../UefiShellGptCommandLib.inf                     |   79 +
> > >  .../UefiShellGptCommandLib.uni                     |  117 ++
> > >  ShellPkg/ShellPkg.dec                              |    1 +
> > >  ShellPkg/ShellPkg.dsc                              |    4 +
> > >  9 files changed, 4146 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
> >
> > This looks like a supremely welcome, long-awaited addition (latest
> > request:
> > <https://lists.01.org/pipermail/edk2-devel/2016-October/002667.html>),
> > but it really needs your Signed-off-by, and the Contributed-under line
> > above it:
> >
> > ShellPkg/Contributions.txt
> >
> > I would also suggest (simply based on what I've seen elsewhere in edk2)
> > to keep the copyright notices tightly collected in the file headings.
> >
> > Someone will have to go over all the licenses too -- does the "Marvell
> > BSD License Option" for example correspond to the 3-clause BSDL?
> >
> > On the technical side, I believe that as long as a shell command (or a
> > command option) is not standardized (in the shell spec), it usually
> > starts with an underscore (_), so as to prevent future name collisions.
> > (I could be wrong about this -- I now recall the TFTP command, which is
> > also not in the 2.2 spec.)
> >
> > Just my two cents.
> >
> > Thanks
> > Laszlo
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel
>


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

* Re: [PATCH] GPT Shell Application/Library
  2016-10-17  6:49       ` Vladimir Olovyannikov
  2016-10-17  7:24         ` Michael Zimmermann
@ 2016-10-17  9:43         ` Laszlo Ersek
  2016-10-17 16:35           ` Carsey, Jaben
  1 sibling, 1 reply; 20+ messages in thread
From: Laszlo Ersek @ 2016-10-17  9:43 UTC (permalink / raw)
  To: Vladimir Olovyannikov; +Cc: edk2-devel@lists.01.org, Jaben Carsey, ruiyu.ni

On 10/17/16 08:49, Vladimir Olovyannikov wrote:
> Thank you Laszlo,
> 
> Sorry, I missed the fields; it is my first contribution, I will add the
> required lines, review the source according to your comments and will
> resubmit the patch.
> So do you think the command should be _gpt instead of gpt? I was
> following TFTP and SF commands as a template.

Right, at this point I'm confused about TFTP even, in retrospect. It's
not in the spec, so I guess it should have been _TFTP. I hope Jaben and
Ray can advise us. :)

Thanks
Laszlo


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

* Re: [PATCH] GPT Shell Application/Library
  2016-10-17  9:43         ` Laszlo Ersek
@ 2016-10-17 16:35           ` Carsey, Jaben
  0 siblings, 0 replies; 20+ messages in thread
From: Carsey, Jaben @ 2016-10-17 16:35 UTC (permalink / raw)
  To: Laszlo Ersek, Vladimir Olovyannikov
  Cc: Ni, Ruiyu, edk2-devel@lists.01.org, Carsey, Jaben

Laszlo,

We don't have a hard and fast rule about command names.  The simple thing is that we may have a conflict in the future, but I don't see that as likely at this point.  

Your comment about _ was when a custom implementation wants to extend an existing defined command with a non-standard parameter. For example there is an _exit parameter to the shell that tells the shell to auto-close after running the initial command line passed into it.

-Jaben

> -----Original Message-----
> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
> Laszlo Ersek
> Sent: Monday, October 17, 2016 2:44 AM
> To: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>
> Cc: Carsey, Jaben <jaben.carsey@intel.com>; Ni, Ruiyu
> <ruiyu.ni@intel.com>; edk2-devel@lists.01.org <edk2-devel@ml01.01.org>
> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> Importance: High
> 
> On 10/17/16 08:49, Vladimir Olovyannikov wrote:
> > Thank you Laszlo,
> >
> > Sorry, I missed the fields; it is my first contribution, I will add the
> > required lines, review the source according to your comments and will
> > resubmit the patch.
> > So do you think the command should be _gpt instead of gpt? I was
> > following TFTP and SF commands as a template.
> 
> Right, at this point I'm confused about TFTP even, in retrospect. It's
> not in the spec, so I guess it should have been _TFTP. I hope Jaben and
> Ray can advise us. :)
> 
> Thanks
> Laszlo
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel


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

* Re: [PATCH] GPT Shell Application/Library
  2016-10-17  7:24         ` Michael Zimmermann
@ 2016-10-17 17:52           ` Vladimir Olovyannikov
  2016-10-17 17:56             ` Carsey, Jaben
  0 siblings, 1 reply; 20+ messages in thread
From: Vladimir Olovyannikov @ 2016-10-17 17:52 UTC (permalink / raw)
  To: Michael Zimmermann
  Cc: Laszlo Ersek, Jaben Carsey, Ni, Ruiyu, edk2-devel@lists.01.org

Hi Michael,

I am absolutely agree with your proposal.



In the gpt Shell library/application I had to “borrow” some stuff from
PartitionDxe.c to not reinvent a  wheel.

If the PartitionDxe maintainer agrees to have a separate library available
for everybody,
I would move all the GPT-related stuff from the GptWorker (and partially
from the PartitionDxe itself) to that independent library.
This could be a longer-term task.

Right now I just wanted to share the tool which could be useful for anybody
who would wish to manage
GPT partitions (and/or do a FAT32 format of either a disk or a GPT
partition) from within the Shell. What do you think?



Thank you,

Vladimir

*From:* Michael Zimmermann [mailto:sigmaepsilon92@gmail.com]
*Sent:* October-17-16 12:25 AM
*To:* Vladimir Olovyannikov
*Cc:* Laszlo Ersek; Jaben Carsey; Ni, Ruiyu; edk2-devel@lists.01.org
*Subject:* Re: [edk2] [PATCH] GPT Shell Application/Library



Hi,



wouldn't it be better to make a generic gpt parsing library which is
independent of the shell so both the shell and PartitionDxe can use it?

It may also be useful for other applications which need additional
information like the gpt partition names.



Thanks

Michael



On Mon, Oct 17, 2016 at 8:49 AM, Vladimir Olovyannikov <
vladimir.olovyannikov@broadcom.com> wrote:

Thank you Laszlo,

Sorry, I missed the fields; it is my first contribution, I will add the
required lines, review the source according to your comments and will
resubmit the patch.
So do you think the command should be _gpt instead of gpt? I was following
TFTP and SF commands as a template.

Thank you,
Vladimir


On Oct 16, 2016 1:05 PM, "Laszlo Ersek" <lersek@redhat.com> wrote:
>
> On 10/16/16 07:23, Vladimir Olovyannikov wrote:
> > This allows managing (create, delete, modify, fat format) of GPT
> > partitions from within UEFI Shell.
> > Syntax:
> > gpt <command> [device_mapped_name] [parameters...]
> > See usage examples in the .uni file
> > ---
> >  .../Library/UefiShellGptCommandLib/FatFormat.c     |  611 +++++++
> >  .../Library/UefiShellGptCommandLib/FatFormat.h     |  111 ++
> >  .../Library/UefiShellGptCommandLib/GptWorker.c     | 1902
++++++++++++++++++++
> >  .../Library/UefiShellGptCommandLib/GptWorker.h     |  186 ++
> >  .../UefiShellGptCommandLib.c                       | 1135 ++++++++++++
> >  .../UefiShellGptCommandLib.inf                     |   79 +
> >  .../UefiShellGptCommandLib.uni                     |  117 ++
> >  ShellPkg/ShellPkg.dec                              |    1 +
> >  ShellPkg/ShellPkg.dsc                              |    4 +
> >  9 files changed, 4146 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
>
> This looks like a supremely welcome, long-awaited addition (latest
> request:
> <https://lists.01.org/pipermail/edk2-devel/2016-October/002667.html>),
> but it really needs your Signed-off-by, and the Contributed-under line
> above it:
>
> ShellPkg/Contributions.txt
>
> I would also suggest (simply based on what I've seen elsewhere in edk2)
> to keep the copyright notices tightly collected in the file headings.
>
> Someone will have to go over all the licenses too -- does the "Marvell
> BSD License Option" for example correspond to the 3-clause BSDL?
>
> On the technical side, I believe that as long as a shell command (or a
> command option) is not standardized (in the shell spec), it usually
> starts with an underscore (_), so as to prevent future name collisions.
> (I could be wrong about this -- I now recall the TFTP command, which is
> also not in the 2.2 spec.)
>
> Just my two cents.
>
> Thanks
> Laszlo
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel


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

* Re: [PATCH] GPT Shell Application/Library
  2016-10-17 17:52           ` Vladimir Olovyannikov
@ 2016-10-17 17:56             ` Carsey, Jaben
  2016-10-18 13:59               ` Shah, Tapan
  0 siblings, 1 reply; 20+ messages in thread
From: Carsey, Jaben @ 2016-10-17 17:56 UTC (permalink / raw)
  To: Vladimir Olovyannikov, Michael Zimmermann
  Cc: Laszlo Ersek, Ni, Ruiyu, edk2-devel@lists.01.org, Arshi, Shala,
	Carsey, Jaben

To the old question about license: I asked our people to check and was told that the license is compatible with our BSD and ok by Intel.

To the technical content – I really like this idea of a shared library.  That would be a great way to share code and not have as much duplicate.

-Jaben

From: Vladimir Olovyannikov [mailto:vladimir.olovyannikov@broadcom.com]
Sent: Monday, October 17, 2016 10:52 AM
To: Michael Zimmermann <sigmaepsilon92@gmail.com>
Cc: Laszlo Ersek <lersek@redhat.com>; Carsey, Jaben <jaben.carsey@intel.com>; Ni, Ruiyu <ruiyu.ni@intel.com>; edk2-devel@lists.01.org <edk2-devel@ml01.01.org>
Subject: RE: [edk2] [PATCH] GPT Shell Application/Library
Importance: High

Hi Michael,
I am absolutely agree with your proposal.

In the gpt Shell library/application I had to “borrow” some stuff from PartitionDxe.c to not reinvent a  wheel.
If the PartitionDxe maintainer agrees to have a separate library available for everybody,
I would move all the GPT-related stuff from the GptWorker (and partially from the PartitionDxe itself) to that independent library.
This could be a longer-term task.
Right now I just wanted to share the tool which could be useful for anybody who would wish to manage
GPT partitions (and/or do a FAT32 format of either a disk or a GPT partition) from within the Shell. What do you think?

Thank you,
Vladimir
From: Michael Zimmermann [mailto:sigmaepsilon92@gmail.com<mailto:sigmaepsilon92@gmail.com>]
Sent: October-17-16 12:25 AM
To: Vladimir Olovyannikov
Cc: Laszlo Ersek; Jaben Carsey; Ni, Ruiyu; edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
Subject: Re: [edk2] [PATCH] GPT Shell Application/Library

Hi,

wouldn't it be better to make a generic gpt parsing library which is independent of the shell so both the shell and PartitionDxe can use it?
It may also be useful for other applications which need additional information like the gpt partition names.

Thanks
Michael

On Mon, Oct 17, 2016 at 8:49 AM, Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com<mailto:vladimir.olovyannikov@broadcom.com>> wrote:
Thank you Laszlo,

Sorry, I missed the fields; it is my first contribution, I will add the
required lines, review the source according to your comments and will
resubmit the patch.
So do you think the command should be _gpt instead of gpt? I was following
TFTP and SF commands as a template.

Thank you,
Vladimir

On Oct 16, 2016 1:05 PM, "Laszlo Ersek" <lersek@redhat.com<mailto:lersek@redhat.com>> wrote:
>
> On 10/16/16 07:23, Vladimir Olovyannikov wrote:
> > This allows managing (create, delete, modify, fat format) of GPT
> > partitions from within UEFI Shell.
> > Syntax:
> > gpt <command> [device_mapped_name] [parameters...]
> > See usage examples in the .uni file
> > ---
> >  .../Library/UefiShellGptCommandLib/FatFormat.c     |  611 +++++++
> >  .../Library/UefiShellGptCommandLib/FatFormat.h     |  111 ++
> >  .../Library/UefiShellGptCommandLib/GptWorker.c     | 1902
++++++++++++++++++++
> >  .../Library/UefiShellGptCommandLib/GptWorker.h     |  186 ++
> >  .../UefiShellGptCommandLib.c                       | 1135 ++++++++++++
> >  .../UefiShellGptCommandLib.inf                     |   79 +
> >  .../UefiShellGptCommandLib.uni                     |  117 ++
> >  ShellPkg/ShellPkg.dec                              |    1 +
> >  ShellPkg/ShellPkg.dsc                              |    4 +
> >  9 files changed, 4146 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
>
> This looks like a supremely welcome, long-awaited addition (latest
> request:
> <https://lists.01.org/pipermail/edk2-devel/2016-October/002667.html>),
> but it really needs your Signed-off-by, and the Contributed-under line
> above it:
>
> ShellPkg/Contributions.txt
>
> I would also suggest (simply based on what I've seen elsewhere in edk2)
> to keep the copyright notices tightly collected in the file headings.
>
> Someone will have to go over all the licenses too -- does the "Marvell
> BSD License Option" for example correspond to the 3-clause BSDL?
>
> On the technical side, I believe that as long as a shell command (or a
> command option) is not standardized (in the shell spec), it usually
> starts with an underscore (_), so as to prevent future name collisions.
> (I could be wrong about this -- I now recall the TFTP command, which is
> also not in the 2.2 spec.)
>
> Just my two cents.
>
> Thanks
> Laszlo
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
https://lists.01.org/mailman/listinfo/edk2-devel


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

* Re: [PATCH] GPT Shell Application/Library
  2016-10-16  5:23 [PATCH] GPT Shell Application/Library Vladimir Olovyannikov
  2016-10-16 20:05 ` Laszlo Ersek
@ 2016-10-18  1:45 ` Ni, Ruiyu
  2016-10-18  1:48   ` Tim Lewis
  1 sibling, 1 reply; 20+ messages in thread
From: Ni, Ruiyu @ 2016-10-18  1:45 UTC (permalink / raw)
  To: Vladimir Olovyannikov, Carsey, Jaben, edk2-devel@lists.01.org

Jaben,
Do you think that providing a standalone gpt.efi is better? So that Shell.efi only provides the internal commands listed in Shell spec.

Thanks/Ray

> -----Original Message-----
> From: Vladimir Olovyannikov [mailto:vladimir.olovyannikov@broadcom.com]
> Sent: Sunday, October 16, 2016 1:24 PM
> To: Carsey, Jaben <jaben.carsey@intel.com>; edk2-devel@lists.01.org; Ni,
> Ruiyu <ruiyu.ni@intel.com>
> Cc: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>
> Subject: [PATCH] GPT Shell Application/Library
> 
> This allows managing (create, delete, modify, fat format) of GPT
> partitions from within UEFI Shell.
> Syntax:
> gpt <command> [device_mapped_name] [parameters...]
> See usage examples in the .uni file
> ---
>  .../Library/UefiShellGptCommandLib/FatFormat.c     |  611 +++++++
>  .../Library/UefiShellGptCommandLib/FatFormat.h     |  111 ++
>  .../Library/UefiShellGptCommandLib/GptWorker.c     | 1902
> ++++++++++++++++++++
>  .../Library/UefiShellGptCommandLib/GptWorker.h     |  186 ++
>  .../UefiShellGptCommandLib.c                       | 1135 ++++++++++++
>  .../UefiShellGptCommandLib.inf                     |   79 +
>  .../UefiShellGptCommandLib.uni                     |  117 ++
>  ShellPkg/ShellPkg.dec                              |    1 +
>  ShellPkg/ShellPkg.dsc                              |    4 +
>  9 files changed, 4146 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..ba7904e6be28
> --- /dev/null
> +++ b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> @@ -0,0 +1,611 @@
> +/** @file
> +
> +  Copyright (c) 2003 - 2012, Rob Riglar, Ultra-Embedded.com. 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.
> +
> +**/
> +
> +/* Portions Copyright (c) 2016, Broadcom. All rights reserved */
> +
> +#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
> +};
> +
> +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)));
> +}
> +
> +//-----------------------------------------------------------------------------
> +// fatfs_calc_cluster_size: Calculate what cluster size should be used
> +//-----------------------------------------------------------------------------
> +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;
> +}
> +//-----------------------------------------------------------------------------
> +// fatfs_erase_sectors: Erase a number of 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;
> +}
> +//-----------------------------------------------------------------------------
> +// fatfs_create_boot_sector: 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;
> +}
> +//-----------------------------------------------------------------------------
> +// fatfs_create_fsinfo_sector: Create the FSInfo Sector (FAT32)
> +//-----------------------------------------------------------------------------
> +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;
> +}
> +//-----------------------------------------------------------------------------
> +// fatfs_erase_fat: Erase FAT table using fs details in fs struct
> +//-----------------------------------------------------------------------------
> +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;
> +}
> +//-----------------------------------------------------------------------------
> +// fatfs_format_fat16: Format a 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;
> +}
> +//-----------------------------------------------------------------------------
> +// fatfs_format_fat32: Format a 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;
> +}
> +//-----------------------------------------------------------------------------
> +// fatfs_format: Format a partition with either FAT16 or FAT32 based on size
> +//-----------------------------------------------------------------------------
> +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;
> +
> +  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 <= 4194304) && (!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..d1a325a57abe
> --- /dev/null
> +++ b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> @@ -0,0 +1,111 @@
> +/** @file
> +
> +  Copyright (c) 2003 - 2012, Ultra-Embedded.com. 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.
> +
> +**/
> +
> +/* Portions Copyright (c) 2016, Broadcom. All rights reserved */
> +
> +#ifndef __FAT_FORMAT_H__
> +#define __FAT_FORMAT_H__
> +
> +#include "GptWorker.h"
> +
> +#define FAT_SECTOR_SIZE                     512
> +#define FAT_BUFFER_SECTORS                    1
> +#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 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..0546c94488b0
> --- /dev/null
> +++ b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> @@ -0,0 +1,1902 @@
> +/** @file
> +Copyright (c) 2006 - 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)
> +{
> +  UINTN                Index;
> +  EFI_PARTITION_ENTRY  *Entry;
> +  EFI_LBA              Length;
> +  UINTN                NumEntries; // Used entries
> +  UINTN                BlockSize;
> +  BOOLEAN              FirstTime;
> +  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, 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 th 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] = { L'\0' };
> +  CONST CHAR16 *StrUnknown = L"Unknown";
> +  EFI_STATUS Status;
> +  EFI_LBA Length;
> +
> +  ASSERT (Entry);
> +
> +  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, PartitionIdGuid;
> +  EFI_STATUS  Status;
> +  UINT64      StartBlock;
> +  UINT64      EndBlock;
> +  UINT64      SizeInBytes = 0;
> +  UINT32      BlockSize;
> +  UINT64      DiskSizeBlocks;
> +  UINT8       *p;
> +  BOOLEAN     OffsetSpecified = FALSE;
> +  BOOLEAN     AllZeros;
> +  INTN        AllZeroEntry;
> +  INTN        OldFreeEntry;
> +  UINT64      AvailBlocks;
> +  UINT64      BlocksToAllocate;
> +  UINT64      HighSeen;
> +  UINTN       Slot;
> +  UINT64      LowestAlignedLba;
> +  UINT32      OptimalTransferBlocks;
> +  UINTN       i, j;
> +  CHAR16      PartNameUsed[MAX_PARTITION_NAME_LENGTH + 1] = { L'\0' };
> +  EFI_PARTITION_ENTRY *Entry;
> +
> +  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..9efec5cefe94
> --- /dev/null
> +++ b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> @@ -0,0 +1,186 @@
> +/*
> + *  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 <ShellBase.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) )
> +
> +
> +//
> +// 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 (
> +  EFI_GUID Guid,
> +  CHAR16 *PartTypeStr,
> +  BOOLEAN NoGuidStr
> +  );
> +
> +
> +EFI_STATUS
> +PartitionGptClearAll (
> +  VOID
> +  );
> +
> +EFI_STATUS
> +PartitionGptCreatePartition (
> +  CONST CHAR16 *PartName,
> +  EFI_LBA StartLba,
> +  EFI_LBA PartitionSize,
> +  UINT64 Attributes,
> +  EFI_GUID PartTypeGuid);
> +
> +EFI_STATUS
> +PartitionGptModifyPartition (
> +  EFI_PARTITION_ENTRY *Entry,
> +  MOD_PARAMS *Params,
> +  MOD_FLAGS Flags
> +  );
> +
> +VOID
> +GptCleanupGlobals (
> +  VOID
> +  );
> +
> +EFI_PARTITION_ENTRY *
> +PartitionFindPartitionByCriteria (
> +  CONST CHAR16   *Name,
> +  EFI_LBA        StartLba,
> +  EFI_LBA        EndingLba,
> +  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..a9d74a780911
> --- /dev/null
> +++
> b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> @@ -0,0 +1,1135 @@
> +/*********************************************************
> **********************
> +Copyright (C) 2016 Marvell International Ltd.
> +
> +Marvell BSD License Option
> +
> +If you received this File from Marvell, you may opt to use, redistribute
> and/or
> +modify this File under the following licensing terms.
> +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.
> +
> +*********************************************************
> **********************/
> +
> +/* Portions Copyright (C) 2016 Broadcom */
> +
> +#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 },
> +  { L"-yes", TypeFlag },
> +  { L"-verbose", TypeFlag },
> +  { 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;
> +}
> +
> +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;
> +}
> +
> +VOID
> +PrintErr (
> +  IN CONST CHAR16 *Message,
> +  IN EFI_STATUS Status
> +  )
> +{
> +  ShellPrintHiiEx (-1, -1,
> +                   NULL, STRING_TOKEN (STR_GPT_ERROR),
> +                   gShellGptHiiHandle,
> +                   gAppName,
> +                   Status,
> +                   Message
> +                  );
> +}
> +
> +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;
> +}
> +
> +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;
> +}
> +
> +STATIC
> +VOID FormatSize(
> +  UINT64 Size, CHAR16 *Buffer)
> +{
> +#define MAX_SIZE_BUF_SIZE 32
> +  UINT64 Base, 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);
> +  }
> +}
> +
> +STATIC
> +EFI_STATUS
> +FindAndPrintPartitionableDevices (VOID)
> +{
> +  UINTN Index;
> +  EFI_HANDLE      *HandlePointer;
> +  UINTN           HandleCount;
> +  UINTN           DevCount;
> +  EFI_STATUS      Status;
> +  BOOLEAN         FirstTime;
> +
> +  Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid,
> NULL, &HandleCount, &HandlePointer);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  DevCount = 0;
> +  FirstTime = TRUE;
> +
> +  for (Index = 0; Index < HandleCount; Index++) {
> +    EFI_DEVICE_PATH       *DevicePath;
> +    CONST CHAR16          *MapPath;
> +    CHAR16                *Match;
> +    EFI_BLOCK_IO          *BlkIo;
> +    EFI_DISK_IO           *DiskIo;
> +    CHAR16                *BufferForSize;
> +
> +    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));
> +      ASSERT (BufferForSize);
> +      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 ();
> +  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 = 0, Offset = 0;
> +  UINT64                    PartAttributes = 0;
> +  EFI_GUID                  PartTypeGuid = { 0 };
> +  SHELL_FILE_HANDLE         FileHandle = NULL;
> +  UINT64                    ByteCount, FileSize;
> +  UINTN                     I;
> +  UINT8                     *Buffer = NULL, *FileBuffer = NULL;
> +
> +  CHAR16                    * ProblemParam,*FilePath;
> +  CONST CHAR16              *AddressStr = NULL, *OffsetStr = NULL;
> +  CONST CHAR16              *PartName = NULL, *NewPartName = NULL,
> *AttrStr = NULL,
> +    *GuidStr = NULL, *VolumeName = NULL;
> +  CONST CHAR16              *LengthStr = NULL, *FileStr = NULL;
> +  BOOLEAN                   AddrFlag = FALSE, LengthFlag = TRUE, FileFlag = FALSE,
> GuidFlag = FALSE, OffsetFlag = TRUE;
> +  BOOLEAN                   PartNameFlag = TRUE, NewPartNameFlag = FALSE,
> AttrFlag = FALSE;
> +  UINTN                     Flag = 0, CheckFlag = 0;
> +  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, NoPrompt = FALSE, Quiet = TRUE;
> +  UINT64                    TimeStampB, TimeStampE, SpeedKB, Freq;
> +
> +  // 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;
> +  }
> +
> +  TimeStampB = 0;
> +  TimeStampE = 0;
> +
> +  NoPrompt = ShellCommandLineGetFlag (CheckPackage, L"-yes");
> +  Quiet = !ShellCommandLineGetFlag (CheckPackage, L"-verbose");
> +
> +  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.
> +  // Generally command is:
> +  // block_name:bootpart_no addr or filename offset
> +
> +  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);
> +        Status = SHELL_ABORTED;
> +      }
> +      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;
> +      }
> +    }
> +  }
> +
> +  // 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) {
> +      Status = EFI_INVALID_PARAMETER;
> +      PrintErr (L"Cannot write to a read-only device", Status);
> +      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: GPT is valid on %s, but no partition(s) defined yet. Use
> create\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:
> +      Print (L"%s: Unsupported command. Try \"help %s\"", gAppName);
> +      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);
> +      Status = SHELL_ABORTED;
> +      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);
> +        Status = SHELL_ABORTED;
> +        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);
> +        Status = SHELL_ABORTED;
> +        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:
> +      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);
> +          Status = SHELL_ABORTED;
> +          goto CleanUp;
> +        }
> +        Status = SHELL_SUCCESS;
> +      } else {
> +        Status = SHELL_ABORTED;
> +      }
> +      break;
> +    case FAT_FORMAT:
> +    {
> +      EFI_LBA StartingLBA, EndingLBA;
> +      CHAR8                LabelName[12];
> +
> +      if (VolumeName) {
> +        if (StrLen (VolumeName) > 11) {
> +          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;
> +        }
> +        if (!Quiet) {
> +          Print (L"Formatting %s to FAT32...\r", PartNameFlag ? Entry-
> >PartitionName : BlockName);
> +        }
> +        Status = FatFormat (StartingLBA, EndingLBA, BlockIo, DiskIo,
> VolumeName ? LabelName : NULL, TRUE);
> +        if (EFI_ERROR (Status)) {
> +          PrintErr (L"Error formatting the partition to FAT             ", Status);
> +          Status = SHELL_ABORTED;
> +          goto CleanUp;
> +        } else if (!Quiet) {
> +          Print (L"%s successfully formatted to FAT. Formatted size %llu MiB\n",
> +                 PartNameFlag ? Entry->PartitionName : BlockName,
> +                 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);
> +    Status = SHELL_ABORTED;
> +    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..1be4b1ab0f11
> --- /dev/null
> +++
> b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> @@ -0,0 +1,79 @@
> +#
> +# Marvell BSD License Option
> +#
> +# If you received this File from Marvell, you may opt to use, redistribute
> +# and/or modify this File under the following licensing terms.
> +# 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.
> +#
> +
> +#
> +# Portions Copyright (C) 2016 Broadcom
> +#
> +
> +[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..55bcb42cfeb3
> --- /dev/null
> +++
> b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
> @@ -0,0 +1,117 @@
> +/*********************************************************
> **********************
> +Copyright (C) 2016 Marvell International Ltd.
> +
> +Marvell BSD License Option
> +
> +If you received this File from Marvell, you may opt to use, redistribute
> and/or
> +modify this File under the following licensing terms.
> +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.
> +
> +*********************************************************
> **********************/
> +
> +/* Portions Copyright (C) 2016 Broadcom */
> +/=#
> +
> +#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 clear the 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 to FAT32 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\r\n"
> +".SH EXAMPLES\r\n"
> +" \r\n"
> +"EXAMPLES:\r\n"
> +"Get the list of available partitionable block device(s)\r\n"
> +"  gpt %Hlist%N\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 list 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 39f8012b98c1..5374a2a62d5f 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]
>    gEfiShellProtocolGuid               = {0x6302d008, 0x7f9b, 0x4f30, {0x87, 0xac,
> 0x60, 0xc9, 0xfe, 0xf5, 0xda, 0x4e}}
> diff --git a/ShellPkg/ShellPkg.dsc b/ShellPkg/ShellPkg.dsc
> index 809bd4220af2..984c1d0ad48b 100644
> --- a/ShellPkg/ShellPkg.dsc
> +++ b/ShellPkg/ShellPkg.dsc
> @@ -89,6 +89,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
> @@ -119,6 +120,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	[flat|nested] 20+ messages in thread

* Re: [PATCH] GPT Shell Application/Library
  2016-10-18  1:45 ` Ni, Ruiyu
@ 2016-10-18  1:48   ` Tim Lewis
  2016-10-18  1:55     ` Ni, Ruiyu
  0 siblings, 1 reply; 20+ messages in thread
From: Tim Lewis @ 2016-10-18  1:48 UTC (permalink / raw)
  To: Ni, Ruiyu, Vladimir Olovyannikov, Carsey, Jaben,
	edk2-devel@lists.01.org

We would prefer that this tool be external.  Tim

-----Original Message-----
From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of Ni, Ruiyu
Sent: Monday, October 17, 2016 6:46 PM
To: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>; Carsey, Jaben <jaben.carsey@intel.com>; edk2-devel@lists.01.org
Subject: Re: [edk2] [PATCH] GPT Shell Application/Library

Jaben,
Do you think that providing a standalone gpt.efi is better? So that Shell.efi only provides the internal commands listed in Shell spec.

Thanks/Ray

> -----Original Message-----
> From: Vladimir Olovyannikov [mailto:vladimir.olovyannikov@broadcom.com]
> Sent: Sunday, October 16, 2016 1:24 PM
> To: Carsey, Jaben <jaben.carsey@intel.com>; edk2-devel@lists.01.org; Ni,
> Ruiyu <ruiyu.ni@intel.com>
> Cc: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>
> Subject: [PATCH] GPT Shell Application/Library
> 
> This allows managing (create, delete, modify, fat format) of GPT
> partitions from within UEFI Shell.
> Syntax:
> gpt <command> [device_mapped_name] [parameters...]
> See usage examples in the .uni file
> ---
>  .../Library/UefiShellGptCommandLib/FatFormat.c     |  611 +++++++
>  .../Library/UefiShellGptCommandLib/FatFormat.h     |  111 ++
>  .../Library/UefiShellGptCommandLib/GptWorker.c     | 1902
> ++++++++++++++++++++
>  .../Library/UefiShellGptCommandLib/GptWorker.h     |  186 ++
>  .../UefiShellGptCommandLib.c                       | 1135 ++++++++++++
>  .../UefiShellGptCommandLib.inf                     |   79 +
>  .../UefiShellGptCommandLib.uni                     |  117 ++
>  ShellPkg/ShellPkg.dec                              |    1 +
>  ShellPkg/ShellPkg.dsc                              |    4 +
>  9 files changed, 4146 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..ba7904e6be28
> --- /dev/null
> +++ b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> @@ -0,0 +1,611 @@
> +/** @file
> +
> +  Copyright (c) 2003 - 2012, Rob Riglar, Ultra-Embedded.com. 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.
> +
> +**/
> +
> +/* Portions Copyright (c) 2016, Broadcom. All rights reserved */
> +
> +#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
> +};
> +
> +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)));
> +}
> +
> +//-----------------------------------------------------------------------------
> +// fatfs_calc_cluster_size: Calculate what cluster size should be used
> +//-----------------------------------------------------------------------------
> +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;
> +}
> +//-----------------------------------------------------------------------------
> +// fatfs_erase_sectors: Erase a number of 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;
> +}
> +//-----------------------------------------------------------------------------
> +// fatfs_create_boot_sector: 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;
> +}
> +//-----------------------------------------------------------------------------
> +// fatfs_create_fsinfo_sector: Create the FSInfo Sector (FAT32)
> +//-----------------------------------------------------------------------------
> +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;
> +}
> +//-----------------------------------------------------------------------------
> +// fatfs_erase_fat: Erase FAT table using fs details in fs struct
> +//-----------------------------------------------------------------------------
> +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;
> +}
> +//-----------------------------------------------------------------------------
> +// fatfs_format_fat16: Format a 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;
> +}
> +//-----------------------------------------------------------------------------
> +// fatfs_format_fat32: Format a 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;
> +}
> +//-----------------------------------------------------------------------------
> +// fatfs_format: Format a partition with either FAT16 or FAT32 based on size
> +//-----------------------------------------------------------------------------
> +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;
> +
> +  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 <= 4194304) && (!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..d1a325a57abe
> --- /dev/null
> +++ b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> @@ -0,0 +1,111 @@
> +/** @file
> +
> +  Copyright (c) 2003 - 2012, Ultra-Embedded.com. 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.
> +
> +**/
> +
> +/* Portions Copyright (c) 2016, Broadcom. All rights reserved */
> +
> +#ifndef __FAT_FORMAT_H__
> +#define __FAT_FORMAT_H__
> +
> +#include "GptWorker.h"
> +
> +#define FAT_SECTOR_SIZE                     512
> +#define FAT_BUFFER_SECTORS                    1
> +#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 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..0546c94488b0
> --- /dev/null
> +++ b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> @@ -0,0 +1,1902 @@
> +/** @file
> +Copyright (c) 2006 - 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)
> +{
> +  UINTN                Index;
> +  EFI_PARTITION_ENTRY  *Entry;
> +  EFI_LBA              Length;
> +  UINTN                NumEntries; // Used entries
> +  UINTN                BlockSize;
> +  BOOLEAN              FirstTime;
> +  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, 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 th 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] = { L'\0' };
> +  CONST CHAR16 *StrUnknown = L"Unknown";
> +  EFI_STATUS Status;
> +  EFI_LBA Length;
> +
> +  ASSERT (Entry);
> +
> +  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, PartitionIdGuid;
> +  EFI_STATUS  Status;
> +  UINT64      StartBlock;
> +  UINT64      EndBlock;
> +  UINT64      SizeInBytes = 0;
> +  UINT32      BlockSize;
> +  UINT64      DiskSizeBlocks;
> +  UINT8       *p;
> +  BOOLEAN     OffsetSpecified = FALSE;
> +  BOOLEAN     AllZeros;
> +  INTN        AllZeroEntry;
> +  INTN        OldFreeEntry;
> +  UINT64      AvailBlocks;
> +  UINT64      BlocksToAllocate;
> +  UINT64      HighSeen;
> +  UINTN       Slot;
> +  UINT64      LowestAlignedLba;
> +  UINT32      OptimalTransferBlocks;
> +  UINTN       i, j;
> +  CHAR16      PartNameUsed[MAX_PARTITION_NAME_LENGTH + 1] = { L'\0' };
> +  EFI_PARTITION_ENTRY *Entry;
> +
> +  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..9efec5cefe94
> --- /dev/null
> +++ b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> @@ -0,0 +1,186 @@
> +/*
> + *  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 <ShellBase.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) )
> +
> +
> +//
> +// 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 (
> +  EFI_GUID Guid,
> +  CHAR16 *PartTypeStr,
> +  BOOLEAN NoGuidStr
> +  );
> +
> +
> +EFI_STATUS
> +PartitionGptClearAll (
> +  VOID
> +  );
> +
> +EFI_STATUS
> +PartitionGptCreatePartition (
> +  CONST CHAR16 *PartName,
> +  EFI_LBA StartLba,
> +  EFI_LBA PartitionSize,
> +  UINT64 Attributes,
> +  EFI_GUID PartTypeGuid);
> +
> +EFI_STATUS
> +PartitionGptModifyPartition (
> +  EFI_PARTITION_ENTRY *Entry,
> +  MOD_PARAMS *Params,
> +  MOD_FLAGS Flags
> +  );
> +
> +VOID
> +GptCleanupGlobals (
> +  VOID
> +  );
> +
> +EFI_PARTITION_ENTRY *
> +PartitionFindPartitionByCriteria (
> +  CONST CHAR16   *Name,
> +  EFI_LBA        StartLba,
> +  EFI_LBA        EndingLba,
> +  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..a9d74a780911
> --- /dev/null
> +++
> b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> @@ -0,0 +1,1135 @@
> +/*********************************************************
> **********************
> +Copyright (C) 2016 Marvell International Ltd.
> +
> +Marvell BSD License Option
> +
> +If you received this File from Marvell, you may opt to use, redistribute
> and/or
> +modify this File under the following licensing terms.
> +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.
> +
> +*********************************************************
> **********************/
> +
> +/* Portions Copyright (C) 2016 Broadcom */
> +
> +#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 },
> +  { L"-yes", TypeFlag },
> +  { L"-verbose", TypeFlag },
> +  { 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;
> +}
> +
> +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;
> +}
> +
> +VOID
> +PrintErr (
> +  IN CONST CHAR16 *Message,
> +  IN EFI_STATUS Status
> +  )
> +{
> +  ShellPrintHiiEx (-1, -1,
> +                   NULL, STRING_TOKEN (STR_GPT_ERROR),
> +                   gShellGptHiiHandle,
> +                   gAppName,
> +                   Status,
> +                   Message
> +                  );
> +}
> +
> +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;
> +}
> +
> +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;
> +}
> +
> +STATIC
> +VOID FormatSize(
> +  UINT64 Size, CHAR16 *Buffer)
> +{
> +#define MAX_SIZE_BUF_SIZE 32
> +  UINT64 Base, 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);
> +  }
> +}
> +
> +STATIC
> +EFI_STATUS
> +FindAndPrintPartitionableDevices (VOID)
> +{
> +  UINTN Index;
> +  EFI_HANDLE      *HandlePointer;
> +  UINTN           HandleCount;
> +  UINTN           DevCount;
> +  EFI_STATUS      Status;
> +  BOOLEAN         FirstTime;
> +
> +  Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid,
> NULL, &HandleCount, &HandlePointer);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  DevCount = 0;
> +  FirstTime = TRUE;
> +
> +  for (Index = 0; Index < HandleCount; Index++) {
> +    EFI_DEVICE_PATH       *DevicePath;
> +    CONST CHAR16          *MapPath;
> +    CHAR16                *Match;
> +    EFI_BLOCK_IO          *BlkIo;
> +    EFI_DISK_IO           *DiskIo;
> +    CHAR16                *BufferForSize;
> +
> +    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));
> +      ASSERT (BufferForSize);
> +      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 ();
> +  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 = 0, Offset = 0;
> +  UINT64                    PartAttributes = 0;
> +  EFI_GUID                  PartTypeGuid = { 0 };
> +  SHELL_FILE_HANDLE         FileHandle = NULL;
> +  UINT64                    ByteCount, FileSize;
> +  UINTN                     I;
> +  UINT8                     *Buffer = NULL, *FileBuffer = NULL;
> +
> +  CHAR16                    * ProblemParam,*FilePath;
> +  CONST CHAR16              *AddressStr = NULL, *OffsetStr = NULL;
> +  CONST CHAR16              *PartName = NULL, *NewPartName = NULL,
> *AttrStr = NULL,
> +    *GuidStr = NULL, *VolumeName = NULL;
> +  CONST CHAR16              *LengthStr = NULL, *FileStr = NULL;
> +  BOOLEAN                   AddrFlag = FALSE, LengthFlag = TRUE, FileFlag = FALSE,
> GuidFlag = FALSE, OffsetFlag = TRUE;
> +  BOOLEAN                   PartNameFlag = TRUE, NewPartNameFlag = FALSE,
> AttrFlag = FALSE;
> +  UINTN                     Flag = 0, CheckFlag = 0;
> +  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, NoPrompt = FALSE, Quiet = TRUE;
> +  UINT64                    TimeStampB, TimeStampE, SpeedKB, Freq;
> +
> +  // 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;
> +  }
> +
> +  TimeStampB = 0;
> +  TimeStampE = 0;
> +
> +  NoPrompt = ShellCommandLineGetFlag (CheckPackage, L"-yes");
> +  Quiet = !ShellCommandLineGetFlag (CheckPackage, L"-verbose");
> +
> +  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.
> +  // Generally command is:
> +  // block_name:bootpart_no addr or filename offset
> +
> +  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);
> +        Status = SHELL_ABORTED;
> +      }
> +      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;
> +      }
> +    }
> +  }
> +
> +  // 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) {
> +      Status = EFI_INVALID_PARAMETER;
> +      PrintErr (L"Cannot write to a read-only device", Status);
> +      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: GPT is valid on %s, but no partition(s) defined yet. Use
> create\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:
> +      Print (L"%s: Unsupported command. Try \"help %s\"", gAppName);
> +      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);
> +      Status = SHELL_ABORTED;
> +      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);
> +        Status = SHELL_ABORTED;
> +        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);
> +        Status = SHELL_ABORTED;
> +        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:
> +      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);
> +          Status = SHELL_ABORTED;
> +          goto CleanUp;
> +        }
> +        Status = SHELL_SUCCESS;
> +      } else {
> +        Status = SHELL_ABORTED;
> +      }
> +      break;
> +    case FAT_FORMAT:
> +    {
> +      EFI_LBA StartingLBA, EndingLBA;
> +      CHAR8                LabelName[12];
> +
> +      if (VolumeName) {
> +        if (StrLen (VolumeName) > 11) {
> +          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;
> +        }
> +        if (!Quiet) {
> +          Print (L"Formatting %s to FAT32...\r", PartNameFlag ? Entry-
> >PartitionName : BlockName);
> +        }
> +        Status = FatFormat (StartingLBA, EndingLBA, BlockIo, DiskIo,
> VolumeName ? LabelName : NULL, TRUE);
> +        if (EFI_ERROR (Status)) {
> +          PrintErr (L"Error formatting the partition to FAT             ", Status);
> +          Status = SHELL_ABORTED;
> +          goto CleanUp;
> +        } else if (!Quiet) {
> +          Print (L"%s successfully formatted to FAT. Formatted size %llu MiB\n",
> +                 PartNameFlag ? Entry->PartitionName : BlockName,
> +                 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);
> +    Status = SHELL_ABORTED;
> +    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..1be4b1ab0f11
> --- /dev/null
> +++
> b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> @@ -0,0 +1,79 @@
> +#
> +# Marvell BSD License Option
> +#
> +# If you received this File from Marvell, you may opt to use, redistribute
> +# and/or modify this File under the following licensing terms.
> +# 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.
> +#
> +
> +#
> +# Portions Copyright (C) 2016 Broadcom
> +#
> +
> +[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..55bcb42cfeb3
> --- /dev/null
> +++
> b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
> @@ -0,0 +1,117 @@
> +/*********************************************************
> **********************
> +Copyright (C) 2016 Marvell International Ltd.
> +
> +Marvell BSD License Option
> +
> +If you received this File from Marvell, you may opt to use, redistribute
> and/or
> +modify this File under the following licensing terms.
> +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.
> +
> +*********************************************************
> **********************/
> +
> +/* Portions Copyright (C) 2016 Broadcom */
> +/=#
> +
> +#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 clear the 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 to FAT32 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\r\n"
> +".SH EXAMPLES\r\n"
> +" \r\n"
> +"EXAMPLES:\r\n"
> +"Get the list of available partitionable block device(s)\r\n"
> +"  gpt %Hlist%N\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 list 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 39f8012b98c1..5374a2a62d5f 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]
>    gEfiShellProtocolGuid               = {0x6302d008, 0x7f9b, 0x4f30, {0x87, 0xac,
> 0x60, 0xc9, 0xfe, 0xf5, 0xda, 0x4e}}
> diff --git a/ShellPkg/ShellPkg.dsc b/ShellPkg/ShellPkg.dsc
> index 809bd4220af2..984c1d0ad48b 100644
> --- a/ShellPkg/ShellPkg.dsc
> +++ b/ShellPkg/ShellPkg.dsc
> @@ -89,6 +89,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
> @@ -119,6 +120,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] 20+ messages in thread

* Re: [PATCH] GPT Shell Application/Library
  2016-10-18  1:48   ` Tim Lewis
@ 2016-10-18  1:55     ` Ni, Ruiyu
  2016-10-18  2:59       ` Carsey, Jaben
  0 siblings, 1 reply; 20+ messages in thread
From: Ni, Ruiyu @ 2016-10-18  1:55 UTC (permalink / raw)
  To: Tim Lewis, Vladimir Olovyannikov, Carsey, Jaben,
	edk2-devel@lists.01.org

Or we could have a common wrapper module, that links to different library to provide different <command>.efi.
This will require the name of the wrapper module is customizable. Haven't tried on that, seems doable.

Thanks/Ray

> -----Original Message-----
> From: Tim Lewis [mailto:tim.lewis@insyde.com]
> Sent: Tuesday, October 18, 2016 9:48 AM
> To: Ni, Ruiyu <ruiyu.ni@intel.com>; Vladimir Olovyannikov
> <vladimir.olovyannikov@broadcom.com>; Carsey, Jaben
> <jaben.carsey@intel.com>; edk2-devel@lists.01.org
> Subject: RE: [PATCH] GPT Shell Application/Library
> 
> We would prefer that this tool be external.  Tim
> 
> -----Original Message-----
> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of Ni,
> Ruiyu
> Sent: Monday, October 17, 2016 6:46 PM
> To: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>; Carsey,
> Jaben <jaben.carsey@intel.com>; edk2-devel@lists.01.org
> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> 
> Jaben,
> Do you think that providing a standalone gpt.efi is better? So that Shell.efi
> only provides the internal commands listed in Shell spec.
> 
> Thanks/Ray
> 
> > -----Original Message-----
> > From: Vladimir Olovyannikov
> [mailto:vladimir.olovyannikov@broadcom.com]
> > Sent: Sunday, October 16, 2016 1:24 PM
> > To: Carsey, Jaben <jaben.carsey@intel.com>; edk2-devel@lists.01.org; Ni,
> > Ruiyu <ruiyu.ni@intel.com>
> > Cc: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>
> > Subject: [PATCH] GPT Shell Application/Library
> >
> > This allows managing (create, delete, modify, fat format) of GPT
> > partitions from within UEFI Shell.
> > Syntax:
> > gpt <command> [device_mapped_name] [parameters...]
> > See usage examples in the .uni file
> > ---
> >  .../Library/UefiShellGptCommandLib/FatFormat.c     |  611 +++++++
> >  .../Library/UefiShellGptCommandLib/FatFormat.h     |  111 ++
> >  .../Library/UefiShellGptCommandLib/GptWorker.c     | 1902
> > ++++++++++++++++++++
> >  .../Library/UefiShellGptCommandLib/GptWorker.h     |  186 ++
> >  .../UefiShellGptCommandLib.c                       | 1135 ++++++++++++
> >  .../UefiShellGptCommandLib.inf                     |   79 +
> >  .../UefiShellGptCommandLib.uni                     |  117 ++
> >  ShellPkg/ShellPkg.dec                              |    1 +
> >  ShellPkg/ShellPkg.dsc                              |    4 +
> >  9 files changed, 4146 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..ba7904e6be28
> > --- /dev/null
> > +++ b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> > @@ -0,0 +1,611 @@
> > +/** @file
> > +
> > +  Copyright (c) 2003 - 2012, Rob Riglar, Ultra-Embedded.com. 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.
> > +
> > +**/
> > +
> > +/* Portions Copyright (c) 2016, Broadcom. All rights reserved */
> > +
> > +#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
> > +};
> > +
> > +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)));
> > +}
> > +
> > +//-----------------------------------------------------------------------------
> > +// fatfs_calc_cluster_size: Calculate what cluster size should be used
> > +//-----------------------------------------------------------------------------
> > +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;
> > +}
> > +//-----------------------------------------------------------------------------
> > +// fatfs_erase_sectors: Erase a number of 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;
> > +}
> > +//-----------------------------------------------------------------------------
> > +// fatfs_create_boot_sector: 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;
> > +}
> > +//-----------------------------------------------------------------------------
> > +// fatfs_create_fsinfo_sector: Create the FSInfo Sector (FAT32)
> > +//-----------------------------------------------------------------------------
> > +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;
> > +}
> > +//-----------------------------------------------------------------------------
> > +// fatfs_erase_fat: Erase FAT table using fs details in fs struct
> > +//-----------------------------------------------------------------------------
> > +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;
> > +}
> > +//-----------------------------------------------------------------------------
> > +// fatfs_format_fat16: Format a 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;
> > +}
> > +//-----------------------------------------------------------------------------
> > +// fatfs_format_fat32: Format a 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;
> > +}
> > +//-----------------------------------------------------------------------------
> > +// fatfs_format: Format a partition with either FAT16 or FAT32 based on
> size
> > +//-----------------------------------------------------------------------------
> > +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;
> > +
> > +  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 <= 4194304) && (!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..d1a325a57abe
> > --- /dev/null
> > +++ b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> > @@ -0,0 +1,111 @@
> > +/** @file
> > +
> > +  Copyright (c) 2003 - 2012, Ultra-Embedded.com. 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.
> > +
> > +**/
> > +
> > +/* Portions Copyright (c) 2016, Broadcom. All rights reserved */
> > +
> > +#ifndef __FAT_FORMAT_H__
> > +#define __FAT_FORMAT_H__
> > +
> > +#include "GptWorker.h"
> > +
> > +#define FAT_SECTOR_SIZE                     512
> > +#define FAT_BUFFER_SECTORS                    1
> > +#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 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..0546c94488b0
> > --- /dev/null
> > +++ b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> > @@ -0,0 +1,1902 @@
> > +/** @file
> > +Copyright (c) 2006 - 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)
> > +{
> > +  UINTN                Index;
> > +  EFI_PARTITION_ENTRY  *Entry;
> > +  EFI_LBA              Length;
> > +  UINTN                NumEntries; // Used entries
> > +  UINTN                BlockSize;
> > +  BOOLEAN              FirstTime;
> > +  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, 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 th 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] = { L'\0' };
> > +  CONST CHAR16 *StrUnknown = L"Unknown";
> > +  EFI_STATUS Status;
> > +  EFI_LBA Length;
> > +
> > +  ASSERT (Entry);
> > +
> > +  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, PartitionIdGuid;
> > +  EFI_STATUS  Status;
> > +  UINT64      StartBlock;
> > +  UINT64      EndBlock;
> > +  UINT64      SizeInBytes = 0;
> > +  UINT32      BlockSize;
> > +  UINT64      DiskSizeBlocks;
> > +  UINT8       *p;
> > +  BOOLEAN     OffsetSpecified = FALSE;
> > +  BOOLEAN     AllZeros;
> > +  INTN        AllZeroEntry;
> > +  INTN        OldFreeEntry;
> > +  UINT64      AvailBlocks;
> > +  UINT64      BlocksToAllocate;
> > +  UINT64      HighSeen;
> > +  UINTN       Slot;
> > +  UINT64      LowestAlignedLba;
> > +  UINT32      OptimalTransferBlocks;
> > +  UINTN       i, j;
> > +  CHAR16      PartNameUsed[MAX_PARTITION_NAME_LENGTH + 1] =
> { L'\0' };
> > +  EFI_PARTITION_ENTRY *Entry;
> > +
> > +  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..9efec5cefe94
> > --- /dev/null
> > +++ b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> > @@ -0,0 +1,186 @@
> > +/*
> > + *  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 <ShellBase.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) )
> > +
> > +
> > +//
> > +// 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 (
> > +  EFI_GUID Guid,
> > +  CHAR16 *PartTypeStr,
> > +  BOOLEAN NoGuidStr
> > +  );
> > +
> > +
> > +EFI_STATUS
> > +PartitionGptClearAll (
> > +  VOID
> > +  );
> > +
> > +EFI_STATUS
> > +PartitionGptCreatePartition (
> > +  CONST CHAR16 *PartName,
> > +  EFI_LBA StartLba,
> > +  EFI_LBA PartitionSize,
> > +  UINT64 Attributes,
> > +  EFI_GUID PartTypeGuid);
> > +
> > +EFI_STATUS
> > +PartitionGptModifyPartition (
> > +  EFI_PARTITION_ENTRY *Entry,
> > +  MOD_PARAMS *Params,
> > +  MOD_FLAGS Flags
> > +  );
> > +
> > +VOID
> > +GptCleanupGlobals (
> > +  VOID
> > +  );
> > +
> > +EFI_PARTITION_ENTRY *
> > +PartitionFindPartitionByCriteria (
> > +  CONST CHAR16   *Name,
> > +  EFI_LBA        StartLba,
> > +  EFI_LBA        EndingLba,
> > +  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..a9d74a780911
> > --- /dev/null
> > +++
> > b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> > @@ -0,0 +1,1135 @@
> >
> +/*********************************************************
> > **********************
> > +Copyright (C) 2016 Marvell International Ltd.
> > +
> > +Marvell BSD License Option
> > +
> > +If you received this File from Marvell, you may opt to use, redistribute
> > and/or
> > +modify this File under the following licensing terms.
> > +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.
> > +
> >
> +*********************************************************
> > **********************/
> > +
> > +/* Portions Copyright (C) 2016 Broadcom */
> > +
> > +#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 },
> > +  { L"-yes", TypeFlag },
> > +  { L"-verbose", TypeFlag },
> > +  { 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;
> > +}
> > +
> > +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;
> > +}
> > +
> > +VOID
> > +PrintErr (
> > +  IN CONST CHAR16 *Message,
> > +  IN EFI_STATUS Status
> > +  )
> > +{
> > +  ShellPrintHiiEx (-1, -1,
> > +                   NULL, STRING_TOKEN (STR_GPT_ERROR),
> > +                   gShellGptHiiHandle,
> > +                   gAppName,
> > +                   Status,
> > +                   Message
> > +                  );
> > +}
> > +
> > +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;
> > +}
> > +
> > +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;
> > +}
> > +
> > +STATIC
> > +VOID FormatSize(
> > +  UINT64 Size, CHAR16 *Buffer)
> > +{
> > +#define MAX_SIZE_BUF_SIZE 32
> > +  UINT64 Base, 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);
> > +  }
> > +}
> > +
> > +STATIC
> > +EFI_STATUS
> > +FindAndPrintPartitionableDevices (VOID)
> > +{
> > +  UINTN Index;
> > +  EFI_HANDLE      *HandlePointer;
> > +  UINTN           HandleCount;
> > +  UINTN           DevCount;
> > +  EFI_STATUS      Status;
> > +  BOOLEAN         FirstTime;
> > +
> > +  Status = gBS->LocateHandleBuffer (ByProtocol,
> &gEfiBlockIoProtocolGuid,
> > NULL, &HandleCount, &HandlePointer);
> > +  if (EFI_ERROR (Status)) {
> > +    return Status;
> > +  }
> > +
> > +  DevCount = 0;
> > +  FirstTime = TRUE;
> > +
> > +  for (Index = 0; Index < HandleCount; Index++) {
> > +    EFI_DEVICE_PATH       *DevicePath;
> > +    CONST CHAR16          *MapPath;
> > +    CHAR16                *Match;
> > +    EFI_BLOCK_IO          *BlkIo;
> > +    EFI_DISK_IO           *DiskIo;
> > +    CHAR16                *BufferForSize;
> > +
> > +    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));
> > +      ASSERT (BufferForSize);
> > +      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 ();
> > +  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 = 0, Offset = 0;
> > +  UINT64                    PartAttributes = 0;
> > +  EFI_GUID                  PartTypeGuid = { 0 };
> > +  SHELL_FILE_HANDLE         FileHandle = NULL;
> > +  UINT64                    ByteCount, FileSize;
> > +  UINTN                     I;
> > +  UINT8                     *Buffer = NULL, *FileBuffer = NULL;
> > +
> > +  CHAR16                    * ProblemParam,*FilePath;
> > +  CONST CHAR16              *AddressStr = NULL, *OffsetStr = NULL;
> > +  CONST CHAR16              *PartName = NULL, *NewPartName = NULL,
> > *AttrStr = NULL,
> > +    *GuidStr = NULL, *VolumeName = NULL;
> > +  CONST CHAR16              *LengthStr = NULL, *FileStr = NULL;
> > +  BOOLEAN                   AddrFlag = FALSE, LengthFlag = TRUE, FileFlag = FALSE,
> > GuidFlag = FALSE, OffsetFlag = TRUE;
> > +  BOOLEAN                   PartNameFlag = TRUE, NewPartNameFlag = FALSE,
> > AttrFlag = FALSE;
> > +  UINTN                     Flag = 0, CheckFlag = 0;
> > +  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, NoPrompt = FALSE, Quiet = TRUE;
> > +  UINT64                    TimeStampB, TimeStampE, SpeedKB, Freq;
> > +
> > +  // 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;
> > +  }
> > +
> > +  TimeStampB = 0;
> > +  TimeStampE = 0;
> > +
> > +  NoPrompt = ShellCommandLineGetFlag (CheckPackage, L"-yes");
> > +  Quiet = !ShellCommandLineGetFlag (CheckPackage, L"-verbose");
> > +
> > +  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.
> > +  // Generally command is:
> > +  // block_name:bootpart_no addr or filename offset
> > +
> > +  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);
> > +        Status = SHELL_ABORTED;
> > +      }
> > +      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;
> > +      }
> > +    }
> > +  }
> > +
> > +  // 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) {
> > +      Status = EFI_INVALID_PARAMETER;
> > +      PrintErr (L"Cannot write to a read-only device", Status);
> > +      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: GPT is valid on %s, but no partition(s) defined yet. Use
> > create\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:
> > +      Print (L"%s: Unsupported command. Try \"help %s\"", gAppName);
> > +      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);
> > +      Status = SHELL_ABORTED;
> > +      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);
> > +        Status = SHELL_ABORTED;
> > +        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);
> > +        Status = SHELL_ABORTED;
> > +        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:
> > +      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);
> > +          Status = SHELL_ABORTED;
> > +          goto CleanUp;
> > +        }
> > +        Status = SHELL_SUCCESS;
> > +      } else {
> > +        Status = SHELL_ABORTED;
> > +      }
> > +      break;
> > +    case FAT_FORMAT:
> > +    {
> > +      EFI_LBA StartingLBA, EndingLBA;
> > +      CHAR8                LabelName[12];
> > +
> > +      if (VolumeName) {
> > +        if (StrLen (VolumeName) > 11) {
> > +          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;
> > +        }
> > +        if (!Quiet) {
> > +          Print (L"Formatting %s to FAT32...\r", PartNameFlag ? Entry-
> > >PartitionName : BlockName);
> > +        }
> > +        Status = FatFormat (StartingLBA, EndingLBA, BlockIo, DiskIo,
> > VolumeName ? LabelName : NULL, TRUE);
> > +        if (EFI_ERROR (Status)) {
> > +          PrintErr (L"Error formatting the partition to FAT             ", Status);
> > +          Status = SHELL_ABORTED;
> > +          goto CleanUp;
> > +        } else if (!Quiet) {
> > +          Print (L"%s successfully formatted to FAT. Formatted size %llu
> MiB\n",
> > +                 PartNameFlag ? Entry->PartitionName : BlockName,
> > +                 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);
> > +    Status = SHELL_ABORTED;
> > +    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..1be4b1ab0f11
> > --- /dev/null
> > +++
> >
> b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> > @@ -0,0 +1,79 @@
> > +#
> > +# Marvell BSD License Option
> > +#
> > +# If you received this File from Marvell, you may opt to use, redistribute
> > +# and/or modify this File under the following licensing terms.
> > +# 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.
> > +#
> > +
> > +#
> > +# Portions Copyright (C) 2016 Broadcom
> > +#
> > +
> > +[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..55bcb42cfeb3
> > --- /dev/null
> > +++
> >
> b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
> > @@ -0,0 +1,117 @@
> >
> +/*********************************************************
> > **********************
> > +Copyright (C) 2016 Marvell International Ltd.
> > +
> > +Marvell BSD License Option
> > +
> > +If you received this File from Marvell, you may opt to use, redistribute
> > and/or
> > +modify this File under the following licensing terms.
> > +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.
> > +
> >
> +*********************************************************
> > **********************/
> > +
> > +/* Portions Copyright (C) 2016 Broadcom */
> > +/=#
> > +
> > +#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 clear the 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 to FAT32 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\r\n"
> > +".SH EXAMPLES\r\n"
> > +" \r\n"
> > +"EXAMPLES:\r\n"
> > +"Get the list of available partitionable block device(s)\r\n"
> > +"  gpt %Hlist%N\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 list 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 39f8012b98c1..5374a2a62d5f 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]
> >    gEfiShellProtocolGuid               = {0x6302d008, 0x7f9b, 0x4f30, {0x87, 0xac,
> > 0x60, 0xc9, 0xfe, 0xf5, 0xda, 0x4e}}
> > diff --git a/ShellPkg/ShellPkg.dsc b/ShellPkg/ShellPkg.dsc
> > index 809bd4220af2..984c1d0ad48b 100644
> > --- a/ShellPkg/ShellPkg.dsc
> > +++ b/ShellPkg/ShellPkg.dsc
> > @@ -89,6 +89,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
> > @@ -119,6 +120,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] 20+ messages in thread

* Re: [PATCH] GPT Shell Application/Library
  2016-10-18  1:55     ` Ni, Ruiyu
@ 2016-10-18  2:59       ` Carsey, Jaben
  0 siblings, 0 replies; 20+ messages in thread
From: Carsey, Jaben @ 2016-10-18  2:59 UTC (permalink / raw)
  To: Ni, Ruiyu, Tim Lewis, Vladimir Olovyannikov,
	edk2-devel@lists.01.org
  Cc: Carsey, Jaben

We already have additional libraries that people can compile at will for things like DP and TFTP.  We only include the documented commands in our binary shell deliveries.  I think that we can allow a library and could even consume that library and make a stand alone GPT.efi.

I think that the GPT command should not be included in the ShellBinPkg for sure.

-JAben

> -----Original Message-----
> From: Ni, Ruiyu
> Sent: Monday, October 17, 2016 6:55 PM
> To: Tim Lewis <tim.lewis@insyde.com>; Vladimir Olovyannikov
> <vladimir.olovyannikov@broadcom.com>; Carsey, Jaben
> <jaben.carsey@intel.com>; edk2-devel@lists.01.org
> Subject: RE: [PATCH] GPT Shell Application/Library
> Importance: High
> 
> Or we could have a common wrapper module, that links to different library to
> provide different <command>.efi.
> This will require the name of the wrapper module is customizable. Haven't tried
> on that, seems doable.
> 
> Thanks/Ray
> 
> > -----Original Message-----
> > From: Tim Lewis [mailto:tim.lewis@insyde.com]
> > Sent: Tuesday, October 18, 2016 9:48 AM
> > To: Ni, Ruiyu <ruiyu.ni@intel.com>; Vladimir Olovyannikov
> > <vladimir.olovyannikov@broadcom.com>; Carsey, Jaben
> > <jaben.carsey@intel.com>; edk2-devel@lists.01.org
> > Subject: RE: [PATCH] GPT Shell Application/Library
> >
> > We would prefer that this tool be external.  Tim
> >
> > -----Original Message-----
> > From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of Ni,
> > Ruiyu
> > Sent: Monday, October 17, 2016 6:46 PM
> > To: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>; Carsey,
> > Jaben <jaben.carsey@intel.com>; edk2-devel@lists.01.org
> > Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> >
> > Jaben,
> > Do you think that providing a standalone gpt.efi is better? So that Shell.efi
> > only provides the internal commands listed in Shell spec.
> >
> > Thanks/Ray
> >
> > > -----Original Message-----
> > > From: Vladimir Olovyannikov
> > [mailto:vladimir.olovyannikov@broadcom.com]
> > > Sent: Sunday, October 16, 2016 1:24 PM
> > > To: Carsey, Jaben <jaben.carsey@intel.com>; edk2-devel@lists.01.org; Ni,
> > > Ruiyu <ruiyu.ni@intel.com>
> > > Cc: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>
> > > Subject: [PATCH] GPT Shell Application/Library
> > >
> > > This allows managing (create, delete, modify, fat format) of GPT
> > > partitions from within UEFI Shell.
> > > Syntax:
> > > gpt <command> [device_mapped_name] [parameters...]
> > > See usage examples in the .uni file
> > > ---
> > >  .../Library/UefiShellGptCommandLib/FatFormat.c     |  611 +++++++
> > >  .../Library/UefiShellGptCommandLib/FatFormat.h     |  111 ++
> > >  .../Library/UefiShellGptCommandLib/GptWorker.c     | 1902
> > > ++++++++++++++++++++
> > >  .../Library/UefiShellGptCommandLib/GptWorker.h     |  186 ++
> > >  .../UefiShellGptCommandLib.c                       | 1135 ++++++++++++
> > >  .../UefiShellGptCommandLib.inf                     |   79 +
> > >  .../UefiShellGptCommandLib.uni                     |  117 ++
> > >  ShellPkg/ShellPkg.dec                              |    1 +
> > >  ShellPkg/ShellPkg.dsc                              |    4 +
> > >  9 files changed, 4146 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..ba7904e6be28
> > > --- /dev/null
> > > +++ b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> > > @@ -0,0 +1,611 @@
> > > +/** @file
> > > +
> > > +  Copyright (c) 2003 - 2012, Rob Riglar, Ultra-Embedded.com. 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.
> > > +
> > > +**/
> > > +
> > > +/* Portions Copyright (c) 2016, Broadcom. All rights reserved */
> > > +
> > > +#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
> > > +};
> > > +
> > > +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)));
> > > +}
> > > +
> > > +//-----------------------------------------------------------------------------
> > > +// fatfs_calc_cluster_size: Calculate what cluster size should be used
> > > +//-----------------------------------------------------------------------------
> > > +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;
> > > +}
> > > +//-----------------------------------------------------------------------------
> > > +// fatfs_erase_sectors: Erase a number of 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;
> > > +}
> > > +//-----------------------------------------------------------------------------
> > > +// fatfs_create_boot_sector: 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;
> > > +}
> > > +//-----------------------------------------------------------------------------
> > > +// fatfs_create_fsinfo_sector: Create the FSInfo Sector (FAT32)
> > > +//-----------------------------------------------------------------------------
> > > +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;
> > > +}
> > > +//-----------------------------------------------------------------------------
> > > +// fatfs_erase_fat: Erase FAT table using fs details in fs struct
> > > +//-----------------------------------------------------------------------------
> > > +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;
> > > +}
> > > +//-----------------------------------------------------------------------------
> > > +// fatfs_format_fat16: Format a 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;
> > > +}
> > > +//-----------------------------------------------------------------------------
> > > +// fatfs_format_fat32: Format a 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;
> > > +}
> > > +//-----------------------------------------------------------------------------
> > > +// fatfs_format: Format a partition with either FAT16 or FAT32 based on
> > size
> > > +//-----------------------------------------------------------------------------
> > > +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;
> > > +
> > > +  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 <= 4194304) && (!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..d1a325a57abe
> > > --- /dev/null
> > > +++ b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> > > @@ -0,0 +1,111 @@
> > > +/** @file
> > > +
> > > +  Copyright (c) 2003 - 2012, Ultra-Embedded.com. 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.
> > > +
> > > +**/
> > > +
> > > +/* Portions Copyright (c) 2016, Broadcom. All rights reserved */
> > > +
> > > +#ifndef __FAT_FORMAT_H__
> > > +#define __FAT_FORMAT_H__
> > > +
> > > +#include "GptWorker.h"
> > > +
> > > +#define FAT_SECTOR_SIZE                     512
> > > +#define FAT_BUFFER_SECTORS                    1
> > > +#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 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..0546c94488b0
> > > --- /dev/null
> > > +++ b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> > > @@ -0,0 +1,1902 @@
> > > +/** @file
> > > +Copyright (c) 2006 - 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)
> > > +{
> > > +  UINTN                Index;
> > > +  EFI_PARTITION_ENTRY  *Entry;
> > > +  EFI_LBA              Length;
> > > +  UINTN                NumEntries; // Used entries
> > > +  UINTN                BlockSize;
> > > +  BOOLEAN              FirstTime;
> > > +  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, 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 th 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] = { L'\0' };
> > > +  CONST CHAR16 *StrUnknown = L"Unknown";
> > > +  EFI_STATUS Status;
> > > +  EFI_LBA Length;
> > > +
> > > +  ASSERT (Entry);
> > > +
> > > +  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, PartitionIdGuid;
> > > +  EFI_STATUS  Status;
> > > +  UINT64      StartBlock;
> > > +  UINT64      EndBlock;
> > > +  UINT64      SizeInBytes = 0;
> > > +  UINT32      BlockSize;
> > > +  UINT64      DiskSizeBlocks;
> > > +  UINT8       *p;
> > > +  BOOLEAN     OffsetSpecified = FALSE;
> > > +  BOOLEAN     AllZeros;
> > > +  INTN        AllZeroEntry;
> > > +  INTN        OldFreeEntry;
> > > +  UINT64      AvailBlocks;
> > > +  UINT64      BlocksToAllocate;
> > > +  UINT64      HighSeen;
> > > +  UINTN       Slot;
> > > +  UINT64      LowestAlignedLba;
> > > +  UINT32      OptimalTransferBlocks;
> > > +  UINTN       i, j;
> > > +  CHAR16      PartNameUsed[MAX_PARTITION_NAME_LENGTH + 1] =
> > { L'\0' };
> > > +  EFI_PARTITION_ENTRY *Entry;
> > > +
> > > +  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..9efec5cefe94
> > > --- /dev/null
> > > +++ b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> > > @@ -0,0 +1,186 @@
> > > +/*
> > > + *  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 <ShellBase.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) )
> > > +
> > > +
> > > +//
> > > +// 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 (
> > > +  EFI_GUID Guid,
> > > +  CHAR16 *PartTypeStr,
> > > +  BOOLEAN NoGuidStr
> > > +  );
> > > +
> > > +
> > > +EFI_STATUS
> > > +PartitionGptClearAll (
> > > +  VOID
> > > +  );
> > > +
> > > +EFI_STATUS
> > > +PartitionGptCreatePartition (
> > > +  CONST CHAR16 *PartName,
> > > +  EFI_LBA StartLba,
> > > +  EFI_LBA PartitionSize,
> > > +  UINT64 Attributes,
> > > +  EFI_GUID PartTypeGuid);
> > > +
> > > +EFI_STATUS
> > > +PartitionGptModifyPartition (
> > > +  EFI_PARTITION_ENTRY *Entry,
> > > +  MOD_PARAMS *Params,
> > > +  MOD_FLAGS Flags
> > > +  );
> > > +
> > > +VOID
> > > +GptCleanupGlobals (
> > > +  VOID
> > > +  );
> > > +
> > > +EFI_PARTITION_ENTRY *
> > > +PartitionFindPartitionByCriteria (
> > > +  CONST CHAR16   *Name,
> > > +  EFI_LBA        StartLba,
> > > +  EFI_LBA        EndingLba,
> > > +  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..a9d74a780911
> > > --- /dev/null
> > > +++
> > > b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> > > @@ -0,0 +1,1135 @@
> > >
> > +/*********************************************************
> > > **********************
> > > +Copyright (C) 2016 Marvell International Ltd.
> > > +
> > > +Marvell BSD License Option
> > > +
> > > +If you received this File from Marvell, you may opt to use, redistribute
> > > and/or
> > > +modify this File under the following licensing terms.
> > > +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.
> > > +
> > >
> > +*********************************************************
> > > **********************/
> > > +
> > > +/* Portions Copyright (C) 2016 Broadcom */
> > > +
> > > +#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 },
> > > +  { L"-yes", TypeFlag },
> > > +  { L"-verbose", TypeFlag },
> > > +  { 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;
> > > +}
> > > +
> > > +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;
> > > +}
> > > +
> > > +VOID
> > > +PrintErr (
> > > +  IN CONST CHAR16 *Message,
> > > +  IN EFI_STATUS Status
> > > +  )
> > > +{
> > > +  ShellPrintHiiEx (-1, -1,
> > > +                   NULL, STRING_TOKEN (STR_GPT_ERROR),
> > > +                   gShellGptHiiHandle,
> > > +                   gAppName,
> > > +                   Status,
> > > +                   Message
> > > +                  );
> > > +}
> > > +
> > > +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;
> > > +}
> > > +
> > > +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;
> > > +}
> > > +
> > > +STATIC
> > > +VOID FormatSize(
> > > +  UINT64 Size, CHAR16 *Buffer)
> > > +{
> > > +#define MAX_SIZE_BUF_SIZE 32
> > > +  UINT64 Base, 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);
> > > +  }
> > > +}
> > > +
> > > +STATIC
> > > +EFI_STATUS
> > > +FindAndPrintPartitionableDevices (VOID)
> > > +{
> > > +  UINTN Index;
> > > +  EFI_HANDLE      *HandlePointer;
> > > +  UINTN           HandleCount;
> > > +  UINTN           DevCount;
> > > +  EFI_STATUS      Status;
> > > +  BOOLEAN         FirstTime;
> > > +
> > > +  Status = gBS->LocateHandleBuffer (ByProtocol,
> > &gEfiBlockIoProtocolGuid,
> > > NULL, &HandleCount, &HandlePointer);
> > > +  if (EFI_ERROR (Status)) {
> > > +    return Status;
> > > +  }
> > > +
> > > +  DevCount = 0;
> > > +  FirstTime = TRUE;
> > > +
> > > +  for (Index = 0; Index < HandleCount; Index++) {
> > > +    EFI_DEVICE_PATH       *DevicePath;
> > > +    CONST CHAR16          *MapPath;
> > > +    CHAR16                *Match;
> > > +    EFI_BLOCK_IO          *BlkIo;
> > > +    EFI_DISK_IO           *DiskIo;
> > > +    CHAR16                *BufferForSize;
> > > +
> > > +    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));
> > > +      ASSERT (BufferForSize);
> > > +      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 ();
> > > +  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 = 0, Offset = 0;
> > > +  UINT64                    PartAttributes = 0;
> > > +  EFI_GUID                  PartTypeGuid = { 0 };
> > > +  SHELL_FILE_HANDLE         FileHandle = NULL;
> > > +  UINT64                    ByteCount, FileSize;
> > > +  UINTN                     I;
> > > +  UINT8                     *Buffer = NULL, *FileBuffer = NULL;
> > > +
> > > +  CHAR16                    * ProblemParam,*FilePath;
> > > +  CONST CHAR16              *AddressStr = NULL, *OffsetStr = NULL;
> > > +  CONST CHAR16              *PartName = NULL, *NewPartName = NULL,
> > > *AttrStr = NULL,
> > > +    *GuidStr = NULL, *VolumeName = NULL;
> > > +  CONST CHAR16              *LengthStr = NULL, *FileStr = NULL;
> > > +  BOOLEAN                   AddrFlag = FALSE, LengthFlag = TRUE, FileFlag =
> FALSE,
> > > GuidFlag = FALSE, OffsetFlag = TRUE;
> > > +  BOOLEAN                   PartNameFlag = TRUE, NewPartNameFlag = FALSE,
> > > AttrFlag = FALSE;
> > > +  UINTN                     Flag = 0, CheckFlag = 0;
> > > +  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, NoPrompt = FALSE, Quiet = TRUE;
> > > +  UINT64                    TimeStampB, TimeStampE, SpeedKB, Freq;
> > > +
> > > +  // 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;
> > > +  }
> > > +
> > > +  TimeStampB = 0;
> > > +  TimeStampE = 0;
> > > +
> > > +  NoPrompt = ShellCommandLineGetFlag (CheckPackage, L"-yes");
> > > +  Quiet = !ShellCommandLineGetFlag (CheckPackage, L"-verbose");
> > > +
> > > +  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.
> > > +  // Generally command is:
> > > +  // block_name:bootpart_no addr or filename offset
> > > +
> > > +  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);
> > > +        Status = SHELL_ABORTED;
> > > +      }
> > > +      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;
> > > +      }
> > > +    }
> > > +  }
> > > +
> > > +  // 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) {
> > > +      Status = EFI_INVALID_PARAMETER;
> > > +      PrintErr (L"Cannot write to a read-only device", Status);
> > > +      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: GPT is valid on %s, but no partition(s) defined yet. Use
> > > create\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:
> > > +      Print (L"%s: Unsupported command. Try \"help %s\"", gAppName);
> > > +      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);
> > > +      Status = SHELL_ABORTED;
> > > +      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);
> > > +        Status = SHELL_ABORTED;
> > > +        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);
> > > +        Status = SHELL_ABORTED;
> > > +        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:
> > > +      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);
> > > +          Status = SHELL_ABORTED;
> > > +          goto CleanUp;
> > > +        }
> > > +        Status = SHELL_SUCCESS;
> > > +      } else {
> > > +        Status = SHELL_ABORTED;
> > > +      }
> > > +      break;
> > > +    case FAT_FORMAT:
> > > +    {
> > > +      EFI_LBA StartingLBA, EndingLBA;
> > > +      CHAR8                LabelName[12];
> > > +
> > > +      if (VolumeName) {
> > > +        if (StrLen (VolumeName) > 11) {
> > > +          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;
> > > +        }
> > > +        if (!Quiet) {
> > > +          Print (L"Formatting %s to FAT32...\r", PartNameFlag ? Entry-
> > > >PartitionName : BlockName);
> > > +        }
> > > +        Status = FatFormat (StartingLBA, EndingLBA, BlockIo, DiskIo,
> > > VolumeName ? LabelName : NULL, TRUE);
> > > +        if (EFI_ERROR (Status)) {
> > > +          PrintErr (L"Error formatting the partition to FAT             ", Status);
> > > +          Status = SHELL_ABORTED;
> > > +          goto CleanUp;
> > > +        } else if (!Quiet) {
> > > +          Print (L"%s successfully formatted to FAT. Formatted size %llu
> > MiB\n",
> > > +                 PartNameFlag ? Entry->PartitionName : BlockName,
> > > +                 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);
> > > +    Status = SHELL_ABORTED;
> > > +    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..1be4b1ab0f11
> > > --- /dev/null
> > > +++
> > >
> > b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> > > @@ -0,0 +1,79 @@
> > > +#
> > > +# Marvell BSD License Option
> > > +#
> > > +# If you received this File from Marvell, you may opt to use, redistribute
> > > +# and/or modify this File under the following licensing terms.
> > > +# 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.
> > > +#
> > > +
> > > +#
> > > +# Portions Copyright (C) 2016 Broadcom
> > > +#
> > > +
> > > +[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..55bcb42cfeb3
> > > --- /dev/null
> > > +++
> > >
> > b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
> > > @@ -0,0 +1,117 @@
> > >
> > +/*********************************************************
> > > **********************
> > > +Copyright (C) 2016 Marvell International Ltd.
> > > +
> > > +Marvell BSD License Option
> > > +
> > > +If you received this File from Marvell, you may opt to use, redistribute
> > > and/or
> > > +modify this File under the following licensing terms.
> > > +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.
> > > +
> > >
> > +*********************************************************
> > > **********************/
> > > +
> > > +/* Portions Copyright (C) 2016 Broadcom */
> > > +/=#
> > > +
> > > +#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 clear the 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 to FAT32 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\r\n"
> > > +".SH EXAMPLES\r\n"
> > > +" \r\n"
> > > +"EXAMPLES:\r\n"
> > > +"Get the list of available partitionable block device(s)\r\n"
> > > +"  gpt %Hlist%N\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 list 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 39f8012b98c1..5374a2a62d5f 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]
> > >    gEfiShellProtocolGuid               = {0x6302d008, 0x7f9b, 0x4f30, {0x87, 0xac,
> > > 0x60, 0xc9, 0xfe, 0xf5, 0xda, 0x4e}}
> > > diff --git a/ShellPkg/ShellPkg.dsc b/ShellPkg/ShellPkg.dsc
> > > index 809bd4220af2..984c1d0ad48b 100644
> > > --- a/ShellPkg/ShellPkg.dsc
> > > +++ b/ShellPkg/ShellPkg.dsc
> > > @@ -89,6 +89,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
> > > @@ -119,6 +120,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] 20+ messages in thread

* Re: [PATCH] GPT Shell Application/Library
  2016-10-17 17:56             ` Carsey, Jaben
@ 2016-10-18 13:59               ` Shah, Tapan
  2016-10-18 16:58                 ` Vladimir Olovyannikov
  0 siblings, 1 reply; 20+ messages in thread
From: Shah, Tapan @ 2016-10-18 13:59 UTC (permalink / raw)
  To: Carsey, Jaben, Vladimir Olovyannikov, Michael Zimmermann
  Cc: Ni, Ruiyu, Arshi, Shala, edk2-devel@lists.01.org, Laszlo Ersek

Thanks for the contribution Vladimir!

Few comments:
1. It's better to refactor the code now before commit and move GPT related code outside ShellPkg and create a shared library.
2. CLI parameters of this utility are too complex and need to be refactored to make it similar to other existing Shell commands.

Thanks,
Tapan

-----Original Message-----
From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of Carsey, Jaben
Sent: Monday, October 17, 2016 12:56 PM
To: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>; Michael Zimmermann <sigmaepsilon92@gmail.com>
Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Arshi, Shala <shala.arshi@intel.com>; edk2-devel@lists.01.org <edk2-devel@ml01.01.org>; Carsey, Jaben <jaben.carsey@intel.com>; Laszlo Ersek <lersek@redhat.com>
Subject: Re: [edk2] [PATCH] GPT Shell Application/Library

To the old question about license: I asked our people to check and was told that the license is compatible with our BSD and ok by Intel.

To the technical content – I really like this idea of a shared library.  That would be a great way to share code and not have as much duplicate.

-Jaben

From: Vladimir Olovyannikov [mailto:vladimir.olovyannikov@broadcom.com]
Sent: Monday, October 17, 2016 10:52 AM
To: Michael Zimmermann <sigmaepsilon92@gmail.com>
Cc: Laszlo Ersek <lersek@redhat.com>; Carsey, Jaben <jaben.carsey@intel.com>; Ni, Ruiyu <ruiyu.ni@intel.com>; edk2-devel@lists.01.org <edk2-devel@ml01.01.org>
Subject: RE: [edk2] [PATCH] GPT Shell Application/Library
Importance: High

Hi Michael,
I am absolutely agree with your proposal.

In the gpt Shell library/application I had to “borrow” some stuff from PartitionDxe.c to not reinvent a  wheel.
If the PartitionDxe maintainer agrees to have a separate library available for everybody, I would move all the GPT-related stuff from the GptWorker (and partially from the PartitionDxe itself) to that independent library.
This could be a longer-term task.
Right now I just wanted to share the tool which could be useful for anybody who would wish to manage GPT partitions (and/or do a FAT32 format of either a disk or a GPT partition) from within the Shell. What do you think?

Thank you,
Vladimir
From: Michael Zimmermann [mailto:sigmaepsilon92@gmail.com<mailto:sigmaepsilon92@gmail.com>]
Sent: October-17-16 12:25 AM
To: Vladimir Olovyannikov
Cc: Laszlo Ersek; Jaben Carsey; Ni, Ruiyu; edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
Subject: Re: [edk2] [PATCH] GPT Shell Application/Library

Hi,

wouldn't it be better to make a generic gpt parsing library which is independent of the shell so both the shell and PartitionDxe can use it?
It may also be useful for other applications which need additional information like the gpt partition names.

Thanks
Michael

On Mon, Oct 17, 2016 at 8:49 AM, Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com<mailto:vladimir.olovyannikov@broadcom.com>> wrote:
Thank you Laszlo,

Sorry, I missed the fields; it is my first contribution, I will add the required lines, review the source according to your comments and will resubmit the patch.
So do you think the command should be _gpt instead of gpt? I was following TFTP and SF commands as a template.

Thank you,
Vladimir

On Oct 16, 2016 1:05 PM, "Laszlo Ersek" <lersek@redhat.com<mailto:lersek@redhat.com>> wrote:
>
> On 10/16/16 07:23, Vladimir Olovyannikov wrote:
> > This allows managing (create, delete, modify, fat format) of GPT 
> > partitions from within UEFI Shell.
> > Syntax:
> > gpt <command> [device_mapped_name] [parameters...] See usage 
> > examples in the .uni file
> > ---
> >  .../Library/UefiShellGptCommandLib/FatFormat.c     |  611 +++++++
> >  .../Library/UefiShellGptCommandLib/FatFormat.h     |  111 ++
> >  .../Library/UefiShellGptCommandLib/GptWorker.c     | 1902
++++++++++++++++++++
> >  .../Library/UefiShellGptCommandLib/GptWorker.h     |  186 ++
> >  .../UefiShellGptCommandLib.c                       | 1135 ++++++++++++
> >  .../UefiShellGptCommandLib.inf                     |   79 +
> >  .../UefiShellGptCommandLib.uni                     |  117 ++
> >  ShellPkg/ShellPkg.dec                              |    1 +
> >  ShellPkg/ShellPkg.dsc                              |    4 +
> >  9 files changed, 4146 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
>
> This looks like a supremely welcome, long-awaited addition (latest
> request:
> <https://lists.01.org/pipermail/edk2-devel/2016-October/002667.html>),
> but it really needs your Signed-off-by, and the Contributed-under line 
> above it:
>
> ShellPkg/Contributions.txt
>
> I would also suggest (simply based on what I've seen elsewhere in 
> edk2) to keep the copyright notices tightly collected in the file headings.
>
> Someone will have to go over all the licenses too -- does the "Marvell 
> BSD License Option" for example correspond to the 3-clause BSDL?
>
> On the technical side, I believe that as long as a shell command (or a 
> command option) is not standardized (in the shell spec), it usually 
> starts with an underscore (_), so as to prevent future name collisions.
> (I could be wrong about this -- I now recall the TFTP command, which 
> is also not in the 2.2 spec.)
>
> Just my two cents.
>
> Thanks
> Laszlo
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
https://lists.01.org/mailman/listinfo/edk2-devel

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

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

* Re: [PATCH] GPT Shell Application/Library
  2016-10-18 13:59               ` Shah, Tapan
@ 2016-10-18 16:58                 ` Vladimir Olovyannikov
  2016-10-18 17:04                   ` Carsey, Jaben
  2016-10-18 17:23                   ` Laszlo Ersek
  0 siblings, 2 replies; 20+ messages in thread
From: Vladimir Olovyannikov @ 2016-10-18 16:58 UTC (permalink / raw)
  To: Shah, Tapan, Carsey, Jaben, Michael Zimmermann
  Cc: Ni, Ruiyu, Arshi, Shala, edk2-devel@lists.01.org, Laszlo Ersek

Thank you all for comments,

So to summarize the discussion:

1. I will create a Shell library which would perform all GPT operations.
     Part of PartitionDxe will also be in that library so PartitionDxe will
be using it.
     The gpt Shell tool will also be using it.
2.  Refactor the parameters of the gpt utility to make it similar to other
existing Shell commands.
      BTW Is there any document describing Shell utility parameters'
standards?

Please let me know if you have other suggestions.

Thank you,
Vladimir

-----Original Message-----
From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of Shah,
Tapan
Sent: October-18-16 6:59 AM
To: Carsey, Jaben; Vladimir Olovyannikov; Michael Zimmermann
Cc: Ni, Ruiyu; Arshi, Shala; edk2-devel@lists.01.org; Laszlo Ersek
Subject: Re: [edk2] [PATCH] GPT Shell Application/Library

Thanks for the contribution Vladimir!

Few comments:
1. It's better to refactor the code now before commit and move GPT related
code outside ShellPkg and create a shared library.
2. CLI parameters of this utility are too complex and need to be refactored
to make it similar to other existing Shell commands.

Thanks,
Tapan

-----Original Message-----
From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
Carsey, Jaben
Sent: Monday, October 17, 2016 12:56 PM
To: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>; Michael
Zimmermann <sigmaepsilon92@gmail.com>
Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Arshi, Shala <shala.arshi@intel.com>;
edk2-devel@lists.01.org <edk2-devel@ml01.01.org>; Carsey, Jaben
<jaben.carsey@intel.com>; Laszlo Ersek <lersek@redhat.com>
Subject: Re: [edk2] [PATCH] GPT Shell Application/Library

To the old question about license: I asked our people to check and was told
that the license is compatible with our BSD and ok by Intel.

To the technical content – I really like this idea of a shared library.
That would be a great way to share code and not have as much duplicate.

-Jaben

From: Vladimir Olovyannikov [mailto:vladimir.olovyannikov@broadcom.com]
Sent: Monday, October 17, 2016 10:52 AM
To: Michael Zimmermann <sigmaepsilon92@gmail.com>
Cc: Laszlo Ersek <lersek@redhat.com>; Carsey, Jaben
<jaben.carsey@intel.com>; Ni, Ruiyu <ruiyu.ni@intel.com>;
edk2-devel@lists.01.org <edk2-devel@ml01.01.org>
Subject: RE: [edk2] [PATCH] GPT Shell Application/Library
Importance: High

Hi Michael,
I am absolutely agree with your proposal.

In the gpt Shell library/application I had to “borrow” some stuff from
PartitionDxe.c to not reinvent a  wheel.
If the PartitionDxe maintainer agrees to have a separate library available
for everybody, I would move all the GPT-related stuff from the GptWorker
(and partially from the PartitionDxe itself) to that independent library.
This could be a longer-term task.
Right now I just wanted to share the tool which could be useful for anybody
who would wish to manage GPT partitions (and/or do a FAT32 format of either
a disk or a GPT partition) from within the Shell. What do you think?

Thank you,
Vladimir
From: Michael Zimmermann
[mailto:sigmaepsilon92@gmail.com<mailto:sigmaepsilon92@gmail.com>]
Sent: October-17-16 12:25 AM
To: Vladimir Olovyannikov
Cc: Laszlo Ersek; Jaben Carsey; Ni, Ruiyu;
edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
Subject: Re: [edk2] [PATCH] GPT Shell Application/Library

Hi,

wouldn't it be better to make a generic gpt parsing library which is
independent of the shell so both the shell and PartitionDxe can use it?
It may also be useful for other applications which need additional
information like the gpt partition names.

Thanks
Michael

On Mon, Oct 17, 2016 at 8:49 AM, Vladimir Olovyannikov
<vladimir.olovyannikov@broadcom.com<mailto:vladimir.olovyannikov@broadcom.com>>
wrote:
Thank you Laszlo,

Sorry, I missed the fields; it is my first contribution, I will add the
required lines, review the source according to your comments and will
resubmit the patch.
So do you think the command should be _gpt instead of gpt? I was following
TFTP and SF commands as a template.

Thank you,
Vladimir

On Oct 16, 2016 1:05 PM, "Laszlo Ersek"
<lersek@redhat.com<mailto:lersek@redhat.com>> wrote:
>
> On 10/16/16 07:23, Vladimir Olovyannikov wrote:
> > This allows managing (create, delete, modify, fat format) of GPT
> > partitions from within UEFI Shell.
> > Syntax:
> > gpt <command> [device_mapped_name] [parameters...] See usage
> > examples in the .uni file
> > ---
> >  .../Library/UefiShellGptCommandLib/FatFormat.c     |  611 +++++++
> >  .../Library/UefiShellGptCommandLib/FatFormat.h     |  111 ++
> >  .../Library/UefiShellGptCommandLib/GptWorker.c     | 1902
++++++++++++++++++++
> >  .../Library/UefiShellGptCommandLib/GptWorker.h     |  186 ++
> >  .../UefiShellGptCommandLib.c                       | 1135 ++++++++++++
> >  .../UefiShellGptCommandLib.inf                     |   79 +
> >  .../UefiShellGptCommandLib.uni                     |  117 ++
> >  ShellPkg/ShellPkg.dec                              |    1 +
> >  ShellPkg/ShellPkg.dsc                              |    4 +
> >  9 files changed, 4146 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
>
> This looks like a supremely welcome, long-awaited addition (latest
> request:
> <https://lists.01.org/pipermail/edk2-devel/2016-October/002667.html>),
> but it really needs your Signed-off-by, and the Contributed-under line
> above it:
>
> ShellPkg/Contributions.txt
>
> I would also suggest (simply based on what I've seen elsewhere in
> edk2) to keep the copyright notices tightly collected in the file
> headings.
>
> Someone will have to go over all the licenses too -- does the "Marvell
> BSD License Option" for example correspond to the 3-clause BSDL?
>
> On the technical side, I believe that as long as a shell command (or a
> command option) is not standardized (in the shell spec), it usually
> starts with an underscore (_), so as to prevent future name collisions.
> (I could be wrong about this -- I now recall the TFTP command, which
> is also not in the 2.2 spec.)
>
> Just my two cents.
>
> Thanks
> Laszlo
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
https://lists.01.org/mailman/listinfo/edk2-devel

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel


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

* Re: [PATCH] GPT Shell Application/Library
  2016-10-18 16:58                 ` Vladimir Olovyannikov
@ 2016-10-18 17:04                   ` Carsey, Jaben
  2016-10-18 18:03                     ` Shah, Tapan
  2016-10-18 17:23                   ` Laszlo Ersek
  1 sibling, 1 reply; 20+ messages in thread
From: Carsey, Jaben @ 2016-10-18 17:04 UTC (permalink / raw)
  To: Vladimir Olovyannikov, Shah, Tapan, Michael Zimmermann
  Cc: Ni, Ruiyu, Arshi, Shala, edk2-devel@lists.01.org, Laszlo Ersek,
	Carsey, Jaben

For the standards, I would try to use the UEFI Shell Spec for some parameters.  For Example:
-v for verbose
-h for help
-sfo for standard format output

> -----Original Message-----
> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
> Vladimir Olovyannikov
> Sent: Tuesday, October 18, 2016 9:58 AM
> To: Shah, Tapan <tapandshah@hpe.com>; Carsey, Jaben
> <jaben.carsey@intel.com>; Michael Zimmermann
> <sigmaepsilon92@gmail.com>
> Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Arshi, Shala <shala.arshi@intel.com>;
> edk2-devel@lists.01.org <edk2-devel@ml01.01.org>; Laszlo Ersek
> <lersek@redhat.com>
> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> Importance: High
> 
> Thank you all for comments,
> 
> So to summarize the discussion:
> 
> 1. I will create a Shell library which would perform all GPT operations.
>      Part of PartitionDxe will also be in that library so PartitionDxe will
> be using it.
>      The gpt Shell tool will also be using it.
> 2.  Refactor the parameters of the gpt utility to make it similar to other
> existing Shell commands.
>       BTW Is there any document describing Shell utility parameters'
> standards?
> 
> Please let me know if you have other suggestions.
> 
> Thank you,
> Vladimir
> 
> -----Original Message-----
> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
> Shah,
> Tapan
> Sent: October-18-16 6:59 AM
> To: Carsey, Jaben; Vladimir Olovyannikov; Michael Zimmermann
> Cc: Ni, Ruiyu; Arshi, Shala; edk2-devel@lists.01.org; Laszlo Ersek
> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> 
> Thanks for the contribution Vladimir!
> 
> Few comments:
> 1. It's better to refactor the code now before commit and move GPT related
> code outside ShellPkg and create a shared library.
> 2. CLI parameters of this utility are too complex and need to be refactored
> to make it similar to other existing Shell commands.
> 
> Thanks,
> Tapan
> 
> -----Original Message-----
> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
> Carsey, Jaben
> Sent: Monday, October 17, 2016 12:56 PM
> To: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>; Michael
> Zimmermann <sigmaepsilon92@gmail.com>
> Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Arshi, Shala <shala.arshi@intel.com>;
> edk2-devel@lists.01.org <edk2-devel@ml01.01.org>; Carsey, Jaben
> <jaben.carsey@intel.com>; Laszlo Ersek <lersek@redhat.com>
> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> 
> To the old question about license: I asked our people to check and was told
> that the license is compatible with our BSD and ok by Intel.
> 
> To the technical content – I really like this idea of a shared library.
> That would be a great way to share code and not have as much duplicate.
> 
> -Jaben
> 
> From: Vladimir Olovyannikov [mailto:vladimir.olovyannikov@broadcom.com]
> Sent: Monday, October 17, 2016 10:52 AM
> To: Michael Zimmermann <sigmaepsilon92@gmail.com>
> Cc: Laszlo Ersek <lersek@redhat.com>; Carsey, Jaben
> <jaben.carsey@intel.com>; Ni, Ruiyu <ruiyu.ni@intel.com>;
> edk2-devel@lists.01.org <edk2-devel@ml01.01.org>
> Subject: RE: [edk2] [PATCH] GPT Shell Application/Library
> Importance: High
> 
> Hi Michael,
> I am absolutely agree with your proposal.
> 
> In the gpt Shell library/application I had to “borrow” some stuff from
> PartitionDxe.c to not reinvent a  wheel.
> If the PartitionDxe maintainer agrees to have a separate library available
> for everybody, I would move all the GPT-related stuff from the GptWorker
> (and partially from the PartitionDxe itself) to that independent library.
> This could be a longer-term task.
> Right now I just wanted to share the tool which could be useful for anybody
> who would wish to manage GPT partitions (and/or do a FAT32 format of
> either
> a disk or a GPT partition) from within the Shell. What do you think?
> 
> Thank you,
> Vladimir
> From: Michael Zimmermann
> [mailto:sigmaepsilon92@gmail.com<mailto:sigmaepsilon92@gmail.com>]
> Sent: October-17-16 12:25 AM
> To: Vladimir Olovyannikov
> Cc: Laszlo Ersek; Jaben Carsey; Ni, Ruiyu;
> edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> 
> Hi,
> 
> wouldn't it be better to make a generic gpt parsing library which is
> independent of the shell so both the shell and PartitionDxe can use it?
> It may also be useful for other applications which need additional
> information like the gpt partition names.
> 
> Thanks
> Michael
> 
> On Mon, Oct 17, 2016 at 8:49 AM, Vladimir Olovyannikov
> <vladimir.olovyannikov@broadcom.com<mailto:vladimir.olovyannikov@broa
> dcom.com>>
> wrote:
> Thank you Laszlo,
> 
> Sorry, I missed the fields; it is my first contribution, I will add the
> required lines, review the source according to your comments and will
> resubmit the patch.
> So do you think the command should be _gpt instead of gpt? I was following
> TFTP and SF commands as a template.
> 
> Thank you,
> Vladimir
> 
> On Oct 16, 2016 1:05 PM, "Laszlo Ersek"
> <lersek@redhat.com<mailto:lersek@redhat.com>> wrote:
> >
> > On 10/16/16 07:23, Vladimir Olovyannikov wrote:
> > > This allows managing (create, delete, modify, fat format) of GPT
> > > partitions from within UEFI Shell.
> > > Syntax:
> > > gpt <command> [device_mapped_name] [parameters...] See usage
> > > examples in the .uni file
> > > ---
> > >  .../Library/UefiShellGptCommandLib/FatFormat.c     |  611 +++++++
> > >  .../Library/UefiShellGptCommandLib/FatFormat.h     |  111 ++
> > >  .../Library/UefiShellGptCommandLib/GptWorker.c     | 1902
> ++++++++++++++++++++
> > >  .../Library/UefiShellGptCommandLib/GptWorker.h     |  186 ++
> > >  .../UefiShellGptCommandLib.c                       | 1135 ++++++++++++
> > >  .../UefiShellGptCommandLib.inf                     |   79 +
> > >  .../UefiShellGptCommandLib.uni                     |  117 ++
> > >  ShellPkg/ShellPkg.dec                              |    1 +
> > >  ShellPkg/ShellPkg.dsc                              |    4 +
> > >  9 files changed, 4146 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
> >
> > This looks like a supremely welcome, long-awaited addition (latest
> > request:
> > <https://lists.01.org/pipermail/edk2-devel/2016-October/002667.html>),
> > but it really needs your Signed-off-by, and the Contributed-under line
> > above it:
> >
> > ShellPkg/Contributions.txt
> >
> > I would also suggest (simply based on what I've seen elsewhere in
> > edk2) to keep the copyright notices tightly collected in the file
> > headings.
> >
> > Someone will have to go over all the licenses too -- does the "Marvell
> > BSD License Option" for example correspond to the 3-clause BSDL?
> >
> > On the technical side, I believe that as long as a shell command (or a
> > command option) is not standardized (in the shell spec), it usually
> > starts with an underscore (_), so as to prevent future name collisions.
> > (I could be wrong about this -- I now recall the TFTP command, which
> > is also not in the 2.2 spec.)
> >
> > Just my two cents.
> >
> > Thanks
> > Laszlo
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
> https://lists.01.org/mailman/listinfo/edk2-devel
> 
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel

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

* Re: [PATCH] GPT Shell Application/Library
  2016-10-18 16:58                 ` Vladimir Olovyannikov
  2016-10-18 17:04                   ` Carsey, Jaben
@ 2016-10-18 17:23                   ` Laszlo Ersek
  2016-10-18 18:03                     ` Vladimir Olovyannikov
  1 sibling, 1 reply; 20+ messages in thread
From: Laszlo Ersek @ 2016-10-18 17:23 UTC (permalink / raw)
  To: Vladimir Olovyannikov, Shah, Tapan, Carsey, Jaben,
	Michael Zimmermann
  Cc: Ni, Ruiyu, Arshi, Shala, edk2-devel@lists.01.org

On 10/18/16 18:58, Vladimir Olovyannikov wrote:
> Thank you all for comments,
> 
> So to summarize the discussion:
> 
> 1. I will create a Shell library which would perform all GPT operations.
>      Part of PartitionDxe will also be in that library so PartitionDxe will
> be using it.
>      The gpt Shell tool will also be using it.

I think you might want to place the library class header file, and the
library instance, under MdeModulePkg. It's okay for the shell
application (or shell libraries) to depend on library classes / library
instances from MdeModulePkg, but -- I think -- it's not okay for a
driver in MdeModulePkg, such as PartitionDxe, to depend on a class +
instance from under ShellPkg.

Thanks!
Laszlo

> 2.  Refactor the parameters of the gpt utility to make it similar to other
> existing Shell commands.
>       BTW Is there any document describing Shell utility parameters'
> standards?
> 
> Please let me know if you have other suggestions.
> 
> Thank you,
> Vladimir
> 
> -----Original Message-----
> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of Shah,
> Tapan
> Sent: October-18-16 6:59 AM
> To: Carsey, Jaben; Vladimir Olovyannikov; Michael Zimmermann
> Cc: Ni, Ruiyu; Arshi, Shala; edk2-devel@lists.01.org; Laszlo Ersek
> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> 
> Thanks for the contribution Vladimir!
> 
> Few comments:
> 1. It's better to refactor the code now before commit and move GPT related
> code outside ShellPkg and create a shared library.
> 2. CLI parameters of this utility are too complex and need to be refactored
> to make it similar to other existing Shell commands.
> 
> Thanks,
> Tapan
> 
> -----Original Message-----
> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
> Carsey, Jaben
> Sent: Monday, October 17, 2016 12:56 PM
> To: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>; Michael
> Zimmermann <sigmaepsilon92@gmail.com>
> Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Arshi, Shala <shala.arshi@intel.com>;
> edk2-devel@lists.01.org <edk2-devel@ml01.01.org>; Carsey, Jaben
> <jaben.carsey@intel.com>; Laszlo Ersek <lersek@redhat.com>
> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> 
> To the old question about license: I asked our people to check and was told
> that the license is compatible with our BSD and ok by Intel.
> 
> To the technical content – I really like this idea of a shared library.
> That would be a great way to share code and not have as much duplicate.
> 
> -Jaben
> 
> From: Vladimir Olovyannikov [mailto:vladimir.olovyannikov@broadcom.com]
> Sent: Monday, October 17, 2016 10:52 AM
> To: Michael Zimmermann <sigmaepsilon92@gmail.com>
> Cc: Laszlo Ersek <lersek@redhat.com>; Carsey, Jaben
> <jaben.carsey@intel.com>; Ni, Ruiyu <ruiyu.ni@intel.com>;
> edk2-devel@lists.01.org <edk2-devel@ml01.01.org>
> Subject: RE: [edk2] [PATCH] GPT Shell Application/Library
> Importance: High
> 
> Hi Michael,
> I am absolutely agree with your proposal.
> 
> In the gpt Shell library/application I had to “borrow” some stuff from
> PartitionDxe.c to not reinvent a  wheel.
> If the PartitionDxe maintainer agrees to have a separate library available
> for everybody, I would move all the GPT-related stuff from the GptWorker
> (and partially from the PartitionDxe itself) to that independent library.
> This could be a longer-term task.
> Right now I just wanted to share the tool which could be useful for anybody
> who would wish to manage GPT partitions (and/or do a FAT32 format of either
> a disk or a GPT partition) from within the Shell. What do you think?
> 
> Thank you,
> Vladimir
> From: Michael Zimmermann
> [mailto:sigmaepsilon92@gmail.com<mailto:sigmaepsilon92@gmail.com>]
> Sent: October-17-16 12:25 AM
> To: Vladimir Olovyannikov
> Cc: Laszlo Ersek; Jaben Carsey; Ni, Ruiyu;
> edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> 
> Hi,
> 
> wouldn't it be better to make a generic gpt parsing library which is
> independent of the shell so both the shell and PartitionDxe can use it?
> It may also be useful for other applications which need additional
> information like the gpt partition names.
> 
> Thanks
> Michael
> 
> On Mon, Oct 17, 2016 at 8:49 AM, Vladimir Olovyannikov
> <vladimir.olovyannikov@broadcom.com<mailto:vladimir.olovyannikov@broadcom.com>>
> wrote:
> Thank you Laszlo,
> 
> Sorry, I missed the fields; it is my first contribution, I will add the
> required lines, review the source according to your comments and will
> resubmit the patch.
> So do you think the command should be _gpt instead of gpt? I was following
> TFTP and SF commands as a template.
> 
> Thank you,
> Vladimir
> 
> On Oct 16, 2016 1:05 PM, "Laszlo Ersek"
> <lersek@redhat.com<mailto:lersek@redhat.com>> wrote:
>>
>> On 10/16/16 07:23, Vladimir Olovyannikov wrote:
>>> This allows managing (create, delete, modify, fat format) of GPT
>>> partitions from within UEFI Shell.
>>> Syntax:
>>> gpt <command> [device_mapped_name] [parameters...] See usage
>>> examples in the .uni file
>>> ---
>>>  .../Library/UefiShellGptCommandLib/FatFormat.c     |  611 +++++++
>>>  .../Library/UefiShellGptCommandLib/FatFormat.h     |  111 ++
>>>  .../Library/UefiShellGptCommandLib/GptWorker.c     | 1902
> ++++++++++++++++++++
>>>  .../Library/UefiShellGptCommandLib/GptWorker.h     |  186 ++
>>>  .../UefiShellGptCommandLib.c                       | 1135 ++++++++++++
>>>  .../UefiShellGptCommandLib.inf                     |   79 +
>>>  .../UefiShellGptCommandLib.uni                     |  117 ++
>>>  ShellPkg/ShellPkg.dec                              |    1 +
>>>  ShellPkg/ShellPkg.dsc                              |    4 +
>>>  9 files changed, 4146 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
>>
>> This looks like a supremely welcome, long-awaited addition (latest
>> request:
>> <https://lists.01.org/pipermail/edk2-devel/2016-October/002667.html>),
>> but it really needs your Signed-off-by, and the Contributed-under line
>> above it:
>>
>> ShellPkg/Contributions.txt
>>
>> I would also suggest (simply based on what I've seen elsewhere in
>> edk2) to keep the copyright notices tightly collected in the file
>> headings.
>>
>> Someone will have to go over all the licenses too -- does the "Marvell
>> BSD License Option" for example correspond to the 3-clause BSDL?
>>
>> On the technical side, I believe that as long as a shell command (or a
>> command option) is not standardized (in the shell spec), it usually
>> starts with an underscore (_), so as to prevent future name collisions.
>> (I could be wrong about this -- I now recall the TFTP command, which
>> is also not in the 2.2 spec.)
>>
>> Just my two cents.
>>
>> Thanks
>> Laszlo
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
> https://lists.01.org/mailman/listinfo/edk2-devel
> 
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel
> 



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

* Re: [PATCH] GPT Shell Application/Library
  2016-10-18 17:23                   ` Laszlo Ersek
@ 2016-10-18 18:03                     ` Vladimir Olovyannikov
  2016-10-18 18:12                       ` Laszlo Ersek
  0 siblings, 1 reply; 20+ messages in thread
From: Vladimir Olovyannikov @ 2016-10-18 18:03 UTC (permalink / raw)
  To: Laszlo Ersek, Shah, Tapan, Carsey, Jaben, Michael Zimmermann
  Cc: Ni, Ruiyu, Arshi, Shala, edk2-devel@lists.01.org

> -----Original Message-----
> From: Laszlo Ersek [mailto:lersek@redhat.com]
> Sent: October-18-16 10:24 AM
> To: Vladimir Olovyannikov; Shah, Tapan; Carsey, Jaben; Michael Zimmermann
> Cc: Ni, Ruiyu; Arshi, Shala; edk2-devel@lists.01.org
> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
>
> On 10/18/16 18:58, Vladimir Olovyannikov wrote:
> > Thank you all for comments,
> >
> > So to summarize the discussion:
> >
> > 1. I will create a Shell library which would perform all GPT operations.
> >      Part of PartitionDxe will also be in that library so PartitionDxe
> > will be using it.
> >      The gpt Shell tool will also be using it.
>
> I think you might want to place the library class header file, and the
> library
> instance, under MdeModulePkg. It's okay for the shell application (or
> shell
> libraries) to depend on library classes / library instances from
> MdeModulePkg, but -- I think -- it's not okay for a driver in
> MdeModulePkg,
> such as PartitionDxe, to depend on a class + instance from under ShellPkg.
Laszlo,
I think PartitionDxe will depend on the GPT shared library (which will have
nothing to do to the ShellPkg),
as well as gpt tool (Shell library/application) will depend on that shared
library as well to get information regarding partitions and
to perform GPT management.

Thank you,
Vladimir
>
> Thanks!
> Laszlo
>
> > 2.  Refactor the parameters of the gpt utility to make it similar to
> > other existing Shell commands.
> >       BTW Is there any document describing Shell utility parameters'
> > standards?
> >
> > Please let me know if you have other suggestions.
> >
> > Thank you,
> > Vladimir
> >
> > -----Original Message-----
> > From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
> > Shah, Tapan
> > Sent: October-18-16 6:59 AM
> > To: Carsey, Jaben; Vladimir Olovyannikov; Michael Zimmermann
> > Cc: Ni, Ruiyu; Arshi, Shala; edk2-devel@lists.01.org; Laszlo Ersek
> > Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> >
> > Thanks for the contribution Vladimir!
> >
> > Few comments:
> > 1. It's better to refactor the code now before commit and move GPT
> > related code outside ShellPkg and create a shared library.
> > 2. CLI parameters of this utility are too complex and need to be
> > refactored to make it similar to other existing Shell commands.
> >
> > Thanks,
> > Tapan
> >
> > -----Original Message-----
> > From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
> > Carsey, Jaben
> > Sent: Monday, October 17, 2016 12:56 PM
> > To: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>;
> > Michael Zimmermann <sigmaepsilon92@gmail.com>
> > Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Arshi, Shala
> > <shala.arshi@intel.com>; edk2-devel@lists.01.org
> > <edk2-devel@ml01.01.org>; Carsey, Jaben <jaben.carsey@intel.com>;
> > Laszlo Ersek <lersek@redhat.com>
> > Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> >
> > To the old question about license: I asked our people to check and was
> > told that the license is compatible with our BSD and ok by Intel.
> >
> > To the technical content – I really like this idea of a shared library.
> > That would be a great way to share code and not have as much duplicate.
> >
> > -Jaben
> >
> > From: Vladimir Olovyannikov
> > [mailto:vladimir.olovyannikov@broadcom.com]
> > Sent: Monday, October 17, 2016 10:52 AM
> > To: Michael Zimmermann <sigmaepsilon92@gmail.com>
> > Cc: Laszlo Ersek <lersek@redhat.com>; Carsey, Jaben
> > <jaben.carsey@intel.com>; Ni, Ruiyu <ruiyu.ni@intel.com>;
> > edk2-devel@lists.01.org <edk2-devel@ml01.01.org>
> > Subject: RE: [edk2] [PATCH] GPT Shell Application/Library
> > Importance: High
> >
> > Hi Michael,
> > I am absolutely agree with your proposal.
> >
> > In the gpt Shell library/application I had to “borrow” some stuff from
> > PartitionDxe.c to not reinvent a  wheel.
> > If the PartitionDxe maintainer agrees to have a separate library
> > available for everybody, I would move all the GPT-related stuff from
> > the GptWorker (and partially from the PartitionDxe itself) to that
> independent library.
> > This could be a longer-term task.
> > Right now I just wanted to share the tool which could be useful for
> > anybody who would wish to manage GPT partitions (and/or do a FAT32
> > format of either a disk or a GPT partition) from within the Shell. What
> > do
> you think?
> >
> > Thank you,
> > Vladimir
> > From: Michael Zimmermann
> > [mailto:sigmaepsilon92@gmail.com<mailto:sigmaepsilon92@gmail.com>]
> > Sent: October-17-16 12:25 AM
> > To: Vladimir Olovyannikov
> > Cc: Laszlo Ersek; Jaben Carsey; Ni, Ruiyu;
> > edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
> > Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> >
> > Hi,
> >
> > wouldn't it be better to make a generic gpt parsing library which is
> > independent of the shell so both the shell and PartitionDxe can use it?
> > It may also be useful for other applications which need additional
> > information like the gpt partition names.
> >
> > Thanks
> > Michael
> >
> > On Mon, Oct 17, 2016 at 8:49 AM, Vladimir Olovyannikov
> >
> <vladimir.olovyannikov@broadcom.com<mailto:vladimir.olovyannikov@broa
> d
> > com.com>>
> > wrote:
> > Thank you Laszlo,
> >
> > Sorry, I missed the fields; it is my first contribution, I will add
> > the required lines, review the source according to your comments and
> > will resubmit the patch.
> > So do you think the command should be _gpt instead of gpt? I was
> > following TFTP and SF commands as a template.
> >
> > Thank you,
> > Vladimir
> >
> > On Oct 16, 2016 1:05 PM, "Laszlo Ersek"
> > <lersek@redhat.com<mailto:lersek@redhat.com>> wrote:
> >>
> >> On 10/16/16 07:23, Vladimir Olovyannikov wrote:
> >>> This allows managing (create, delete, modify, fat format) of GPT
> >>> partitions from within UEFI Shell.
> >>> Syntax:
> >>> gpt <command> [device_mapped_name] [parameters...] See usage
> >>> examples in the .uni file
> >>> ---
> >>>  .../Library/UefiShellGptCommandLib/FatFormat.c     |  611 +++++++
> >>>  .../Library/UefiShellGptCommandLib/FatFormat.h     |  111 ++
> >>>  .../Library/UefiShellGptCommandLib/GptWorker.c     | 1902
> > ++++++++++++++++++++
> >>>  .../Library/UefiShellGptCommandLib/GptWorker.h     |  186 ++
> >>>  .../UefiShellGptCommandLib.c                       | 1135
> >>> ++++++++++++
> >>>  .../UefiShellGptCommandLib.inf                     |   79 +
> >>>  .../UefiShellGptCommandLib.uni                     |  117 ++
> >>>  ShellPkg/ShellPkg.dec                              |    1 +
> >>>  ShellPkg/ShellPkg.dsc                              |    4 +
> >>>  9 files changed, 4146 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
> >>
> >> This looks like a supremely welcome, long-awaited addition (latest
> >> request:
> >> <https://lists.01.org/pipermail/edk2-devel/2016-October/002667.html>)
> >> , but it really needs your Signed-off-by, and the Contributed-under
> >> line above it:
> >>
> >> ShellPkg/Contributions.txt
> >>
> >> I would also suggest (simply based on what I've seen elsewhere in
> >> edk2) to keep the copyright notices tightly collected in the file
> >> headings.
> >>
> >> Someone will have to go over all the licenses too -- does the
> >> "Marvell BSD License Option" for example correspond to the 3-clause
> BSDL?
> >>
> >> On the technical side, I believe that as long as a shell command (or
> >> a command option) is not standardized (in the shell spec), it usually
> >> starts with an underscore (_), so as to prevent future name collisions.
> >> (I could be wrong about this -- I now recall the TFTP command, which
> >> is also not in the 2.2 spec.)
> >>
> >> Just my two cents.
> >>
> >> Thanks
> >> Laszlo
> > _______________________________________________
> > edk2-devel mailing list
> > edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
> > https://lists.01.org/mailman/listinfo/edk2-devel
> >
> > _______________________________________________
> > edk2-devel mailing list
> > edk2-devel@lists.01.org
> > https://lists.01.org/mailman/listinfo/edk2-devel
> > _______________________________________________
> > edk2-devel mailing list
> > edk2-devel@lists.01.org
> > https://lists.01.org/mailman/listinfo/edk2-devel
> >


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

* Re: [PATCH] GPT Shell Application/Library
  2016-10-18 17:04                   ` Carsey, Jaben
@ 2016-10-18 18:03                     ` Shah, Tapan
  2016-10-18 19:09                       ` Vladimir Olovyannikov
  0 siblings, 1 reply; 20+ messages in thread
From: Shah, Tapan @ 2016-10-18 18:03 UTC (permalink / raw)
  To: Carsey, Jaben, Vladimir Olovyannikov, Michael Zimmermann
  Cc: Ni, Ruiyu, Arshi, Shala, edk2-devel@lists.01.org, Laszlo Ersek

1. Create this new shared library in MdeModulePkg.
2. For parameters: Other than standard parameters defined in Shell specification I would suggest to follow single character flag where it makes sense (example: -d to delete, -l to list, -c to create etc.) and if more than one operation can be tied with one flag, then add individual value as a flag value. There are plenty of ShellPkg commands you can use as a reference.

-----Original Message-----
From: Carsey, Jaben [mailto:jaben.carsey@intel.com] 
Sent: Tuesday, October 18, 2016 12:04 PM
To: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>; Shah, Tapan <tapandshah@hpe.com>; Michael Zimmermann <sigmaepsilon92@gmail.com>
Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Arshi, Shala <shala.arshi@intel.com>; edk2-devel@lists.01.org <edk2-devel@ml01.01.org>; Laszlo Ersek <lersek@redhat.com>; Carsey, Jaben <jaben.carsey@intel.com>
Subject: RE: [edk2] [PATCH] GPT Shell Application/Library

For the standards, I would try to use the UEFI Shell Spec for some parameters.  For Example:
-v for verbose
-h for help
-sfo for standard format output

> -----Original Message-----
> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of 
> Vladimir Olovyannikov
> Sent: Tuesday, October 18, 2016 9:58 AM
> To: Shah, Tapan <tapandshah@hpe.com>; Carsey, Jaben 
> <jaben.carsey@intel.com>; Michael Zimmermann 
> <sigmaepsilon92@gmail.com>
> Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Arshi, Shala 
> <shala.arshi@intel.com>; edk2-devel@lists.01.org 
> <edk2-devel@ml01.01.org>; Laszlo Ersek <lersek@redhat.com>
> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> Importance: High
> 
> Thank you all for comments,
> 
> So to summarize the discussion:
> 
> 1. I will create a Shell library which would perform all GPT operations.
>      Part of PartitionDxe will also be in that library so PartitionDxe 
> will be using it.
>      The gpt Shell tool will also be using it.
> 2.  Refactor the parameters of the gpt utility to make it similar to 
> other existing Shell commands.
>       BTW Is there any document describing Shell utility parameters'
> standards?
> 
> Please let me know if you have other suggestions.
> 
> Thank you,
> Vladimir
> 
> -----Original Message-----
> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of 
> Shah, Tapan
> Sent: October-18-16 6:59 AM
> To: Carsey, Jaben; Vladimir Olovyannikov; Michael Zimmermann
> Cc: Ni, Ruiyu; Arshi, Shala; edk2-devel@lists.01.org; Laszlo Ersek
> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> 
> Thanks for the contribution Vladimir!
> 
> Few comments:
> 1. It's better to refactor the code now before commit and move GPT 
> related code outside ShellPkg and create a shared library.
> 2. CLI parameters of this utility are too complex and need to be 
> refactored to make it similar to other existing Shell commands.
> 
> Thanks,
> Tapan
> 
> -----Original Message-----
> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of 
> Carsey, Jaben
> Sent: Monday, October 17, 2016 12:56 PM
> To: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>; 
> Michael Zimmermann <sigmaepsilon92@gmail.com>
> Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Arshi, Shala 
> <shala.arshi@intel.com>; edk2-devel@lists.01.org 
> <edk2-devel@ml01.01.org>; Carsey, Jaben <jaben.carsey@intel.com>; 
> Laszlo Ersek <lersek@redhat.com>
> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> 
> To the old question about license: I asked our people to check and was 
> told that the license is compatible with our BSD and ok by Intel.
> 
> To the technical content – I really like this idea of a shared library.
> That would be a great way to share code and not have as much duplicate.
> 
> -Jaben
> 
> From: Vladimir Olovyannikov 
> [mailto:vladimir.olovyannikov@broadcom.com]
> Sent: Monday, October 17, 2016 10:52 AM
> To: Michael Zimmermann <sigmaepsilon92@gmail.com>
> Cc: Laszlo Ersek <lersek@redhat.com>; Carsey, Jaben 
> <jaben.carsey@intel.com>; Ni, Ruiyu <ruiyu.ni@intel.com>; 
> edk2-devel@lists.01.org <edk2-devel@ml01.01.org>
> Subject: RE: [edk2] [PATCH] GPT Shell Application/Library
> Importance: High
> 
> Hi Michael,
> I am absolutely agree with your proposal.
> 
> In the gpt Shell library/application I had to “borrow” some stuff from 
> PartitionDxe.c to not reinvent a  wheel.
> If the PartitionDxe maintainer agrees to have a separate library 
> available for everybody, I would move all the GPT-related stuff from 
> the GptWorker (and partially from the PartitionDxe itself) to that independent library.
> This could be a longer-term task.
> Right now I just wanted to share the tool which could be useful for 
> anybody who would wish to manage GPT partitions (and/or do a FAT32 
> format of either a disk or a GPT partition) from within the Shell. 
> What do you think?
> 
> Thank you,
> Vladimir
> From: Michael Zimmermann
> [mailto:sigmaepsilon92@gmail.com<mailto:sigmaepsilon92@gmail.com>]
> Sent: October-17-16 12:25 AM
> To: Vladimir Olovyannikov
> Cc: Laszlo Ersek; Jaben Carsey; Ni, Ruiyu; 
> edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> 
> Hi,
> 
> wouldn't it be better to make a generic gpt parsing library which is 
> independent of the shell so both the shell and PartitionDxe can use it?
> It may also be useful for other applications which need additional 
> information like the gpt partition names.
> 
> Thanks
> Michael
> 
> On Mon, Oct 17, 2016 at 8:49 AM, Vladimir Olovyannikov 
> <vladimir.olovyannikov@broadcom.com<mailto:vladimir.olovyannikov@broa
> dcom.com>>
> wrote:
> Thank you Laszlo,
> 
> Sorry, I missed the fields; it is my first contribution, I will add 
> the required lines, review the source according to your comments and 
> will resubmit the patch.
> So do you think the command should be _gpt instead of gpt? I was 
> following TFTP and SF commands as a template.
> 
> Thank you,
> Vladimir
> 
> On Oct 16, 2016 1:05 PM, "Laszlo Ersek"
> <lersek@redhat.com<mailto:lersek@redhat.com>> wrote:
> >
> > On 10/16/16 07:23, Vladimir Olovyannikov wrote:
> > > This allows managing (create, delete, modify, fat format) of GPT 
> > > partitions from within UEFI Shell.
> > > Syntax:
> > > gpt <command> [device_mapped_name] [parameters...] See usage 
> > > examples in the .uni file
> > > ---
> > >  .../Library/UefiShellGptCommandLib/FatFormat.c     |  611 +++++++
> > >  .../Library/UefiShellGptCommandLib/FatFormat.h     |  111 ++
> > >  .../Library/UefiShellGptCommandLib/GptWorker.c     | 1902
> ++++++++++++++++++++
> > >  .../Library/UefiShellGptCommandLib/GptWorker.h     |  186 ++
> > >  .../UefiShellGptCommandLib.c                       | 1135 ++++++++++++
> > >  .../UefiShellGptCommandLib.inf                     |   79 +
> > >  .../UefiShellGptCommandLib.uni                     |  117 ++
> > >  ShellPkg/ShellPkg.dec                              |    1 +
> > >  ShellPkg/ShellPkg.dsc                              |    4 +
> > >  9 files changed, 4146 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
> >
> > This looks like a supremely welcome, long-awaited addition (latest
> > request:
> > <https://lists.01.org/pipermail/edk2-devel/2016-October/002667.html>
> > ), but it really needs your Signed-off-by, and the Contributed-under 
> > line above it:
> >
> > ShellPkg/Contributions.txt
> >
> > I would also suggest (simply based on what I've seen elsewhere in
> > edk2) to keep the copyright notices tightly collected in the file 
> > headings.
> >
> > Someone will have to go over all the licenses too -- does the 
> > "Marvell BSD License Option" for example correspond to the 3-clause BSDL?
> >
> > On the technical side, I believe that as long as a shell command (or 
> > a command option) is not standardized (in the shell spec), it 
> > usually starts with an underscore (_), so as to prevent future name collisions.
> > (I could be wrong about this -- I now recall the TFTP command, which 
> > is also not in the 2.2 spec.)
> >
> > Just my two cents.
> >
> > Thanks
> > Laszlo
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
> https://lists.01.org/mailman/listinfo/edk2-devel
> 
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel

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

* Re: [PATCH] GPT Shell Application/Library
  2016-10-18 18:03                     ` Vladimir Olovyannikov
@ 2016-10-18 18:12                       ` Laszlo Ersek
  0 siblings, 0 replies; 20+ messages in thread
From: Laszlo Ersek @ 2016-10-18 18:12 UTC (permalink / raw)
  To: Vladimir Olovyannikov, Shah, Tapan, Carsey, Jaben,
	Michael Zimmermann
  Cc: Ni, Ruiyu, Arshi, Shala, edk2-devel@lists.01.org

On 10/18/16 20:03, Vladimir Olovyannikov wrote:
>> -----Original Message-----
>> From: Laszlo Ersek [mailto:lersek@redhat.com]
>> Sent: October-18-16 10:24 AM
>> To: Vladimir Olovyannikov; Shah, Tapan; Carsey, Jaben; Michael Zimmermann
>> Cc: Ni, Ruiyu; Arshi, Shala; edk2-devel@lists.01.org
>> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
>>
>> On 10/18/16 18:58, Vladimir Olovyannikov wrote:
>>> Thank you all for comments,
>>>
>>> So to summarize the discussion:
>>>
>>> 1. I will create a Shell library which would perform all GPT operations.
>>>      Part of PartitionDxe will also be in that library so PartitionDxe
>>> will be using it.
>>>      The gpt Shell tool will also be using it.
>>
>> I think you might want to place the library class header file, and the
>> library
>> instance, under MdeModulePkg. It's okay for the shell application (or
>> shell
>> libraries) to depend on library classes / library instances from
>> MdeModulePkg, but -- I think -- it's not okay for a driver in
>> MdeModulePkg,
>> such as PartitionDxe, to depend on a class + instance from under ShellPkg.
> Laszlo,
> I think PartitionDxe will depend on the GPT shared library (which will have
> nothing to do to the ShellPkg),
> as well as gpt tool (Shell library/application) will depend on that shared
> library as well to get information regarding partitions and
> to perform GPT management.

I understood that, yes. My point was the location of the new common
library (class header and instance both). You wrote

"I will create a Shell library ..."

which made me think you wanted to place the files under:

  ShellPkg/Include/Library/...
  ShellPkg/Library/...

which is not right in this instance. I suggested to place those files under

  MdeModulePkg/Include/Library/...
  MdeModulePkg/Library/...

Thanks!
Laszlo

> 
> Thank you,
> Vladimir
>>
>> Thanks!
>> Laszlo
>>
>>> 2.  Refactor the parameters of the gpt utility to make it similar to
>>> other existing Shell commands.
>>>       BTW Is there any document describing Shell utility parameters'
>>> standards?
>>>
>>> Please let me know if you have other suggestions.
>>>
>>> Thank you,
>>> Vladimir
>>>
>>> -----Original Message-----
>>> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
>>> Shah, Tapan
>>> Sent: October-18-16 6:59 AM
>>> To: Carsey, Jaben; Vladimir Olovyannikov; Michael Zimmermann
>>> Cc: Ni, Ruiyu; Arshi, Shala; edk2-devel@lists.01.org; Laszlo Ersek
>>> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
>>>
>>> Thanks for the contribution Vladimir!
>>>
>>> Few comments:
>>> 1. It's better to refactor the code now before commit and move GPT
>>> related code outside ShellPkg and create a shared library.
>>> 2. CLI parameters of this utility are too complex and need to be
>>> refactored to make it similar to other existing Shell commands.
>>>
>>> Thanks,
>>> Tapan
>>>
>>> -----Original Message-----
>>> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
>>> Carsey, Jaben
>>> Sent: Monday, October 17, 2016 12:56 PM
>>> To: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>;
>>> Michael Zimmermann <sigmaepsilon92@gmail.com>
>>> Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Arshi, Shala
>>> <shala.arshi@intel.com>; edk2-devel@lists.01.org
>>> <edk2-devel@ml01.01.org>; Carsey, Jaben <jaben.carsey@intel.com>;
>>> Laszlo Ersek <lersek@redhat.com>
>>> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
>>>
>>> To the old question about license: I asked our people to check and was
>>> told that the license is compatible with our BSD and ok by Intel.
>>>
>>> To the technical content – I really like this idea of a shared library.
>>> That would be a great way to share code and not have as much duplicate.
>>>
>>> -Jaben
>>>
>>> From: Vladimir Olovyannikov
>>> [mailto:vladimir.olovyannikov@broadcom.com]
>>> Sent: Monday, October 17, 2016 10:52 AM
>>> To: Michael Zimmermann <sigmaepsilon92@gmail.com>
>>> Cc: Laszlo Ersek <lersek@redhat.com>; Carsey, Jaben
>>> <jaben.carsey@intel.com>; Ni, Ruiyu <ruiyu.ni@intel.com>;
>>> edk2-devel@lists.01.org <edk2-devel@ml01.01.org>
>>> Subject: RE: [edk2] [PATCH] GPT Shell Application/Library
>>> Importance: High
>>>
>>> Hi Michael,
>>> I am absolutely agree with your proposal.
>>>
>>> In the gpt Shell library/application I had to “borrow” some stuff from
>>> PartitionDxe.c to not reinvent a  wheel.
>>> If the PartitionDxe maintainer agrees to have a separate library
>>> available for everybody, I would move all the GPT-related stuff from
>>> the GptWorker (and partially from the PartitionDxe itself) to that
>> independent library.
>>> This could be a longer-term task.
>>> Right now I just wanted to share the tool which could be useful for
>>> anybody who would wish to manage GPT partitions (and/or do a FAT32
>>> format of either a disk or a GPT partition) from within the Shell. What
>>> do
>> you think?
>>>
>>> Thank you,
>>> Vladimir
>>> From: Michael Zimmermann
>>> [mailto:sigmaepsilon92@gmail.com<mailto:sigmaepsilon92@gmail.com>]
>>> Sent: October-17-16 12:25 AM
>>> To: Vladimir Olovyannikov
>>> Cc: Laszlo Ersek; Jaben Carsey; Ni, Ruiyu;
>>> edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
>>> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
>>>
>>> Hi,
>>>
>>> wouldn't it be better to make a generic gpt parsing library which is
>>> independent of the shell so both the shell and PartitionDxe can use it?
>>> It may also be useful for other applications which need additional
>>> information like the gpt partition names.
>>>
>>> Thanks
>>> Michael
>>>
>>> On Mon, Oct 17, 2016 at 8:49 AM, Vladimir Olovyannikov
>>>
>> <vladimir.olovyannikov@broadcom.com<mailto:vladimir.olovyannikov@broa
>> d
>>> com.com>>
>>> wrote:
>>> Thank you Laszlo,
>>>
>>> Sorry, I missed the fields; it is my first contribution, I will add
>>> the required lines, review the source according to your comments and
>>> will resubmit the patch.
>>> So do you think the command should be _gpt instead of gpt? I was
>>> following TFTP and SF commands as a template.
>>>
>>> Thank you,
>>> Vladimir
>>>
>>> On Oct 16, 2016 1:05 PM, "Laszlo Ersek"
>>> <lersek@redhat.com<mailto:lersek@redhat.com>> wrote:
>>>>
>>>> On 10/16/16 07:23, Vladimir Olovyannikov wrote:
>>>>> This allows managing (create, delete, modify, fat format) of GPT
>>>>> partitions from within UEFI Shell.
>>>>> Syntax:
>>>>> gpt <command> [device_mapped_name] [parameters...] See usage
>>>>> examples in the .uni file
>>>>> ---
>>>>>  .../Library/UefiShellGptCommandLib/FatFormat.c     |  611 +++++++
>>>>>  .../Library/UefiShellGptCommandLib/FatFormat.h     |  111 ++
>>>>>  .../Library/UefiShellGptCommandLib/GptWorker.c     | 1902
>>> ++++++++++++++++++++
>>>>>  .../Library/UefiShellGptCommandLib/GptWorker.h     |  186 ++
>>>>>  .../UefiShellGptCommandLib.c                       | 1135
>>>>> ++++++++++++
>>>>>  .../UefiShellGptCommandLib.inf                     |   79 +
>>>>>  .../UefiShellGptCommandLib.uni                     |  117 ++
>>>>>  ShellPkg/ShellPkg.dec                              |    1 +
>>>>>  ShellPkg/ShellPkg.dsc                              |    4 +
>>>>>  9 files changed, 4146 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
>>>>
>>>> This looks like a supremely welcome, long-awaited addition (latest
>>>> request:
>>>> <https://lists.01.org/pipermail/edk2-devel/2016-October/002667.html>)
>>>> , but it really needs your Signed-off-by, and the Contributed-under
>>>> line above it:
>>>>
>>>> ShellPkg/Contributions.txt
>>>>
>>>> I would also suggest (simply based on what I've seen elsewhere in
>>>> edk2) to keep the copyright notices tightly collected in the file
>>>> headings.
>>>>
>>>> Someone will have to go over all the licenses too -- does the
>>>> "Marvell BSD License Option" for example correspond to the 3-clause
>> BSDL?
>>>>
>>>> On the technical side, I believe that as long as a shell command (or
>>>> a command option) is not standardized (in the shell spec), it usually
>>>> starts with an underscore (_), so as to prevent future name collisions.
>>>> (I could be wrong about this -- I now recall the TFTP command, which
>>>> is also not in the 2.2 spec.)
>>>>
>>>> Just my two cents.
>>>>
>>>> Thanks
>>>> Laszlo
>>> _______________________________________________
>>> edk2-devel mailing list
>>> edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
>>> https://lists.01.org/mailman/listinfo/edk2-devel
>>>
>>> _______________________________________________
>>> edk2-devel mailing list
>>> edk2-devel@lists.01.org
>>> https://lists.01.org/mailman/listinfo/edk2-devel
>>> _______________________________________________
>>> edk2-devel mailing list
>>> edk2-devel@lists.01.org
>>> https://lists.01.org/mailman/listinfo/edk2-devel
>>>



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

* Re: [PATCH] GPT Shell Application/Library
  2016-10-18 18:03                     ` Shah, Tapan
@ 2016-10-18 19:09                       ` Vladimir Olovyannikov
  0 siblings, 0 replies; 20+ messages in thread
From: Vladimir Olovyannikov @ 2016-10-18 19:09 UTC (permalink / raw)
  To: Shah, Tapan, Carsey, Jaben, Michael Zimmermann
  Cc: Ni, Ruiyu, Arshi, Shala, edk2-devel@lists.01.org, Laszlo Ersek

OK,
Thank you for advice.

> -----Original Message-----
> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
> Shah, Tapan
> Sent: October-18-16 11:04 AM
> To: Carsey, Jaben; Vladimir Olovyannikov; Michael Zimmermann
> Cc: Ni, Ruiyu; Arshi, Shala; edk2-devel@lists.01.org; Laszlo Ersek
> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
>
> 1. Create this new shared library in MdeModulePkg.
> 2. For parameters: Other than standard parameters defined in Shell
> specification I would suggest to follow single character flag where it
> makes
> sense (example: -d to delete, -l to list, -c to create etc.) and if more
> than one
> operation can be tied with one flag, then add individual value as a flag
> value.
> There are plenty of ShellPkg commands you can use as a reference.
>
> -----Original Message-----
> From: Carsey, Jaben [mailto:jaben.carsey@intel.com]
> Sent: Tuesday, October 18, 2016 12:04 PM
> To: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>; Shah,
> Tapan <tapandshah@hpe.com>; Michael Zimmermann
> <sigmaepsilon92@gmail.com>
> Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Arshi, Shala <shala.arshi@intel.com>;
> edk2-devel@lists.01.org <edk2-devel@ml01.01.org>; Laszlo Ersek
> <lersek@redhat.com>; Carsey, Jaben <jaben.carsey@intel.com>
> Subject: RE: [edk2] [PATCH] GPT Shell Application/Library
>
> For the standards, I would try to use the UEFI Shell Spec for some
> parameters.  For Example:
> -v for verbose
> -h for help
> -sfo for standard format output
>
> > -----Original Message-----
> > From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
> > Vladimir Olovyannikov
> > Sent: Tuesday, October 18, 2016 9:58 AM
> > To: Shah, Tapan <tapandshah@hpe.com>; Carsey, Jaben
> > <jaben.carsey@intel.com>; Michael Zimmermann
> > <sigmaepsilon92@gmail.com>
> > Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Arshi, Shala
> > <shala.arshi@intel.com>; edk2-devel@lists.01.org
> > <edk2-devel@ml01.01.org>; Laszlo Ersek <lersek@redhat.com>
> > Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> > Importance: High
> >
> > Thank you all for comments,
> >
> > So to summarize the discussion:
> >
> > 1. I will create a Shell library which would perform all GPT operations.
> >      Part of PartitionDxe will also be in that library so PartitionDxe
> > will be using it.
> >      The gpt Shell tool will also be using it.
> > 2.  Refactor the parameters of the gpt utility to make it similar to
> > other existing Shell commands.
> >       BTW Is there any document describing Shell utility parameters'
> > standards?
> >
> > Please let me know if you have other suggestions.
> >
> > Thank you,
> > Vladimir
> >
> > -----Original Message-----
> > From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
> > Shah, Tapan
> > Sent: October-18-16 6:59 AM
> > To: Carsey, Jaben; Vladimir Olovyannikov; Michael Zimmermann
> > Cc: Ni, Ruiyu; Arshi, Shala; edk2-devel@lists.01.org; Laszlo Ersek
> > Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> >
> > Thanks for the contribution Vladimir!
> >
> > Few comments:
> > 1. It's better to refactor the code now before commit and move GPT
> > related code outside ShellPkg and create a shared library.
> > 2. CLI parameters of this utility are too complex and need to be
> > refactored to make it similar to other existing Shell commands.
> >
> > Thanks,
> > Tapan
> >
> > -----Original Message-----
> > From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
> > Carsey, Jaben
> > Sent: Monday, October 17, 2016 12:56 PM
> > To: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>;
> > Michael Zimmermann <sigmaepsilon92@gmail.com>
> > Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Arshi, Shala
> > <shala.arshi@intel.com>; edk2-devel@lists.01.org
> > <edk2-devel@ml01.01.org>; Carsey, Jaben <jaben.carsey@intel.com>;
> > Laszlo Ersek <lersek@redhat.com>
> > Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> >
> > To the old question about license: I asked our people to check and was
> > told that the license is compatible with our BSD and ok by Intel.
> >
> > To the technical content – I really like this idea of a shared library.
> > That would be a great way to share code and not have as much duplicate.
> >
> > -Jaben
> >
> > From: Vladimir Olovyannikov
> > [mailto:vladimir.olovyannikov@broadcom.com]
> > Sent: Monday, October 17, 2016 10:52 AM
> > To: Michael Zimmermann <sigmaepsilon92@gmail.com>
> > Cc: Laszlo Ersek <lersek@redhat.com>; Carsey, Jaben
> > <jaben.carsey@intel.com>; Ni, Ruiyu <ruiyu.ni@intel.com>;
> > edk2-devel@lists.01.org <edk2-devel@ml01.01.org>
> > Subject: RE: [edk2] [PATCH] GPT Shell Application/Library
> > Importance: High
> >
> > Hi Michael,
> > I am absolutely agree with your proposal.
> >
> > In the gpt Shell library/application I had to “borrow” some stuff from
> > PartitionDxe.c to not reinvent a  wheel.
> > If the PartitionDxe maintainer agrees to have a separate library
> > available for everybody, I would move all the GPT-related stuff from
> > the GptWorker (and partially from the PartitionDxe itself) to that
> independent library.
> > This could be a longer-term task.
> > Right now I just wanted to share the tool which could be useful for
> > anybody who would wish to manage GPT partitions (and/or do a FAT32
> > format of either a disk or a GPT partition) from within the Shell.
> > What do you think?
> >
> > Thank you,
> > Vladimir
> > From: Michael Zimmermann
> > [mailto:sigmaepsilon92@gmail.com<mailto:sigmaepsilon92@gmail.com>]
> > Sent: October-17-16 12:25 AM
> > To: Vladimir Olovyannikov
> > Cc: Laszlo Ersek; Jaben Carsey; Ni, Ruiyu;
> > edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
> > Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> >
> > Hi,
> >
> > wouldn't it be better to make a generic gpt parsing library which is
> > independent of the shell so both the shell and PartitionDxe can use it?
> > It may also be useful for other applications which need additional
> > information like the gpt partition names.
> >
> > Thanks
> > Michael
> >
> > On Mon, Oct 17, 2016 at 8:49 AM, Vladimir Olovyannikov
> >
> <vladimir.olovyannikov@broadcom.com<mailto:vladimir.olovyannikov@broa
> > dcom.com>>
> > wrote:
> > Thank you Laszlo,
> >
> > Sorry, I missed the fields; it is my first contribution, I will add
> > the required lines, review the source according to your comments and
> > will resubmit the patch.
> > So do you think the command should be _gpt instead of gpt? I was
> > following TFTP and SF commands as a template.
> >
> > Thank you,
> > Vladimir
> >
> > On Oct 16, 2016 1:05 PM, "Laszlo Ersek"
> > <lersek@redhat.com<mailto:lersek@redhat.com>> wrote:
> > >
> > > On 10/16/16 07:23, Vladimir Olovyannikov wrote:
> > > > This allows managing (create, delete, modify, fat format) of GPT
> > > > partitions from within UEFI Shell.
> > > > Syntax:
> > > > gpt <command> [device_mapped_name] [parameters...] See usage
> > > > examples in the .uni file
> > > > ---
> > > >  .../Library/UefiShellGptCommandLib/FatFormat.c     |  611 +++++++
> > > >  .../Library/UefiShellGptCommandLib/FatFormat.h     |  111 ++
> > > >  .../Library/UefiShellGptCommandLib/GptWorker.c     | 1902
> > ++++++++++++++++++++
> > > >  .../Library/UefiShellGptCommandLib/GptWorker.h     |  186 ++
> > > >  .../UefiShellGptCommandLib.c                       | 1135
> > > > ++++++++++++
> > > >  .../UefiShellGptCommandLib.inf                     |   79 +
> > > >  .../UefiShellGptCommandLib.uni                     |  117 ++
> > > >  ShellPkg/ShellPkg.dec                              |    1 +
> > > >  ShellPkg/ShellPkg.dsc                              |    4 +
> > > >  9 files changed, 4146 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
> > >
> > > This looks like a supremely welcome, long-awaited addition (latest
> > > request:
> > > <https://lists.01.org/pipermail/edk2-devel/2016-October/002667.html>
> > > ), but it really needs your Signed-off-by, and the Contributed-under
> > > line above it:
> > >
> > > ShellPkg/Contributions.txt
> > >
> > > I would also suggest (simply based on what I've seen elsewhere in
> > > edk2) to keep the copyright notices tightly collected in the file
> > > headings.
> > >
> > > Someone will have to go over all the licenses too -- does the
> > > "Marvell BSD License Option" for example correspond to the 3-clause
> BSDL?
> > >
> > > On the technical side, I believe that as long as a shell command (or
> > > a command option) is not standardized (in the shell spec), it
> > > usually starts with an underscore (_), so as to prevent future name
> collisions.
> > > (I could be wrong about this -- I now recall the TFTP command, which
> > > is also not in the 2.2 spec.)
> > >
> > > Just my two cents.
> > >
> > > Thanks
> > > Laszlo
> > _______________________________________________
> > edk2-devel mailing list
> > edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
> > https://lists.01.org/mailman/listinfo/edk2-devel
> >
> > _______________________________________________
> > edk2-devel mailing list
> > edk2-devel@lists.01.org
> > https://lists.01.org/mailman/listinfo/edk2-devel
> > _______________________________________________
> > edk2-devel mailing list
> > edk2-devel@lists.01.org
> > https://lists.01.org/mailman/listinfo/edk2-devel
> > _______________________________________________
> > edk2-devel mailing list
> > edk2-devel@lists.01.org
> > https://lists.01.org/mailman/listinfo/edk2-devel
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel


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

end of thread, other threads:[~2016-10-18 19:09 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-10-16  5:23 [PATCH] GPT Shell Application/Library Vladimir Olovyannikov
2016-10-16 20:05 ` Laszlo Ersek
     [not found]   ` <CACmgjazi_K4Qo5=TeO_tCGK2cB26d0rqOEZh6TthP1UYbo6J6w@mail.gmail.com>
     [not found]     ` <CACmgjaziUEF2EsSn73HY5JvL2rmRWrXS+rHMtOQ1HaRwPpXS+g@mail.gmail.com>
2016-10-17  6:49       ` Vladimir Olovyannikov
2016-10-17  7:24         ` Michael Zimmermann
2016-10-17 17:52           ` Vladimir Olovyannikov
2016-10-17 17:56             ` Carsey, Jaben
2016-10-18 13:59               ` Shah, Tapan
2016-10-18 16:58                 ` Vladimir Olovyannikov
2016-10-18 17:04                   ` Carsey, Jaben
2016-10-18 18:03                     ` Shah, Tapan
2016-10-18 19:09                       ` Vladimir Olovyannikov
2016-10-18 17:23                   ` Laszlo Ersek
2016-10-18 18:03                     ` Vladimir Olovyannikov
2016-10-18 18:12                       ` Laszlo Ersek
2016-10-17  9:43         ` Laszlo Ersek
2016-10-17 16:35           ` Carsey, Jaben
2016-10-18  1:45 ` Ni, Ruiyu
2016-10-18  1:48   ` Tim Lewis
2016-10-18  1:55     ` Ni, Ruiyu
2016-10-18  2:59       ` Carsey, Jaben

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