From: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>
To: jaben.carsey@intel.com, edk2-devel@lists.01.org, ruiyu.ni@intel.com
Cc: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>
Subject: [PATCH] GPT Shell Application/Library
Date: Sat, 15 Oct 2016 22:23:40 -0700 [thread overview]
Message-ID: <1476595420-12566-1-git-send-email-vladimir.olovyannikov@broadcom.com> (raw)
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
next reply other threads:[~2016-10-16 5:25 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-10-16 5:23 Vladimir Olovyannikov [this message]
2016-10-16 20:05 ` [PATCH] GPT Shell Application/Library 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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1476595420-12566-1-git-send-email-vladimir.olovyannikov@broadcom.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox