* [PATCH] GPT Shell Application/Library
@ 2016-10-16 5:23 Vladimir Olovyannikov
2016-10-16 20:05 ` Laszlo Ersek
2016-10-18 1:45 ` Ni, Ruiyu
0 siblings, 2 replies; 20+ messages in thread
From: Vladimir Olovyannikov @ 2016-10-16 5:23 UTC (permalink / raw)
To: jaben.carsey, edk2-devel, ruiyu.ni; +Cc: Vladimir Olovyannikov
This allows managing (create, delete, modify, fat format) of GPT
partitions from within UEFI Shell.
Syntax:
gpt <command> [device_mapped_name] [parameters...]
See usage examples in the .uni file
---
.../Library/UefiShellGptCommandLib/FatFormat.c | 611 +++++++
.../Library/UefiShellGptCommandLib/FatFormat.h | 111 ++
.../Library/UefiShellGptCommandLib/GptWorker.c | 1902 ++++++++++++++++++++
.../Library/UefiShellGptCommandLib/GptWorker.h | 186 ++
.../UefiShellGptCommandLib.c | 1135 ++++++++++++
.../UefiShellGptCommandLib.inf | 79 +
.../UefiShellGptCommandLib.uni | 117 ++
ShellPkg/ShellPkg.dec | 1 +
ShellPkg/ShellPkg.dsc | 4 +
9 files changed, 4146 insertions(+)
create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
diff --git a/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
new file mode 100644
index 000000000000..ba7904e6be28
--- /dev/null
+++ b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
@@ -0,0 +1,611 @@
+/** @file
+
+ Copyright (c) 2003 - 2012, Rob Riglar, Ultra-Embedded.com. All rights reserved<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+/* Portions Copyright (c) 2016, Broadcom. All rights reserved */
+
+#include "FatFormat.h"
+
+//-----------------------------------------------------------------------------
+// Tables
+//-----------------------------------------------------------------------------
+typedef struct
+{
+ UINT64 Sectors;
+ UINT8 SectorsPerCluster;
+} SectorsPerClusterTable;
+
+STATIC SectorsPerClusterTable ClusterSizeTable16[] =
+{
+ { 32680, 2 }, // 16MB - 1K
+ { 262144, 4 }, // 128MB - 2K
+ { 524288, 8 }, // 256MB - 4K
+ { 1048576, 16 }, // 512MB - 8K
+ { 2097152, 32 }, // 1GB - 16K
+ { 4194304, 64 }, // 2GB - 32K
+ { 8388608, 128 }, // 2GB - 64K [Warning only supported by Windows XP onwards]
+ { 0, 0 } // Invalid
+};
+
+STATIC SectorsPerClusterTable ClusterSizeTable32[] =
+{
+ { 532480, 1 }, // 260MB - 512b
+ { 16777216, 8 }, // 8GB - 4K
+ { 33554432, 16 }, // 16GB - 8K
+ { 67108864, 32 }, // 32GB - 16K
+ { 0xFFFFFFFF, 64 }, // >32GB - 32K
+ { 0, 0 } // Invalid
+};
+
+STATIC
+EFI_LBA LbaOfCluster (
+ IN FATFS *Fs,
+ IN UINT64 ClusterNumber
+ )
+{
+ if (Fs->FatType == FAT_TYPE_16)
+ return (Fs->ClusterBeginLba +
+ (Fs->RootEntryCount * 32 / FAT_SECTOR_SIZE) +
+ ((ClusterNumber - 2) * Fs->SectorsPerCluster));
+ else
+ return ((Fs->ClusterBeginLba +
+ ((ClusterNumber - 2) * Fs->SectorsPerCluster)));
+}
+
+//-----------------------------------------------------------------------------
+// fatfs_calc_cluster_size: Calculate what cluster size should be used
+//-----------------------------------------------------------------------------
+STATIC
+UINT8 CalcClusterSize (
+ IN UINTN Sectors,
+ IN BOOLEAN IsFat32)
+{
+ UINTN Index;
+
+ if (!IsFat32) {
+ for (Index = 0; ClusterSizeTable16[Index].SectorsPerCluster != 0; Index++)
+ if (Sectors <= ClusterSizeTable16[Index].Sectors)
+ return ClusterSizeTable16[Index].SectorsPerCluster;
+ } else {
+ for (Index = 0; ClusterSizeTable32[Index].SectorsPerCluster != 0; Index++)
+ if (Sectors <= ClusterSizeTable32[Index].Sectors)
+ return ClusterSizeTable32[Index].SectorsPerCluster;
+ }
+
+ return 0;
+}
+//-----------------------------------------------------------------------------
+// fatfs_erase_sectors: Erase a number of sectors
+//-----------------------------------------------------------------------------
+STATIC
+EFI_STATUS
+EraseSectors (
+ IN FATFS *Fs,
+ IN EFI_LBA Lba,
+ IN UINTN Count
+ )
+{
+ UINTN Index;
+ EFI_STATUS Status;
+
+ // Zero Sector first
+ ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE);
+
+ for (Index = 0; Index < Count; Index++)
+ Status = Fs->DiskIo->WriteDisk (
+ Fs->DiskIo, Fs->BlockIo->Media->MediaId,
+ MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) +
+ MultU64x32 ((Lba + Index), FAT_SECTOR_SIZE),
+ FAT_SECTOR_SIZE, Fs->CurrentSector.Sector);
+
+ return Status;
+}
+//-----------------------------------------------------------------------------
+// fatfs_create_boot_sector: Create the boot Sector
+//-----------------------------------------------------------------------------
+STATIC
+EFI_STATUS
+CreateBootSector (
+ IN FATFS *Fs,
+ IN EFI_LBA BootSectorLba,
+ IN UINT64 VolSectors,
+ IN CONST CHAR8 *Name,
+ IN BOOLEAN IsFat32
+ )
+{
+ UINTN TotalClusters;
+ UINTN Index;
+ EFI_STATUS Status;
+
+ // Zero Sector initially
+ ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE);
+
+ // OEM Name & Jump Code
+ Fs->CurrentSector.Sector[0] = 0xEB;
+ Fs->CurrentSector.Sector[1] = 0x3C;
+ Fs->CurrentSector.Sector[2] = 0x90;
+ Fs->CurrentSector.Sector[3] = 0x4D;
+ Fs->CurrentSector.Sector[4] = 0x53;
+ Fs->CurrentSector.Sector[5] = 0x44;
+ Fs->CurrentSector.Sector[6] = 0x4F;
+ Fs->CurrentSector.Sector[7] = 0x53;
+ Fs->CurrentSector.Sector[8] = 0x35;
+ Fs->CurrentSector.Sector[9] = 0x2E;
+ Fs->CurrentSector.Sector[10] = 0x30;
+
+ // Bytes per Sector
+ Fs->CurrentSector.Sector[11] = (FAT_SECTOR_SIZE >> 0) & 0xFF;
+ Fs->CurrentSector.Sector[12] = (FAT_SECTOR_SIZE >> 8) & 0xFF;
+
+ // Get sectors per cluster size for the disk
+ Fs->SectorsPerCluster = CalcClusterSize (VolSectors, IsFat32);
+ if (!Fs->SectorsPerCluster)
+ return 0; // Invalid disk size
+
+ // Sectors per cluster
+ Fs->CurrentSector.Sector[13] = Fs->SectorsPerCluster;
+
+ // Reserved Sectors
+ if (!IsFat32)
+ Fs->ReservedSectors = 8;
+ else
+ Fs->ReservedSectors = 32;
+ Fs->CurrentSector.Sector[14] = (Fs->ReservedSectors >> 0) & 0xFF;
+ Fs->CurrentSector.Sector[15] = (Fs->ReservedSectors >> 8) & 0xFF;
+
+ // Number of FATS
+ Fs->NumOfFats = 2;
+ Fs->CurrentSector.Sector[16] = Fs->NumOfFats;
+
+ // Max entries in root dir (FAT16 only)
+ if (!IsFat32) {
+ Fs->RootEntryCount = 512;
+ Fs->CurrentSector.Sector[17] = (Fs->RootEntryCount >> 0) & 0xFF;
+ Fs->CurrentSector.Sector[18] = (Fs->RootEntryCount >> 8) & 0xFF;
+ } else {
+ Fs->RootEntryCount = 0;
+ Fs->CurrentSector.Sector[17] = 0;
+ Fs->CurrentSector.Sector[18] = 0;
+ }
+
+ // [FAT16] Total sectors (use FAT32 count instead)
+ Fs->CurrentSector.Sector[19] = 0x00;
+ Fs->CurrentSector.Sector[20] = 0x00;
+
+ // Media type
+ Fs->CurrentSector.Sector[21] = 0xF8;
+
+
+ // FAT16 BS Details
+ if (!IsFat32) {
+ // Count of sectors used by the FAT table (FAT16 only)
+ TotalClusters = (VolSectors / Fs->SectorsPerCluster) + 1;
+ Fs->FatSectors = (TotalClusters / (FAT_SECTOR_SIZE / 2)) + 1;
+ Fs->CurrentSector.Sector[22] = (UINT8)((Fs->FatSectors >> 0) & 0xFF);
+ Fs->CurrentSector.Sector[23] = (UINT8)((Fs->FatSectors >> 8) & 0xFF);
+
+ // Sectors per track
+ Fs->CurrentSector.Sector[24] = 0x00;
+ Fs->CurrentSector.Sector[25] = 0x00;
+
+ // Heads
+ Fs->CurrentSector.Sector[26] = 0x00;
+ Fs->CurrentSector.Sector[27] = 0x00;
+
+ // Hidden sectors
+ Fs->CurrentSector.Sector[28] = 0x20;
+ Fs->CurrentSector.Sector[29] = 0x00;
+ Fs->CurrentSector.Sector[30] = 0x00;
+ Fs->CurrentSector.Sector[31] = 0x00;
+
+ // Total sectors for this volume
+ Fs->CurrentSector.Sector[32] = (UINT8)((VolSectors >> 0) & 0xFF);
+ Fs->CurrentSector.Sector[33] = (UINT8)((VolSectors >> 8) & 0xFF);
+ Fs->CurrentSector.Sector[34] = (UINT8)((VolSectors >> 16) & 0xFF);
+ Fs->CurrentSector.Sector[35] = (UINT8)((VolSectors >> 24) & 0xFF);
+
+ // Drive number
+ Fs->CurrentSector.Sector[36] = 0x00;
+
+ // Reserved
+ Fs->CurrentSector.Sector[37] = 0x00;
+
+ // Boot signature
+ Fs->CurrentSector.Sector[38] = 0x29;
+
+ // Volume ID
+ Fs->CurrentSector.Sector[39] = 0x12;
+ Fs->CurrentSector.Sector[40] = 0x34;
+ Fs->CurrentSector.Sector[41] = 0x56;
+ Fs->CurrentSector.Sector[42] = 0x78;
+
+ // Volume name
+ for (Index = 0; Index < 11; Index++) {
+ if (Index < AsciiStrLen (Name))
+ Fs->CurrentSector.Sector[Index + 43] = Name[Index];
+ else
+ Fs->CurrentSector.Sector[Index + 43] = ' ';
+ }
+
+ // File sys type
+ Fs->CurrentSector.Sector[54] = 'F';
+ Fs->CurrentSector.Sector[55] = 'A';
+ Fs->CurrentSector.Sector[56] = 'T';
+ Fs->CurrentSector.Sector[57] = '1';
+ Fs->CurrentSector.Sector[58] = '6';
+ Fs->CurrentSector.Sector[59] = ' ';
+ Fs->CurrentSector.Sector[60] = ' ';
+ Fs->CurrentSector.Sector[61] = ' ';
+
+ // Signature
+ Fs->CurrentSector.Sector[510] = 0x55;
+ Fs->CurrentSector.Sector[511] = 0xAA;
+ }
+ // FAT32 BS Details
+ else {
+ // Count of sectors used by the FAT table (FAT16 only)
+ Fs->CurrentSector.Sector[22] = 0;
+ Fs->CurrentSector.Sector[23] = 0;
+
+ // Sectors per track (default)
+ Fs->CurrentSector.Sector[24] = 0x3F;
+ Fs->CurrentSector.Sector[25] = 0x00;
+
+ // Heads (default)
+ Fs->CurrentSector.Sector[26] = 0xFF;
+ Fs->CurrentSector.Sector[27] = 0x00;
+
+ // Hidden sectors
+ Fs->CurrentSector.Sector[28] = 0x00;
+ Fs->CurrentSector.Sector[29] = 0x00;
+ Fs->CurrentSector.Sector[30] = 0x00;
+ Fs->CurrentSector.Sector[31] = 0x00;
+
+ // Total sectors for this volume
+ Fs->CurrentSector.Sector[32] = (UINT8)((VolSectors >> 0) & 0xFF);
+ Fs->CurrentSector.Sector[33] = (UINT8)((VolSectors >> 8) & 0xFF);
+ Fs->CurrentSector.Sector[34] = (UINT8)((VolSectors >> 16) & 0xFF);
+ Fs->CurrentSector.Sector[35] = (UINT8)((VolSectors >> 24) & 0xFF);
+
+ TotalClusters = (VolSectors / Fs->SectorsPerCluster) + 1;
+ Fs->FatSectors = (TotalClusters / (FAT_SECTOR_SIZE / 4)) + 1;
+
+ // BPB_FATSz32
+ Fs->CurrentSector.Sector[36] = (UINT8)((Fs->FatSectors >> 0) & 0xFF);
+ Fs->CurrentSector.Sector[37] = (UINT8)((Fs->FatSectors >> 8) & 0xFF);
+ Fs->CurrentSector.Sector[38] = (UINT8)((Fs->FatSectors >> 16) & 0xFF);
+ Fs->CurrentSector.Sector[39] = (UINT8)((Fs->FatSectors >> 24) & 0xFF);
+
+ // BPB_ExtFlags
+ Fs->CurrentSector.Sector[40] = 0;
+ Fs->CurrentSector.Sector[41] = 0;
+
+ // BPB_FSVer
+ Fs->CurrentSector.Sector[42] = 0;
+ Fs->CurrentSector.Sector[43] = 0;
+
+ // BPB_RootClus
+ Fs->CurrentSector.Sector[44] = (UINT8)((Fs->RootdirFirstCluster >> 0) & 0xFF);
+ Fs->CurrentSector.Sector[45] = (UINT8)((Fs->RootdirFirstCluster >> 8) & 0xFF);
+ Fs->CurrentSector.Sector[46] = (UINT8)((Fs->RootdirFirstCluster >> 16) & 0xFF);
+ Fs->CurrentSector.Sector[47] = (UINT8)((Fs->RootdirFirstCluster >> 24) & 0xFF);
+
+ // BPB_FSInfo
+ Fs->CurrentSector.Sector[48] = (UINT8)((Fs->FsInfoSector >> 0) & 0xFF);
+ Fs->CurrentSector.Sector[49] = (UINT8)((Fs->FsInfoSector >> 8) & 0xFF);
+
+ // BPB_BkBootSec
+ Fs->CurrentSector.Sector[50] = 6;
+ Fs->CurrentSector.Sector[51] = 0;
+
+ // Drive number
+ Fs->CurrentSector.Sector[64] = 0x00;
+
+ // Boot signature
+ Fs->CurrentSector.Sector[66] = 0x29;
+
+ // Volume ID
+ Fs->CurrentSector.Sector[67] = 0x12;
+ Fs->CurrentSector.Sector[68] = 0x34;
+ Fs->CurrentSector.Sector[69] = 0x56;
+ Fs->CurrentSector.Sector[70] = 0x78;
+
+ // Volume name
+ for (Index = 0; Index < 11; Index++) {
+ if (Index < (int)AsciiStrLen (Name))
+ Fs->CurrentSector.Sector[Index + 71] = Name[Index];
+ else
+ Fs->CurrentSector.Sector[Index + 71] = ' ';
+ }
+
+ // File sys type
+ Fs->CurrentSector.Sector[82] = 'F';
+ Fs->CurrentSector.Sector[83] = 'A';
+ Fs->CurrentSector.Sector[84] = 'T';
+ Fs->CurrentSector.Sector[85] = '3';
+ Fs->CurrentSector.Sector[86] = '2';
+ Fs->CurrentSector.Sector[87] = ' ';
+ Fs->CurrentSector.Sector[88] = ' ';
+ Fs->CurrentSector.Sector[89] = ' ';
+
+ // Signature
+ Fs->CurrentSector.Sector[510] = 0x55;
+ Fs->CurrentSector.Sector[511] = 0xAA;
+ }
+
+ Status = Fs->DiskIo->WriteDisk (
+ Fs->DiskIo, Fs->BlockIo->Media->MediaId,
+ MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) +
+ MultU64x32 (Fs->FatBeginLba, FAT_SECTOR_SIZE),
+ FAT_SECTOR_SIZE,
+ Fs->CurrentSector.Sector);
+
+ return Status;
+}
+//-----------------------------------------------------------------------------
+// fatfs_create_fsinfo_sector: Create the FSInfo Sector (FAT32)
+//-----------------------------------------------------------------------------
+STATIC
+EFI_STATUS
+CreateFsinfoSector (
+ IN FATFS *Fs,
+ IN EFI_LBA SectorLba
+ )
+{
+ EFI_STATUS Status;
+
+ // Zero Sector initially
+ ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE);
+
+ // FSI_LeadSig
+ Fs->CurrentSector.Sector[0] = 0x52;
+ Fs->CurrentSector.Sector[1] = 0x52;
+ Fs->CurrentSector.Sector[2] = 0x61;
+ Fs->CurrentSector.Sector[3] = 0x41;
+
+ // FSI_StrucSig
+ Fs->CurrentSector.Sector[484] = 0x72;
+ Fs->CurrentSector.Sector[485] = 0x72;
+ Fs->CurrentSector.Sector[486] = 0x41;
+ Fs->CurrentSector.Sector[487] = 0x61;
+
+ // FSI_Free_Count
+ Fs->CurrentSector.Sector[488] = 0xFF;
+ Fs->CurrentSector.Sector[489] = 0xFF;
+ Fs->CurrentSector.Sector[490] = 0xFF;
+ Fs->CurrentSector.Sector[491] = 0xFF;
+
+ // FSI_Nxt_Free
+ Fs->CurrentSector.Sector[492] = 0xFF;
+ Fs->CurrentSector.Sector[493] = 0xFF;
+ Fs->CurrentSector.Sector[494] = 0xFF;
+ Fs->CurrentSector.Sector[495] = 0xFF;
+
+ // Signature
+ Fs->CurrentSector.Sector[510] = 0x55;
+ Fs->CurrentSector.Sector[511] = 0xAA;
+
+ Status = Fs->DiskIo->WriteDisk (
+ Fs->DiskIo, Fs->BlockIo->Media->MediaId,
+ MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) +
+ MultU64x32 (SectorLba, FAT_SECTOR_SIZE),
+ FAT_SECTOR_SIZE,
+ Fs->CurrentSector.Sector);
+
+ return Status;
+}
+//-----------------------------------------------------------------------------
+// fatfs_erase_fat: Erase FAT table using fs details in fs struct
+//-----------------------------------------------------------------------------
+STATIC
+EFI_STATUS
+EraseFat (
+ IN FATFS *Fs,
+ IN BOOLEAN IsFat32)
+{
+ UINTN Index;
+ EFI_STATUS Status;
+
+ // Zero Sector initially
+ ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE);
+
+ // Initialise default allocate / reserved clusters
+ if (!IsFat32) {
+ SET_16BIT_WORD (Fs->CurrentSector.Sector, 0, 0xFFF8);
+ SET_16BIT_WORD (Fs->CurrentSector.Sector, 2, 0xFFFF);
+ } else {
+ SET_32BIT_WORD (Fs->CurrentSector.Sector, 0, 0x0FFFFFF8);
+ SET_32BIT_WORD (Fs->CurrentSector.Sector, 4, 0xFFFFFFFF);
+ SET_32BIT_WORD (Fs->CurrentSector.Sector, 8, 0x0FFFFFFF);
+ }
+
+ Status = Fs->DiskIo->WriteDisk (
+ Fs->DiskIo, Fs->BlockIo->Media->MediaId,
+ MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) +
+ MultU64x32 (Fs->FatBeginLba, FAT_SECTOR_SIZE),
+ FAT_SECTOR_SIZE,
+ Fs->CurrentSector.Sector);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Zero remaining FAT sectors
+ ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE);
+ for (Index = 1; Index < Fs->FatSectors * Fs->NumOfFats; Index++) {
+ Status = Fs->DiskIo->WriteDisk (
+ Fs->DiskIo,
+ Fs->BlockIo->Media->MediaId,
+ MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) +
+ MultU64x32 ((Fs->FatBeginLba + Index), FAT_SECTOR_SIZE),
+ FAT_SECTOR_SIZE,
+ Fs->CurrentSector.Sector);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ return Status;
+}
+//-----------------------------------------------------------------------------
+// fatfs_format_fat16: Format a FAT16 partition
+//-----------------------------------------------------------------------------
+STATIC
+EFI_STATUS
+FormatFat16 (
+ IN FATFS *Fs,
+ IN UINT64 VolumeSectors,
+ IN CONST CHAR8 *Name
+ )
+{
+ EFI_STATUS Status;
+
+ Fs->CurrentSector.Address = FAT32_INVALID_CLUSTER;
+ Fs->CurrentSector.Dirty = 0;
+
+ Fs->NextFreeCluster = 0; // Invalid
+
+ // Volume is FAT16
+ Fs->FatType = FAT_TYPE_16;
+
+ // Not valid for FAT16
+ Fs->FsInfoSector = 0;
+ Fs->RootdirFirstCluster = 0;
+
+ Fs->LbaBegin = 0;
+ Status = CreateBootSector (Fs, Fs->LbaBegin, VolumeSectors, Name, 0);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // For FAT16 (which this may be), RootdirFirstCluster is actuall RootdirFirstSector
+ Fs->RootdirFirstSector = Fs->ReservedSectors + (Fs->NumOfFats * Fs->FatSectors);
+ Fs->RootdirSectors = ((Fs->RootEntryCount * 32) +
+ (FAT_SECTOR_SIZE - 1)) / FAT_SECTOR_SIZE;
+
+ // First FAT LBA Address
+ Fs->FatBeginLba = Fs->LbaBegin + Fs->ReservedSectors;
+
+ // The Address of the first data cluster on this volume
+ Fs->ClusterBeginLba = Fs->FatBeginLba +
+ (Fs->NumOfFats * Fs->FatSectors);
+
+ // Initialise FAT sectors
+ Status = EraseFat (Fs, 0);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Erase Root directory
+ Status = EraseSectors (
+ Fs,
+ Fs->LbaBegin + Fs->RootdirFirstSector,
+ Fs->RootdirSectors);
+
+ return Status;
+}
+//-----------------------------------------------------------------------------
+// fatfs_format_fat32: Format a FAT32 partition
+//-----------------------------------------------------------------------------
+STATIC
+EFI_STATUS
+FormatFat32 (
+ IN FATFS *Fs,
+ IN UINTN VolumeSectors,
+ IN CONST CHAR8 *Name
+ )
+{
+ EFI_STATUS Status;
+
+ Fs->CurrentSector.Address = FAT32_INVALID_CLUSTER;
+ Fs->CurrentSector.Dirty = 0;
+
+ Fs->NextFreeCluster = 0; // Invalid
+
+ // Volume is FAT32
+ Fs->FatType = FAT_TYPE_32;
+
+ // Basic defaults for normal FAT32 partitions
+ Fs->FsInfoSector = 1;
+ Fs->RootdirFirstCluster = 2;
+
+ // Sector 0: Boot Sector
+ // NOTE: We don't need an MBR, it is a waste of a good Sector!
+ Fs->LbaBegin = 0;
+ Status = CreateBootSector (Fs, Fs->LbaBegin, VolumeSectors, Name, 1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // First FAT LBA address
+ Fs->FatBeginLba = Fs->LbaBegin + Fs->ReservedSectors;
+
+ // The address of the first data cluster on this volume
+ Fs->ClusterBeginLba = Fs->FatBeginLba + (Fs->NumOfFats * Fs->FatSectors);
+
+ // Initialise FSInfo sector
+ Status = CreateFsinfoSector (Fs, Fs->FsInfoSector);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Initialise FAT sectors
+ Status = EraseFat (Fs, 1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Erase Root directory
+ Status = EraseSectors (
+ Fs,
+ LbaOfCluster (Fs, Fs->RootdirFirstCluster),
+ Fs->SectorsPerCluster);
+
+ return Status;
+}
+//-----------------------------------------------------------------------------
+// fatfs_format: Format a partition with either FAT16 or FAT32 based on size
+//-----------------------------------------------------------------------------
+EFI_STATUS
+FatFormat (
+ IN EFI_LBA StartingLBA,
+ IN EFI_LBA EndingLBA,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN CHAR8 *VolumeName,
+ IN BOOLEAN ForceFat32
+ )
+{
+ FATFS Fs;
+ UINT64 VolumeSectors;
+
+ VolumeSectors = DivU64x32 (
+ MultU64x32 (
+ EndingLBA - StartingLBA + 1, BlockIo->Media->BlockSize),
+ FAT_SECTOR_SIZE);
+
+ if (VolumeName == NULL) {
+ VolumeName = DEFAULT_FAT_LABEL_NAME;
+ }
+
+ ZeroMem (&Fs, sizeof(Fs));
+
+ Fs.StartingLBA = StartingLBA;
+ Fs.EndingLBA = EndingLBA;
+ Fs.BlockIo = BlockIo;
+ Fs.DiskIo = DiskIo;
+ // 2GB - 32K limit for safe behaviour for FAT16
+ if ((VolumeSectors <= 4194304) && (!ForceFat32)) {
+ return FormatFat16 (&Fs, VolumeSectors, VolumeName);
+ } else {
+ return FormatFat32 (&Fs, VolumeSectors, VolumeName);
+ }
+}
diff --git a/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
new file mode 100644
index 000000000000..d1a325a57abe
--- /dev/null
+++ b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
@@ -0,0 +1,111 @@
+/** @file
+
+ Copyright (c) 2003 - 2012, Ultra-Embedded.com. All rights reserved<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+/* Portions Copyright (c) 2016, Broadcom. All rights reserved */
+
+#ifndef __FAT_FORMAT_H__
+#define __FAT_FORMAT_H__
+
+#include "GptWorker.h"
+
+#define FAT_SECTOR_SIZE 512
+#define FAT_BUFFER_SECTORS 1
+#define FAT32_LAST_CLUSTER 0xFFFFFFFF
+#define FAT32_INVALID_CLUSTER 0xFFFFFFFF
+#define FAT_DIR_ENTRY_SIZE 32
+#define FAT_BUFFERS 1
+#define DEFAULT_FAT_LABEL_NAME "EFIVOL"
+
+#define GET_32BIT_WORD(Buffer, Location) ( ((UINT32)Buffer[Location + 3] << 24) + \
+ ((UINT32)Buffer[Location + 2] <<16 ) + \
+ ((UINT32)Buffer[Location + 1] << 8) + \
+ (UINT32)Buffer[Location+0] )
+
+#define GET_16BIT_WORD(Buffer, Location) ( ((UINT16)Buffer[Location + 1] << 8) + \
+ (UINT16)Buffer[Location+0])
+
+#define SET_32BIT_WORD(Buffer, Location, Value) { Buffer[Location + 0] = (UINT8)((Value) & 0xFF); \
+ Buffer[Location + 1] = (UINT8)((Value >> 8) & 0xFF); \
+ Buffer[Location + 2] = (UINT8)((Value >> 16) & 0xFF); \
+ Buffer[Location + 3] = (UINT8)((Value >> 24) & 0xFF); }
+
+#define SET_16BIT_WORD(Buffer, Location, Value) { Buffer[Location + 0] = (UINT8)((Value) & 0xFF); \
+ Buffer[Location + 1] = (UINT8)((Value >> 8) & 0xFF); }
+
+typedef enum eFatType
+{
+ FAT_TYPE_16,
+ FAT_TYPE_32
+} FAT_FS_TYPE;
+
+
+// Forward declaration
+typedef struct _FAT_BUFFER FAT_BUFFER;
+
+struct _FAT_BUFFER {
+ UINT8 Sector[FAT_SECTOR_SIZE * FAT_BUFFER_SECTORS];
+ UINTN Address;
+ BOOLEAN Dirty;
+ UINT8 *Ptr;
+
+ // Next in chain of sector buffers
+ struct FAT_BUFFER *NextBuf;
+};
+
+typedef struct
+{
+ // Filesystem globals
+ UINT8 SectorsPerCluster;
+ EFI_LBA ClusterBeginLba;
+ UINTN RootdirFirstCluster;
+ UINTN RootdirFirstSector;
+ UINTN RootdirSectors;
+ EFI_LBA FatBeginLba;
+ UINT16 FsInfoSector;
+ EFI_LBA LbaBegin;
+ UINTN FatSectors;
+ UINTN NextFreeCluster;
+ UINT16 RootEntryCount;
+ UINT16 ReservedSectors;
+ UINT8 NumOfFats;
+ FAT_FS_TYPE FatType;
+
+ // Working buffer
+ FAT_BUFFER CurrentSector;
+ // FAT Buffer
+ FAT_BUFFER *FatBufferHead;
+ FAT_BUFFER FatBuffers[FAT_BUFFERS];
+ EFI_LBA StartingLBA;
+ EFI_LBA EndingLBA;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+
+} FATFS;
+
+
+
+//-----------------------------------------------------------------------------
+// Prototypes
+//-----------------------------------------------------------------------------
+EFI_STATUS
+FatFormat (
+ IN EFI_LBA StartingLBA,
+ IN EFI_LBA EndingLBA,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN CHAR8 *VolumeName,
+ IN BOOLEAN ForceFat32
+ );
+
+#endif
diff --git a/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
new file mode 100644
index 000000000000..0546c94488b0
--- /dev/null
+++ b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
@@ -0,0 +1,1902 @@
+/** @file
+Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2016, Broadcom. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "GptWorker.h"
+
+#define GPT_DEBUG_LEVEL 0
+
+STATIC EFI_PARTITION_TABLE_HEADER *PrimaryHeader = NULL;
+STATIC EFI_PARTITION_TABLE_HEADER *BackupHeader = NULL;
+STATIC EFI_PARTITION_ENTRY *PartEntry = NULL;
+STATIC EFI_PARTITION_ENTRY_STATUS *PEntryStatus = NULL;
+
+STATIC EFI_BLOCK_IO_PROTOCOL *BlockIo;
+STATIC EFI_DISK_IO_PROTOCOL *DiskIo;
+
+STATIC BOOLEAN MbrValid;
+STATIC BOOLEAN GptValid;
+
+STATIC EFI_KNOWN_PARTITION_TYPE PartitionTypes[] =
+{
+ // Known Partition type GUIDs
+ // Expand this table as needed.
+ // Starting with EFI System partition
+ { { 0xC12A7328L, 0xF81F, 0x11D2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B } }, L"EFI System" },
+ // Known Windows partition types
+ { { 0xE3C9E316L, 0x0B5C, 0x4DB8, { 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE } }, L"MS Windows Reserved (MSR)" },
+ { { 0xEBD0A0A2L, 0xB9E5, 0x4433, { 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 } }, L"MS Windows Basic Data" },
+ { { 0x5808C8AAL, 0x7E8F, 0x42E0, { 0x85, 0xD2, 0xE1, 0xE9, 0x04, 0x34, 0xCF, 0xB3 } }, L"MS Windows LDM Metadata" },
+ { { 0xAF9B60A0L, 0x1431, 0x4F62, { 0xBC, 0x68, 0x33, 0x11, 0x71, 0x4A, 0x69, 0xAD } }, L"MS Windows LDM Data" },
+ { { 0xDE94BBA4L, 0x06D1, 0x4D40, { 0xA1, 0x6A, 0xBF, 0xD5, 0x01, 0x79, 0xD6, 0xAC } }, L"MS Windows Recovery Environment" },
+ { { 0xE75CAF8FL, 0xF680, 0x4CEE, { 0xAF, 0xA3, 0xB0, 0x01, 0xE5, 0x6E, 0xFC, 0x2D } }, L"MS Windows Storage Spaces" },
+ // Known Linux partition types
+ { { 0x0FC63DAFL, 0x8483, 0x4772, { 0x8E, 0x79, 0x3D, 0x69, 0xD8, 0x47, 0x7D, 0xE4 } }, L"Linux Filesystem Data" },
+ { { 0xA19D880FL, 0x05FC, 0x4D3B, { 0xA0, 0x06, 0x74, 0x3F, 0x0F, 0x84, 0x91, 0x1E } }, L"Linux RAID" },
+ { { 0x44479540L, 0xF297, 0x41B2, { 0x9A, 0xF7, 0xD1, 0x31, 0xD5, 0xF0, 0x45, 0x8A } }, L"Linux Root (x86)" },
+ { { 0x4F68BCE3L, 0xE8CD, 0x4DB1, { 0x96, 0xE7, 0xFB, 0xCA, 0xF9, 0x84, 0xB7, 0x09 } }, L"Linux Root (x86-64)" },
+ { { 0x69DAD710L, 0x2CE4, 0x4E3C, { 0xB1, 0x6C, 0x21, 0xA1, 0xD4, 0x9A, 0xBe, 0xD3 } }, L"Linux Root (ARM 32-bit)" },
+ { { 0xB921B045L, 0x1DF0, 0x41C3, { 0xAF, 0x44, 0x4C, 0x6F, 0x28, 0x0D, 0x3F, 0xAE } }, L"Linux Root (ARM 64-bit/AARCH64)" },
+ { { 0x0657FD6DL, 0xA4AB, 0x43C4, { 0x84, 0xE5, 0x09, 0x33, 0xC8, 0x4B, 0x4F, 0x4F } }, L"Linux Swap" },
+ { { 0xE6D6D379L, 0xF507, 0x44C2, { 0xA2, 0x3C, 0x23, 0x8F, 0x2A, 0x3D, 0xF9, 0x28 } }, L"Linux Logical Volume Manager (LVM)" },
+ { { 0x933AC7E1L, 0x2EB4, 0x4F13, { 0xB8, 0x44, 0x0E, 0x14, 0xE2, 0xAE, 0xF9, 0x15 } }, L"Linux /home" },
+ { { 0x3B8F8425L, 0x20E0, 0x4F3B, { 0x90, 0x7F, 0x1A, 0x25, 0xA7, 0x6F, 0x98, 0xE8 } }, L"Linux /srv (server data)" },
+ { { 0x7FFEC5C9L, 0x2D00, 0x49B7, { 0x89, 0x41, 0x3E, 0xA1, 0x0A, 0x55, 0x86, 0xB7 } }, L"Linux Plain dm-crypt" },
+ { { 0xCA7D7CCBL, 0x63ED, 0x4C53, { 0x86, 0x1C, 0x17, 0x42, 0x53, 0x60, 0x59, 0xCC } }, L"Linux LUKS" },
+ { { 0x8DA63339L, 0x0007, 0x60C0, { 0xC4, 0x36, 0x08, 0x3A, 0xC8, 0x23, 0x09, 0x08 } }, L"Linux Reserved" },
+};
+
+MASTER_BOOT_RECORD ProtectiveMbrTemplate = {
+ { 0 }, // BoostStrapCode [440]
+ { 0 }, // UniqueMbrSignature[4] (unused)
+ { 0 }, // Unknown[2]
+
+ // PARTITIONS
+ {
+ // MBR_PARTITION_RECORD
+ {
+ 0, // BootIndicator
+ 0, // StartHead
+ 0x1, // StartSector
+ 0x1, // StartTrack
+ PMBR_GPT_PARTITION, // OSIndicator
+ 0xff, // EndHead
+ 0xff, // EndSector
+ 0xff, // EndTrack
+ { 0x1, 0x0, 0x0, 0x0 }, // StartingLba[4]
+ { 0xff, 0xff, 0xff, 0xff }, // SizeInLba[4]
+ },
+ { 0 }, { 0 }, { 0 }, // Unused partitions
+ },
+
+ MBR_SIGNATURE // Signature
+};
+
+STATIC UINT32 CurRand = 1;
+
+/**
+ Get random seed based on the RTC
+
+**/
+
+STATIC
+VOID
+Srand (VOID)
+{
+ EFI_TIME Time;
+ UINT32 Seed;
+ UINT64 MonotonicCount;
+
+ gRT->GetTime (&Time, NULL);
+ Seed = (~Time.Hour << 24 | Time.Day << 16 | Time.Minute << 8 | Time.Second);
+ Seed ^= Time.Nanosecond;
+ Seed ^= Time.Year << 7;
+
+ gBS->GetNextMonotonicCount (&MonotonicCount);
+ Seed += (UINT32)MonotonicCount;
+
+ /* Store this seed */
+ CurRand = (UINT32)Seed;
+}
+
+/**
+ Get a pseudo-random number
+
+ @retval A pseudo-random number in the range 0 - 0x7fff
+**/
+
+STATIC UINTN Rand (VOID)
+{
+ /* return a pseudo-random in range 0 - 0x7fff */
+ return ((CurRand = CurRand * 214013L + 2531011L) >> 16) & 0x7fff;
+}
+
+/**
+ Generate a GUID
+
+ @param[in] Guid A pointer to a GUID receiving a generated value
+**/
+
+STATIC VOID
+GenerateGuid (OUT GUID *Guid)
+{
+ UINTN Index;
+ UINT16 Buffer[sizeof(GUID)];
+
+ /* Generates 128 random bits for new UUID */
+ for (Index = 0; Index < sizeof(GUID); Index++) {
+ UINTN V;
+
+ V = Rand () >> 7;
+ Buffer[Index] = (UINT16)V;
+ }
+ /* set variant 10x and version 4 as required by RFC 4122 */
+ Buffer[8] = 0x80 | (Buffer[8] & 0x3f);
+ Buffer[6] = 0x40 | (Buffer[6] & 0xf);
+ CopyGuid (Guid, (CONST GUID *)Buffer);
+}
+
+/**
+ Clean up globals
+**/
+VOID
+GptCleanupGlobals (VOID)
+{
+ SHELL_FREE_NON_NULL (PrimaryHeader);
+ SHELL_FREE_NON_NULL (BackupHeader);
+ SHELL_FREE_NON_NULL (PartEntry);
+ SHELL_FREE_NON_NULL (PEntryStatus);
+ GptValid = FALSE;
+ MbrValid = FALSE;
+}
+
+/**
+ Caution: This function may receive untrusted input.
+ The GPT partition table header is external input, so this routine
+ will do basic validation for GPT partition table header before return.
+
+ @param[in] Lba The starting Lba of the Partition Table
+ @param[out] PartHeader Stores the partition table that is read
+
+ @retval EFI_SUCCESS The partition table is valid
+ @retval ERROR The partition table is not valid
+
+**/
+STATIC
+EFI_STATUS
+PartitionValidGptTable (
+ IN EFI_LBA Lba,
+ OUT EFI_PARTITION_TABLE_HEADER *PartHeader
+ );
+
+/**
+ Check if the CRC field in the Partition table header is valid
+ for Partition entry array.
+
+ @param[in] PartHeader Partition table header structure
+
+ @retval TRUE the CRC is valid
+ @retval FALSE the CRC is invalid
+
+**/
+STATIC
+BOOLEAN
+PartitionCheckGptEntryArrayCRC (
+ IN EFI_PARTITION_TABLE_HEADER *PartHeader
+ );
+
+
+/**
+ Restore Partition Table to its alternate place
+ (Primary -> Backup or Backup -> Primary).
+
+ @param[in] PartHeader Partition table header structure.
+
+ @retval TRUE Restoring succeeds
+ @retval FALSE Restoring failed
+
+**/
+STATIC
+BOOLEAN
+PartitionRestoreGptTable (
+ IN EFI_PARTITION_TABLE_HEADER *PartHeader
+ );
+
+
+/**
+ This routine will check GPT partition entry and return entry status.
+
+ Caution: This function may receive untrusted input.
+ The GPT partition entry is external input, so this routine
+ will do basic validation for GPT partition entry and report status.
+
+ @param[in] PartHeader Partition table header structure
+ @param[in] PartEntry The partition entry array
+ @param[out] PEntryStatus the partition entry status array
+ recording the status of each partition
+
+**/
+STATIC
+VOID
+PartitionCheckGptEntry (
+ IN EFI_PARTITION_TABLE_HEADER *PartHeader,
+ IN EFI_PARTITION_ENTRY *PartEntry,
+ OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus
+ );
+
+
+/**
+ Checks the CRC32 value in the table header.
+
+ @param MaxSize Max Size limit
+ @param Size The size of the table
+ @param Hdr Table to check
+
+ @return TRUE CRC Valid
+ @return FALSE CRC Invalid
+
+**/
+STATIC
+BOOLEAN
+PartitionCheckCrcAltSize (
+ IN UINTN MaxSize,
+ IN UINTN Size,
+ IN OUT EFI_TABLE_HEADER *Hdr
+ );
+
+
+/**
+ Checks the CRC32 value in the table header.
+
+ @param MaxSize Max Size limit
+ @param Hdr Table to check
+
+ @return TRUE CRC Valid
+ @return FALSE CRC Invalid
+
+**/
+STATIC
+BOOLEAN
+PartitionCheckCrc (
+ IN UINTN MaxSize,
+ IN OUT EFI_TABLE_HEADER *Hdr
+ );
+
+
+/**
+ Updates the CRC32 value in the table header.
+
+ @param Size The size of the table
+ @param Hdr Table to update
+
+**/
+STATIC
+VOID
+PartitionSetCrcAltSize (
+ IN UINTN Size,
+ IN OUT EFI_TABLE_HEADER *Hdr
+ );
+
+
+/**
+ Updates the CRC32 value in the table header.
+
+ @param Hdr Table to update
+
+**/
+STATIC
+VOID
+PartitionSetCrc (
+ IN OUT EFI_TABLE_HEADER *Hdr
+ );
+
+
+/**
+ Get GPT tables.
+
+ Caution: This function may receive untrusted input.
+ The GPT partition table is external input, so this routine
+ will do basic validation for GPT partition table before install
+ child handle for each GPT partition.
+
+ @param[in] DiskIoProt DiskIo interface.
+ @param[in] BlockIoProt BlockIo interface.
+
+ @retval EFI_SUCCESS Valid GPT disk.
+ @retval EFI_MEDIA_CHANGED Media changed Detected.
+ @retval other Not a valid GPT disk.
+
+**/
+EFI_STATUS
+PartitionGetGptTables (
+ IN EFI_DISK_IO_PROTOCOL *DiskIoProt,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIoProt
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+ EFI_LBA LastBlock;
+ UINTN Index;
+ EFI_STATUS GptValidStatus;
+ UINT32 MediaId;
+ MASTER_BOOT_RECORD *ProtectiveMbr;
+
+ // Clear leftovers
+ GptCleanupGlobals ();
+
+ MbrValid = FALSE;
+ GptValid = FALSE;
+
+ ProtectiveMbr = NULL;
+
+ BlockIo = BlockIoProt;
+ DiskIo = DiskIoProt;
+
+ if (CurRand == 1) {
+ Srand ();
+ }
+
+ BlockSize = BlockIo->Media->BlockSize;
+ LastBlock = BlockIo->Media->LastBlock;
+ MediaId = BlockIo->Media->MediaId;
+
+ DEBUG ((EFI_D_VERBOSE, " BlockSize : %d \n", BlockSize));
+ DEBUG ((EFI_D_VERBOSE, " LastBlock : %lx \n", LastBlock));
+
+ GptValidStatus = EFI_NOT_FOUND;
+ GptValid = FALSE;
+ MbrValid = FALSE;
+
+ //
+ // Allocate a buffer for the Protective MBR
+ //
+ ProtectiveMbr = AllocatePool (BlockSize);
+ if (ProtectiveMbr == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Read the Protective MBR from LBA #0
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ MediaId,
+ 0,
+ BlockSize,
+ ProtectiveMbr
+ );
+ if (EFI_ERROR (Status)) {
+ GptValidStatus = Status;
+ goto Done;
+ }
+
+ //
+ // Verify that the Protective MBR is valid
+ //
+ for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
+ if (ProtectiveMbr->Partition[Index].BootIndicator == 0x00 &&
+ ProtectiveMbr->Partition[Index].OSIndicator == PMBR_GPT_PARTITION &&
+ UNPACK_UINT32 (ProtectiveMbr->Partition[Index].StartingLBA) == 1
+ ) {
+ break;
+ }
+ }
+ if (Index == MAX_MBR_PARTITIONS) {
+ goto Done;
+ }
+
+ MbrValid = TRUE;
+
+ //
+ // Allocate the GPT structures
+ //
+ PrimaryHeader = AllocateZeroPool (sizeof(EFI_PARTITION_TABLE_HEADER));
+ if (PrimaryHeader == NULL) {
+ goto Done;
+ }
+
+ BackupHeader = AllocateZeroPool (sizeof(EFI_PARTITION_TABLE_HEADER));
+ if (BackupHeader == NULL) {
+ goto Done;
+ }
+
+ //
+ // Check primary and backup partition tables
+ //
+ Status = PartitionValidGptTable (PRIMARY_PART_HEADER_LBA, PrimaryHeader);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, " Not Valid primary partition table\n"));
+
+ Status = PartitionValidGptTable (LastBlock, BackupHeader);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, " Not Valid backup partition table\n"));
+ goto Done;
+ } else {
+ DEBUG ((EFI_D_INFO, " Valid backup partition table\n"));
+ DEBUG ((EFI_D_INFO, " Restore primary partition table by the backup\n"));
+ if (!PartitionRestoreGptTable (BackupHeader)) {
+ DEBUG ((EFI_D_INFO, " Restore primary partition table error\n"));
+ }
+
+ Status = PartitionValidGptTable (BackupHeader->AlternateLBA, PrimaryHeader);
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, " Restore backup partition table success\n"));
+ }
+ }
+ } else if (EFI_ERROR (PartitionValidGptTable (PrimaryHeader->AlternateLBA, BackupHeader))) {
+ DEBUG ((EFI_D_INFO, " Valid primary and !Valid backup partition table\n"));
+ DEBUG ((EFI_D_INFO, " Restore backup partition table by the primary\n"));
+ if (!PartitionRestoreGptTable (PrimaryHeader)) {
+ DEBUG ((EFI_D_INFO, " Restore backup partition table error\n"));
+ }
+
+ Status = PartitionValidGptTable (PrimaryHeader->AlternateLBA, BackupHeader);
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, " Restore backup partition table success\n"));
+ }
+ }
+
+ DEBUG ((EFI_D_VERBOSE, " Valid primary and Valid backup partition table\n"));
+
+ //
+ // Read the EFI Partition Entries
+ //
+ PartEntry = AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry);
+ if (PartEntry == NULL) {
+ DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
+ goto Done;
+ }
+
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ MediaId,
+ MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockSize),
+ PrimaryHeader->NumberOfPartitionEntries * (PrimaryHeader->SizeOfPartitionEntry),
+ PartEntry
+ );
+ if (EFI_ERROR (Status)) {
+ GptValidStatus = Status;
+ DEBUG ((EFI_D_ERROR, " Partition Entry ReadDisk error\n"));
+ goto Done;
+ }
+
+ DEBUG ((EFI_D_VERBOSE, " Partition entries read block success\n"));
+
+ DEBUG ((EFI_D_VERBOSE, " Number of partition entries: %d\n", PrimaryHeader->NumberOfPartitionEntries));
+
+ PEntryStatus = AllocateZeroPool (PrimaryHeader->NumberOfPartitionEntries * sizeof(EFI_PARTITION_ENTRY_STATUS));
+ if (PEntryStatus == NULL) {
+ DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
+ goto Done;
+ }
+
+ //
+ // Check the integrity of partition entries
+ //
+ PartitionCheckGptEntry (PrimaryHeader, PartEntry, PEntryStatus);
+
+ //
+ // If we got this far the GPT layout of the disk is valid and we should return true
+ //
+ GptValidStatus = EFI_SUCCESS;
+
+ Done:
+ SHELL_FREE_NON_NULL (ProtectiveMbr);
+ if (EFI_ERROR (GptValidStatus)) {
+ SHELL_FREE_NON_NULL (PrimaryHeader);
+ SHELL_FREE_NON_NULL (BackupHeader);
+ SHELL_FREE_NON_NULL (PartEntry);
+ SHELL_FREE_NON_NULL (PEntryStatus);
+ } else {
+ GptValid = TRUE;
+ }
+
+ return GptValidStatus;
+}
+
+/**
+ This routine will read GPT partition table header and return it.
+
+ Caution: This function may receive untrusted input.
+ The GPT partition table header is external input, so this routine
+ will do basic validation for GPT partition table header before return.
+
+ @param[in] Lba The starting Lba of the Partition Table
+ @param[out] PartHeader Stores the partition table that is read
+
+ @retval TRUE The partition table is valid
+ @retval FALSE The partition table is not valid
+
+**/
+STATIC
+EFI_STATUS
+PartitionValidGptTable (
+ IN EFI_LBA Lba,
+ OUT EFI_PARTITION_TABLE_HEADER *PartHeader
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+ EFI_PARTITION_TABLE_HEADER *PartHdr;
+ UINT32 MediaId;
+
+ BlockSize = BlockIo->Media->BlockSize;
+ MediaId = BlockIo->Media->MediaId;
+ PartHdr = AllocateZeroPool (BlockSize);
+
+ if (PartHdr == NULL) {
+ DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Read the EFI Partition Table Header
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ MediaId,
+ MultU64x32 (Lba, BlockSize),
+ BlockSize,
+ PartHdr
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (PartHdr);
+ return Status;
+ }
+
+ if ((PartHdr->Header.Signature != EFI_PTAB_HEADER_ID) ||
+ !PartitionCheckCrc (BlockSize, &PartHdr->Header) ||
+ PartHdr->MyLBA != Lba ||
+ (PartHdr->SizeOfPartitionEntry < sizeof(EFI_PARTITION_ENTRY))
+ ) {
+ DEBUG ((EFI_D_ERROR, "Invalid efi partition table header\n"));
+ FreePool (PartHdr);
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ //
+ // Ensure the NumberOfPartitionEntries * SizeOfPartitionEntry doesn't overflow.
+ //
+ if (PartHdr->NumberOfPartitionEntries > DivU64x32 (MAX_UINTN, PartHdr->SizeOfPartitionEntry)) {
+ FreePool (PartHdr);
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ CopyMem (PartHeader, PartHdr, sizeof(EFI_PARTITION_TABLE_HEADER));
+ if (!PartitionCheckGptEntryArrayCRC (PartHeader)) {
+ FreePool (PartHdr);
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ DEBUG ((EFI_D_VERBOSE, " Valid efi partition table header\n"));
+ FreePool (PartHdr);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if the CRC field in the Partition table header is valid
+ for Partition entry array.
+
+ @param[in] PartHeader Partition table header structure
+
+ @retval TRUE the CRC is valid
+ @retval FALSE the CRC is invalid
+
+**/
+STATIC
+BOOLEAN
+PartitionCheckGptEntryArrayCRC (
+ IN EFI_PARTITION_TABLE_HEADER *PartHeader
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Ptr;
+ UINT32 Crc;
+ UINTN Size;
+
+ //
+ // Read the EFI Partition Entries
+ //
+ Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry);
+ if (Ptr == NULL) {
+ DEBUG ((EFI_D_ERROR, " Allocate pool error\n"));
+ return FALSE;
+ }
+
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 (PartHeader->PartitionEntryLBA, BlockIo->Media->BlockSize),
+ PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
+ Ptr
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (Ptr);
+ return FALSE;
+ }
+
+ Size = PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry;
+
+ Status = gBS->CalculateCrc32 (Ptr, Size, &Crc);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "CheckPEntryArrayCRC: Crc calculation failed\n"));
+ FreePool (Ptr);
+ return FALSE;
+ }
+
+ FreePool (Ptr);
+
+ return (BOOLEAN)(PartHeader->PartitionEntryArrayCRC32 == Crc);
+}
+
+
+/**
+ Restore Partition Table to its alternate place
+ (Primary -> Backup or Backup -> Primary).
+
+ @param[in] PartHeader Partition table header structure.
+
+ @retval TRUE Restoring succeeds
+ @retval FALSE Restoring failed
+
+**/
+STATIC
+BOOLEAN
+PartitionRestoreGptTable (
+ IN EFI_PARTITION_TABLE_HEADER *PartHeader
+ )
+{
+ EFI_STATUS Status;
+ UINTN BlockSize;
+ EFI_PARTITION_TABLE_HEADER *PartHdr;
+ EFI_LBA PEntryLBA;
+ UINT8 *Ptr;
+ UINT32 MediaId;
+
+ PartHdr = NULL;
+ Ptr = NULL;
+
+ BlockSize = BlockIo->Media->BlockSize;
+ MediaId = BlockIo->Media->MediaId;
+
+ PartHdr = AllocateZeroPool (BlockSize);
+
+ if (PartHdr == NULL) {
+ DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
+ return FALSE;
+ }
+
+ PEntryLBA = (PartHeader->MyLBA == PRIMARY_PART_HEADER_LBA) ?\
+ (PartHeader->LastUsableLBA + 1) :\
+ (PRIMARY_PART_HEADER_LBA + 1);
+
+ CopyMem (PartHdr, PartHeader, sizeof(EFI_PARTITION_TABLE_HEADER));
+
+ PartHdr->MyLBA = PartHeader->AlternateLBA;
+ PartHdr->AlternateLBA = PartHeader->MyLBA;
+ PartHdr->PartitionEntryLBA = PEntryLBA;
+ PartitionSetCrc ((EFI_TABLE_HEADER *)PartHdr);
+
+ Status = DiskIo->WriteDisk (
+ DiskIo,
+ MediaId,
+ MultU64x32 (PartHdr->MyLBA, (UINT32)BlockSize),
+ BlockSize,
+ PartHdr
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry);
+ if (Ptr == NULL) {
+ DEBUG ((EFI_D_ERROR, " Allocate pool error\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ MediaId,
+ MultU64x32 (PartHeader->PartitionEntryLBA, (UINT32)BlockSize),
+ PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
+ Ptr
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = DiskIo->WriteDisk (
+ DiskIo,
+ MediaId,
+ MultU64x32 (PEntryLBA, (UINT32)BlockSize),
+ PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
+ Ptr
+ );
+
+ Done:
+ FreePool (PartHdr);
+
+ if (Ptr != NULL) {
+ FreePool (Ptr);
+ }
+
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ This routine will check GPT partition entry and return entry status.
+
+ Caution: This function may receive untrusted input.
+ The GPT partition entry is external input, so this routine
+ will do basic validation for GPT partition entry and report status.
+
+ @param[in] PartHeader Partition table header structure
+ @param[in] PartEntry The partition entry array
+ @param[out] PEntryStatus the partition entry status array
+ recording the status of each partition
+
+**/
+STATIC
+VOID
+PartitionCheckGptEntry (
+ IN EFI_PARTITION_TABLE_HEADER *PartHeader,
+ IN EFI_PARTITION_ENTRY *PartEntry,
+ OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus
+ )
+{
+ EFI_LBA StartingLBA;
+ EFI_LBA EndingLBA;
+ EFI_PARTITION_ENTRY *Entry;
+ UINTN Index1;
+ UINTN Index2;
+
+ DEBUG ((EFI_D_VERBOSE, " start check partition entries\n"));
+ for (Index1 = 0; Index1 < PartHeader->NumberOfPartitionEntries; Index1++) {
+ Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index1 * PartHeader->SizeOfPartitionEntry);
+ if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {
+ continue;
+ }
+
+ StartingLBA = Entry->StartingLBA;
+ EndingLBA = Entry->EndingLBA;
+ if (StartingLBA > EndingLBA ||
+ StartingLBA < PartHeader->FirstUsableLBA ||
+ StartingLBA > PartHeader->LastUsableLBA ||
+ EndingLBA < PartHeader->FirstUsableLBA ||
+ EndingLBA > PartHeader->LastUsableLBA
+ ) {
+ PEntryStatus[Index1].OutOfRange = TRUE;
+ continue;
+ }
+
+ if ((Entry->Attributes & BIT1) != 0) {
+ //
+ // If Bit 1 is set, this indicate that this is an OS specific GUID partition.
+ //
+ PEntryStatus[Index1].OsSpecific = TRUE;
+ }
+
+ for (Index2 = Index1 + 1; Index2 < PartHeader->NumberOfPartitionEntries; Index2++) {
+ Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index2 * PartHeader->SizeOfPartitionEntry);
+ if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {
+ continue;
+ }
+
+ if (Entry->EndingLBA >= StartingLBA && Entry->StartingLBA <= EndingLBA) {
+ //
+ // This region overlaps with the Index1'th region
+ //
+ PEntryStatus[Index1].Overlap = TRUE;
+ PEntryStatus[Index2].Overlap = TRUE;
+ continue;
+ }
+ }
+ }
+
+ DEBUG ((EFI_D_VERBOSE, " End check partition entries\n"));
+}
+
+
+/**
+ Updates the CRC32 value in the table header.
+
+ @param Hdr Table to update
+
+**/
+STATIC
+VOID
+PartitionSetCrc (
+ IN OUT EFI_TABLE_HEADER *Hdr
+ )
+{
+ PartitionSetCrcAltSize (Hdr->HeaderSize, Hdr);
+}
+
+
+/**
+ Updates the CRC32 value in the table header.
+
+ @param Size The size of the table
+ @param Hdr Table to update
+
+**/
+STATIC
+VOID
+PartitionSetCrcAltSize (
+ IN UINTN Size,
+ IN OUT EFI_TABLE_HEADER *Hdr
+ )
+{
+ UINT32 Crc;
+
+ Hdr->CRC32 = 0;
+ gBS->CalculateCrc32 ((UINT8 *)Hdr, Size, &Crc);
+ Hdr->CRC32 = Crc;
+}
+
+
+/**
+ Checks the CRC32 value in the table header.
+
+ @param MaxSize Max Size limit
+ @param Hdr Table to check
+
+ @return TRUE CRC Valid
+ @return FALSE CRC Invalid
+
+**/
+STATIC
+BOOLEAN
+PartitionCheckCrc (
+ IN UINTN MaxSize,
+ IN OUT EFI_TABLE_HEADER *Hdr
+ )
+{
+ return PartitionCheckCrcAltSize (MaxSize, Hdr->HeaderSize, Hdr);
+}
+
+
+/**
+ Checks the CRC32 value in the table header.
+
+ @param MaxSize Max Size limit
+ @param Size The size of the table
+ @param Hdr Table to check
+
+ @return TRUE CRC Valid
+ @return FALSE CRC Invalid
+
+**/
+STATIC
+BOOLEAN
+PartitionCheckCrcAltSize (
+ IN UINTN MaxSize,
+ IN UINTN Size,
+ IN OUT EFI_TABLE_HEADER *Hdr
+ )
+{
+ UINT32 Crc;
+ UINT32 OrgCrc;
+ EFI_STATUS Status;
+
+ Crc = 0;
+
+ if (Size == 0) {
+ //
+ // If header size is 0 CRC will pass so return FALSE here
+ //
+ return FALSE;
+ }
+
+ if ((MaxSize != 0) && (Size > MaxSize)) {
+ DEBUG ((EFI_D_ERROR, "CheckCrc32: Size > MaxSize\n"));
+ return FALSE;
+ }
+ //
+ // clear old crc from header
+ //
+ OrgCrc = Hdr->CRC32;
+ Hdr->CRC32 = 0;
+
+ Status = gBS->CalculateCrc32 ((UINT8 *)Hdr, Size, &Crc);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc calculation failed\n"));
+ return FALSE;
+ }
+ //
+ // set results
+ //
+ Hdr->CRC32 = Crc;
+
+ //
+ // return status
+ //
+ DEBUG_CODE_BEGIN ();
+ if (OrgCrc != Crc) {
+ DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc check failed\n"));
+ }
+ DEBUG_CODE_END ();
+
+ return (BOOLEAN)(OrgCrc == Crc);
+}
+
+/**
+ Converts a GUID into a unicode string.
+
+ @param [in] Guid A GUID to be converted
+ @param [out] Buffer A pointer to a buffer receiving the string
+ @param [in] BufferSize Size of the buffer
+
+ @return EFI_SUCCESS Successful conversion
+ @return EFI_INVALID_PARAMETER Conversion failed
+
+**/
+
+STATIC
+EFI_STATUS
+GuidToString (
+ IN EFI_GUID *Guid,
+ OUT CHAR16 *Buffer,
+ IN UINTN BufferSize
+ )
+{
+ UINTN Size;
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ Size = UnicodeSPrint (
+ Buffer,
+ BufferSize,
+ L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ (UINTN)Guid->Data1,
+ (UINTN)Guid->Data2,
+ (UINTN)Guid->Data3,
+ (UINTN)Guid->Data4[0],
+ (UINTN)Guid->Data4[1],
+ (UINTN)Guid->Data4[2],
+ (UINTN)Guid->Data4[3],
+ (UINTN)Guid->Data4[4],
+ (UINTN)Guid->Data4[5],
+ (UINTN)Guid->Data4[6],
+ (UINTN)Guid->Data4[7]
+ );
+ if (!Size) {
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ return Status;
+}
+
+/**
+ Get a string representation of a known
+ partition type GUID. If partition GUID is not
+ known, gets a string representation of the GUID
+
+ @param GUID Guid to be searched for
+ @param PartTypeStr Buffer receiving the string
+ @param NoGuidStr Do not convert GUID to string
+ for an unknown partition type
+
+ @return EFI_SUCCESS GUID type is known
+ @return EFI_NOT_FOUND Unknown GUID partition type
+
+**/
+EFI_STATUS
+GetPartitionTypeStr (
+ IN EFI_GUID Guid,
+ OUT CHAR16 *PartTypeStr,
+ IN BOOLEAN NoGuidStr)
+{
+ UINTN Index;
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+ for (Index = 0; Index < ARRAY_SIZE (PartitionTypes); Index++) {
+ if (CompareGuid (&Guid, &PartitionTypes[Index].TypeGuid)) {
+ StrnCpy (PartTypeStr, PartitionTypes[Index].TypeName, MAX_PARTITION_NAME_LENGTH);
+ return Status;
+ }
+ }
+ if (!NoGuidStr) {
+ GuidToString (&Guid, PartTypeStr, (MAX_PARTITION_NAME_LENGTH + 1) * sizeof(CHAR16));
+ }
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Lists partitions on a block device.
+
+ @return Number of partitions used
+**/
+
+UINTN
+PartitionListGptEntries (VOID)
+{
+ UINTN Index;
+ EFI_PARTITION_ENTRY *Entry;
+ EFI_LBA Length;
+ UINTN NumEntries; // Used entries
+ UINTN BlockSize;
+ BOOLEAN FirstTime;
+ UINT64 BlocksOccupied;
+
+ NumEntries = 0;
+ BlockSize = BlockIo->Media->BlockSize;
+ FirstTime = TRUE;
+
+ if (!GptValid) {
+ return 0;
+ }
+
+ BlocksOccupied = 0;
+
+ for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {
+
+ BOOLEAN Specific;
+ CHAR16 PartTypeStr[MAX_PARTITION_NAME_LENGTH + 1];
+
+ Specific = FALSE;
+
+ Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index * PrimaryHeader->SizeOfPartitionEntry);
+
+ Length = Entry->EndingLBA - Entry->StartingLBA + 1;
+
+ if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {
+ continue;
+ }
+
+ if (FirstTime) {
+ Print (L" No \t%-36s\tStart (LBA)\tEnd (LBA)\tSize (MiB)\t Partition Type\r\n", L"Name");
+ Print (L" ---- -------------------------------------- ----------- ----------- ---------- -------------------------------\r\n");
+ FirstTime = FALSE;
+ }
+ NumEntries++;
+ if (PEntryStatus[Index].OutOfRange ||
+ PEntryStatus[Index].Overlap ||
+ PEntryStatus[Index].OsSpecific) {
+ Specific = TRUE;
+ }
+
+ BlocksOccupied += Length;
+
+ GetPartitionTypeStr (Entry->PartitionTypeGUID, (CHAR16 *)&PartTypeStr, FALSE);
+
+ Print (L"%1s %-3d\t%-36s\t0x%09llx\t0x%09llx\t%06llu\t %s\r\n",
+ Specific ? L"S" : L"",
+ Index + 1,
+ Entry->PartitionName,
+ (UINT64)Entry->StartingLBA,
+ (UINT64)Entry->EndingLBA,
+ (MultU64x32 (Length, BlockSize)) >> 20,
+ PartTypeStr);
+ }
+
+ // This code block is to provide additional info
+ {
+ UINT64 DiskSizeMiB, SizeOccupiedMiB;
+
+ DiskSizeMiB = MultU64x32 (PrimaryHeader->LastUsableLBA - PrimaryHeader->FirstUsableLBA + 1, BlockIo->Media->BlockSize) >> 20;
+ SizeOccupiedMiB = MultU64x32 (BlocksOccupied, BlockIo->Media->BlockSize) >> 20;
+ Print (L"\r\n%d partition(s) used out of %d\r\n", NumEntries, PrimaryHeader->NumberOfPartitionEntries);
+ Print (L"Total device capacity (minus GPT service blocks): %llu MiB\r\nPartitioned space: %llu MiB\r\n",
+ DiskSizeMiB,
+ SizeOccupiedMiB);
+ Print (L"Unpartitioned space available: %llu MiB (%d%%)\n",
+ DiskSizeMiB - SizeOccupiedMiB,
+ (100 * (DiskSizeMiB - SizeOccupiedMiB)) / DiskSizeMiB);
+ }
+
+ return NumEntries;
+}
+
+/**
+ Locate a partition by criteria
+
+ @param Name Partition name (or ordinal represented a string)
+ @param StartLba StartLba of the partition to search for
+ @param EndingLba EndingLba of the partition to search for
+ @param SearchType A combination (OR) of search options.
+ Options are:
+ SRC_BY_NAME = search by partition name
+ SRC_BY_LBA = search by Start/Ending lba
+ SRC_ANY = returns a first used partition
+ SRC_BY_NUM = search by ordinal
+
+
+ @return Non-NULL Pointer to th partition found
+ @return NULL No partition found
+
+**/
+EFI_PARTITION_ENTRY *
+PartitionFindPartitionByCriteria (
+ IN OPTIONAL CONST CHAR16 *Name,
+ IN OPTIONAL EFI_LBA StartLba,
+ IN OPTIONAL EFI_LBA EndingLba,
+ IN SEARCH_TYPE SearchType
+ )
+{
+ UINTN Index;
+ EFI_PARTITION_ENTRY *Entry;
+
+ if (!GptValid) {
+ return NULL;
+ }
+
+ if (!Name && (SearchType & SRC_BY_NAME)) {
+ return NULL;
+ }
+
+ for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {
+ Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index * PrimaryHeader->SizeOfPartitionEntry);
+
+ if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {
+ continue;
+ }
+
+ if (SearchType & SRC_ANY) {
+ return Entry;
+ }
+
+ if (SearchType & SRC_BY_NAME) {
+ if (!StrCmp (Name, Entry->PartitionName)) {
+ return Entry;
+ }
+ }
+ if (SearchType & SRC_BY_NUM) {
+ UINTN Ordinal;
+
+ Ordinal = ShellStrToUintn (Name);
+ if (Index == (Ordinal - 1)) {
+ return Entry;
+ }
+ }
+ if (SearchType & SRC_BY_LBA) {
+ if (
+ ((StartLba >= Entry->StartingLBA) &&
+ (StartLba <= Entry->EndingLBA)
+ ) ||
+ ((EndingLba >= Entry->StartingLBA) &&
+ (EndingLba <= Entry->EndingLBA)
+ )
+ ) {
+ return Entry;
+ }
+ }
+ }
+ return NULL;
+}
+
+/**
+ Prints information on a given partition.
+
+ @param Entry Pointer to the Partition of interest
+**/
+
+VOID
+PartitionPrintGptPartInfo (
+ IN EFI_PARTITION_ENTRY *Entry
+ )
+{
+ CONST CHAR16 PartStr[MAX_PARTITION_NAME_LENGTH + 1] = { L'\0' };
+ CONST CHAR16 *StrUnknown = L"Unknown";
+ EFI_STATUS Status;
+ EFI_LBA Length;
+
+ ASSERT (Entry);
+
+ Status = GetPartitionTypeStr (Entry->PartitionTypeGUID, (CHAR16 *)&PartStr, TRUE);
+ if (EFI_ERROR (Status)) {
+ StrCpy ((CHAR16 *)&PartStr, StrUnknown);
+ }
+
+ Length = Entry->EndingLBA - Entry->StartingLBA + 1;
+
+ Print (L"Partition name: %s\r\n", Entry->PartitionName);
+ Print (L"Starting LBA : 0x%09llx\r\nEnding LBA : 0x%09llx\r\n",
+ (UINT64)Entry->StartingLBA, (UINT64)Entry->EndingLBA);
+ Print (L"Partition Size: %llu MiB (0x%llx blocks)\n",
+ (MultU64x32 (Length, BlockIo->Media->BlockSize)) >> 20, Length);
+ Print (L"Attributes : 0x%09llx\r\n", Entry->Attributes);
+ Print (L"Type/GUID : %s/%g\r\n", PartStr, &Entry->PartitionTypeGUID);
+ Print (L"Unique GUID : %g\n", &Entry->UniquePartitionGUID);
+}
+
+
+/**
+ Writes protective MBR to a block device.
+
+ @return EFI_SUCCESS MBR written successfully
+ @return other Failed to write an MBR
+
+**/
+
+STATIC
+EFI_STATUS
+WriteProtectiveMbr (
+ VOID
+ )
+{
+ UINT32 BlockSize;
+ UINT64 DiskSize;
+ EFI_STATUS Status;
+ MBR_PARTITION_RECORD *Partition;
+ MASTER_BOOT_RECORD *ProtectiveMbr;
+
+ BlockSize = BlockIo->Media->BlockSize;
+
+ ProtectiveMbr = NULL;
+ ProtectiveMbr = AllocateZeroPool (BlockSize);
+ if (ProtectiveMbr == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DiskSize = BlockIo->Media->LastBlock + 1;
+ if (DiskSize > 0xffffffff) {
+ DiskSize = 0xffffffff;
+ }
+
+ CopyMem (ProtectiveMbr, &ProtectiveMbrTemplate, sizeof(MASTER_BOOT_RECORD));
+
+ Partition = &ProtectiveMbr->Partition[0];
+
+ Partition->BootIndicator = 0;
+ Partition->StartSector = 1;
+
+ //
+ // We don't actually know this data, so we'll make up
+ // something that seems likely.
+ //
+
+ //
+ // Old software is expecting the Partition to start on
+ // a Track boundary, so we'll set track to 1 to avoid "overlay"
+ // with the MBR
+ //
+
+ Partition->StartTrack = 1;
+
+ Status = DiskIo->WriteDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ 0,
+ BlockSize,
+ ProtectiveMbr
+ );
+
+ MbrValid = !EFI_ERROR (Status);
+
+ SHELL_FREE_NON_NULL (ProtectiveMbr);
+
+ return Status;
+}
+
+/**
+ Write GPT tables to the block device.
+
+ @return EFI_SUCCESS GPT tables were successfully written/updated
+ @return other Failed to write/update GPT tables
+
+**/
+
+STATIC
+EFI_STATUS
+WriteGPT (
+ VOID
+ )
+/*
+ CALLER is expected to fill in:
+ FirstUseableLBA
+ LastUseableLBA
+ EntryCount
+ DiskGUID
+
+ We fill in the rest, and blast it out.
+
+ Returns a status.
+
+*/
+{
+ UINT32 BlockSize;
+ UINT32 TableSize;
+ EFI_STATUS Status = EFI_SUCCESS;
+
+ BlockSize = BlockIo->Media->BlockSize;
+ TableSize = PrimaryHeader->NumberOfPartitionEntries * sizeof(EFI_PARTITION_ENTRY);
+
+ if (!MbrValid) {
+ WriteProtectiveMbr ();
+ }
+ //
+ // Write out the primary header...
+ //
+ PrimaryHeader->Header.Signature = EFI_PTAB_HEADER_ID;
+ PrimaryHeader->Header.Revision = GPT_REVISION_1_0;
+ PrimaryHeader->Header.HeaderSize = sizeof(EFI_PARTITION_TABLE_HEADER);
+
+ PrimaryHeader->AlternateLBA = BackupHeader->MyLBA;
+
+ PrimaryHeader->SizeOfPartitionEntry = sizeof(EFI_PARTITION_ENTRY);
+
+ Status = gBS->CalculateCrc32 ((UINT8 *)PartEntry, TableSize, &PrimaryHeader->PartitionEntryArrayCRC32);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Write primary header
+ PartitionSetCrc (&PrimaryHeader->Header);
+
+ Status = DiskIo->WriteDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 (PrimaryHeader->MyLBA, (UINT32)BlockSize),
+ BlockSize,
+ PrimaryHeader
+ );
+
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Write out the primary table ...
+ //
+ Status = DiskIo->WriteDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 (PrimaryHeader->PartitionEntryLBA, (UINT32)BlockSize),
+ TableSize,
+ PartEntry
+ );
+
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Write out the secondary header and table by calling restore
+ //
+
+ if (!PartitionRestoreGptTable (PrimaryHeader)) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+ BlockIo->FlushBlocks (BlockIo);
+ GptValid = !EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ (Re)initialize GPT tables on the block device
+
+ @return EFI_SUCCESS Successfully (re)initialized GPT Tables
+ @return other Failed to (re)initialize GPT tables
+
+**/
+STATIC
+EFI_STATUS
+TableCreateEmptyGpt (VOID)
+{
+ UINTN EntryCount;
+ UINTN BlockFit;
+ UINTN BlockSize;
+ UINTN EntryBlocks;
+ UINT64 DiskSize;
+ UINTN TableSize;
+ EFI_LBA Header1_LBA;
+ EFI_LBA Table1_LBA;
+ EFI_LBA Header2_LBA;
+ EFI_LBA Table2_LBA;
+ EFI_LBA FirstUsableLBA;
+ EFI_LBA LastUsableLBA;
+ EFI_STATUS Status;
+
+ EntryCount = ENTRY_DEFAULT;
+ BlockSize = BlockIo->Media->BlockSize;
+ BlockFit = BlockSize / sizeof(EFI_PARTITION_ENTRY);
+
+ if (BlockFit > ENTRY_DEFAULT) {
+ EntryCount = BlockFit;
+ }
+ EntryBlocks = EntryCount / BlockFit;
+
+ if ((EntryBlocks * BlockFit) != EntryCount) {
+ Status = EFI_VOLUME_CORRUPTED;
+ PrintErr (L"Invalid Entry blocks and Entry count combination\n", Status);
+ return Status;
+ }
+
+ DiskSize = BlockIo->Media->LastBlock + 1;
+
+ SHELL_FREE_NON_NULL (PrimaryHeader);
+ SHELL_FREE_NON_NULL (BackupHeader);
+ SHELL_FREE_NON_NULL (PartEntry);
+
+ PrimaryHeader = AllocateZeroPool (BlockSize);
+ if (PrimaryHeader == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ BackupHeader = AllocateZeroPool (BlockSize);
+ if (BackupHeader == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Header1_LBA = 1;
+ Table1_LBA = 2;
+ FirstUsableLBA = Table1_LBA + EntryBlocks;
+
+ Header2_LBA = DiskSize - 1;
+ Table2_LBA = Header2_LBA - EntryBlocks;
+ LastUsableLBA = Table2_LBA - 1;
+
+ TableSize = EntryBlocks * BlockSize;
+
+ if (TableSize != (EntryCount * sizeof(EFI_PARTITION_ENTRY))) {
+ Status = EFI_VOLUME_CORRUPTED;
+ PrintErr (L"Invalid Table size and Entry count combination\n", Status);
+ return Status;
+ }
+
+ if (GPT_DEBUG_LEVEL) {
+ Print (L"DiskSize = %lx\n", DiskSize);
+ Print (L"BlockSize = %x\n", BlockSize);
+ Print (L"Header1_LBA = %lx\n", Header1_LBA);
+ Print (L"Table1_LBA = %lx\n", Table1_LBA);
+ Print (L"FirstUsableLBA = %lx\n", FirstUsableLBA);
+ Print (L"Header2_LBA = %lx\n", Header2_LBA);
+ Print (L"Table2_LBA = %lx\n", Table2_LBA);
+ Print (L"LastUsableLBA = %lx\n", LastUsableLBA);
+ Print (L"EntryCount = %x\n", EntryCount);
+ Print (L"EntryBlocks = %x\n", EntryBlocks);
+ }
+
+ //
+ // Since we're making empty tables, we just write zeros...
+ //
+
+ PartEntry = AllocateZeroPool (TableSize);
+ if (PartEntry == NULL) {
+ SHELL_FREE_NON_NULL (PrimaryHeader);
+ SHELL_FREE_NON_NULL (BackupHeader);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ PEntryStatus = AllocateZeroPool (TableSize);
+
+ PrimaryHeader->FirstUsableLBA = FirstUsableLBA;
+ PrimaryHeader->LastUsableLBA = LastUsableLBA;
+ PrimaryHeader->NumberOfPartitionEntries = (UINT32)EntryCount;
+ GenerateGuid (&PrimaryHeader->DiskGUID);
+
+ PrimaryHeader->MyLBA = Header1_LBA;
+ BackupHeader->MyLBA = Header2_LBA;
+ PrimaryHeader->PartitionEntryLBA = Table1_LBA;
+ BackupHeader->PartitionEntryLBA = Table2_LBA;
+
+ Status = WriteGPT ();
+
+ return Status;
+}
+
+/**
+ Clear GPT partitions.
+
+ @return EFI_SUCCESS Cleared successfully
+ @return FALSE Failed to clear
+
+**/
+
+EFI_STATUS
+PartitionGptClearAll (VOID)
+{
+ GptCleanupGlobals ();
+ GptValid = FALSE;
+ MbrValid = FALSE;
+ return TableCreateEmptyGpt ();
+}
+
+/**
+ Create a GPT partition.
+
+ @param PartName Partition Name
+ @param StartLba Starting LBA of the partition.
+ if zero, will be calculated
+ @param SizeInMegaBytes Size of the partition in MB
+ @param Attributes Partition attributes
+ @param PartTypeGuid a Type GUID to be assigned to the partition (not a partition unique GUID)
+
+
+ @return EFI_SUCCESS Partition successfully created
+ @return EFI_INVALID_PARAMETER Either partition exists, or wrong parameters specified
+ @return other Failed to create a partition
+**/
+EFI_STATUS
+PartitionGptCreatePartition (
+ IN CONST CHAR16 *PartName,
+ IN EFI_LBA StartLba,
+ IN UINT64 SizeInMegabytes,
+ IN UINT64 Attributes,
+ IN EFI_GUID PartTypeGuid)
+{
+ EFI_GUID Guid, PartitionIdGuid;
+ EFI_STATUS Status;
+ UINT64 StartBlock;
+ UINT64 EndBlock;
+ UINT64 SizeInBytes = 0;
+ UINT32 BlockSize;
+ UINT64 DiskSizeBlocks;
+ UINT8 *p;
+ BOOLEAN OffsetSpecified = FALSE;
+ BOOLEAN AllZeros;
+ INTN AllZeroEntry;
+ INTN OldFreeEntry;
+ UINT64 AvailBlocks;
+ UINT64 BlocksToAllocate;
+ UINT64 HighSeen;
+ UINTN Slot;
+ UINT64 LowestAlignedLba;
+ UINT32 OptimalTransferBlocks;
+ UINTN i, j;
+ CHAR16 PartNameUsed[MAX_PARTITION_NAME_LENGTH + 1] = { L'\0' };
+ EFI_PARTITION_ENTRY *Entry;
+
+ LowestAlignedLba = 0;
+ OptimalTransferBlocks = 1;
+
+ AllZeroEntry = -1;
+ OldFreeEntry = -1;
+
+ BlockSize = BlockIo->Media->BlockSize;
+ OffsetSpecified = (StartLba != 0);
+ CopyMem (&PartNameUsed, PartName, sizeof(CHAR16) * StrSize (PartName));
+
+ GenerateGuid (&Guid);
+
+ // Creating a new partition
+ if (!GptValid) {
+ // Creating a GPT for the first time
+ Status = TableCreateEmptyGpt ();
+ if (!EFI_ERROR (Status)) {
+ // Fill in the structures
+ Status = PartitionGetGptTables (DiskIo, BlockIo);
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ Entry = PartitionFindPartitionByCriteria (PartName, 0, 0, SRC_BY_NAME);
+ if (Entry) {
+ Status = EFI_INVALID_PARAMETER;
+ PrintErr (L"Partition with this name already exists", Status);
+ return Status;
+ }
+ HighSeen = PrimaryHeader->FirstUsableLBA - 1;
+
+ if (StartLba) {
+ //
+ // if offset is specified, compute the start and end blocks
+ //
+ StartBlock = StartLba;
+ //
+ // StartBlock should be aligned to OptimalTransferBlocks, the least common multiple of:
+ // a). the physical block boundary, if any
+ // b). the optimal transfer length granularity, if any
+ //
+ if (StartBlock < LowestAlignedLba) {
+ StartBlock = LowestAlignedLba;
+ } else {
+ while (((StartBlock - LowestAlignedLba) % OptimalTransferBlocks) != 0) {
+ StartBlock++;
+ }
+ }
+
+ if (StartBlock < PrimaryHeader->FirstUsableLBA ||
+ StartBlock > PrimaryHeader->LastUsableLBA) {
+ //
+ // Offset specified is too large
+ //
+ Status = EFI_INVALID_PARAMETER;
+ PrintErr (L"Specified offset is too large", EFI_INVALID_PARAMETER);
+ goto Exit;
+ }
+
+ SizeInBytes = MultU64x32 (SizeInMegabytes, (1024 * 1024));
+ if (SizeInBytes < SizeInMegabytes || SizeInBytes == 0) {
+ //
+ // If size is not specified or too large,
+ // try to make the partition as big as it can be
+ //
+ BlocksToAllocate = EndBlock = SizeInBytes = 0xffffffffffffffff;
+ } else {
+ BlocksToAllocate = DivU64x32 (SizeInBytes, BlockSize);
+ EndBlock = StartBlock + BlocksToAllocate - 1;
+ if (EndBlock > PrimaryHeader->LastUsableLBA) {
+ EndBlock = PrimaryHeader->LastUsableLBA;
+ BlocksToAllocate = EndBlock - StartBlock + 1;
+ }
+ }
+ }
+
+ for (i = 0; i < PrimaryHeader->NumberOfPartitionEntries; i++) {
+ Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + i * PrimaryHeader->SizeOfPartitionEntry);
+ if (!CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {
+
+ //
+ // Type not null, so it's allocated
+ //
+ if (Entry->EndingLBA > HighSeen) {
+ HighSeen = Entry->EndingLBA;
+ }
+ if (OffsetSpecified) {
+ //
+ // make sure new partition does not overlap with existing partitions
+ //
+ if (Entry->StartingLBA <= StartBlock &&
+ StartBlock <= Entry->EndingLBA) {
+ //
+ // starting block is inside an existing partition
+ //
+ Status = EFI_INVALID_PARAMETER;
+ PrintErr (L"Starting block is inside an existing partition", Status);
+ goto Exit;
+ }
+ if ((Entry->StartingLBA <= EndBlock &&
+ EndBlock <= Entry->EndingLBA) ||
+ (StartBlock <= Entry->StartingLBA &&
+ Entry->StartingLBA <= EndBlock) ||
+ (StartBlock <= Entry->EndingLBA &&
+ Entry->EndingLBA <= EndBlock)) {
+ //
+ // new partition overlaps with an existing partition
+ // readjust new partition size to avoid overlapping
+ //
+ EndBlock = Entry->StartingLBA - 1;
+ if (EndBlock < StartBlock) {
+ Status = EFI_INVALID_PARAMETER;
+ PrintErr (L"Cannot readjust new partition size - overlapping", Status);
+ goto Exit;
+ } else {
+ BlocksToAllocate = EndBlock - StartBlock + 1;
+ }
+ }
+ }
+ } else {
+ p = (UINT8 *)(Entry);
+ AllZeros = TRUE;
+ for (j = 0; j < sizeof(EFI_PARTITION_ENTRY); j++) {
+ if (p[j] != 0) {
+ AllZeros = FALSE;
+ }
+ }
+ if (AllZeros) {
+ if (AllZeroEntry == -1) {
+ AllZeroEntry = i;
+ }
+ } else if (OldFreeEntry == -1) {
+ OldFreeEntry = i;
+ }
+ }
+ }
+
+ //
+ // AllZeroEntry - if not -1, is pointer to a never before used entry (free)
+ // OldFreeEntry - if not -1, is pointer to some pre-used free entry
+ //
+ if ((AllZeroEntry == -1) && (OldFreeEntry == -1)) {
+ //
+ // TABLE IS FULL!!
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ PrintErr (L"Table is full", Status);
+ goto Exit;
+ }
+
+ if (OffsetSpecified) {
+ //
+ // the user haven't specified the new partition size and we haven't
+ // run into any partition that will limit the size of this new partition.
+ // So, use the max it can
+ //
+ if (BlocksToAllocate == -1) {
+ EndBlock = PrimaryHeader->LastUsableLBA;
+ BlocksToAllocate = EndBlock - StartBlock + 1;
+ }
+ } else {
+ //
+ // Because HighSeen is the last LBA of the used blocks, let HighSeen align to the least common multiple of:
+ // a). the physical block boundary, if any
+ // b). the optimal transfer length granularity, if any
+ //
+ if (HighSeen + 1 < LowestAlignedLba) {
+ HighSeen = LowestAlignedLba - 1;
+ } else {
+ while (((HighSeen + 1 - LowestAlignedLba) % OptimalTransferBlocks) != 0) {
+ HighSeen++;
+ }
+ }
+
+ if (PrimaryHeader->LastUsableLBA <= HighSeen) {
+ Status = EFI_OUT_OF_RESOURCES;
+ PrintErr (L"Disk has no free blocks (FULL) cannot create", Status);
+ goto Exit;
+ }
+ //
+ // [HighSeen+1 ... LastUsableLBA] is available...
+ // avail = (LastUsableLBA - (HighSeen+1)) + 1 => LastUsabbleLBA - HighSeen
+ //
+ AvailBlocks = PrimaryHeader->LastUsableLBA - HighSeen;
+
+ SizeInBytes = MultU64x32 (SizeInMegabytes, (1024 * 1024));
+ if (SizeInBytes < SizeInMegabytes) {
+ //
+ // overflow, force a very big answer
+ //
+ SizeInBytes = 0xffffffffffffffff;
+ }
+
+ if ((SizeInBytes == 0) ||
+ (SizeInBytes > (MultU64x32 (AvailBlocks, BlockSize)))) {
+ //
+ // User asked for zero, or for more than we've got,
+ // so give them all that is left
+ //
+ BlocksToAllocate = AvailBlocks;
+
+ } else {
+
+ //
+ // We would have to have a BlockSize > 1mb for Remainder to
+ // not be 0. Since we cannot actually test this case, we
+ // ingore it...
+ //
+ BlocksToAllocate = DivU64x32 (SizeInBytes, BlockSize);
+
+ }
+ }
+
+ //
+ // We have a name
+ // We have a type guid
+ // We have a size in blocks
+ // We have an attribute mask
+ //
+
+ if (BlocksToAllocate < ((1024 * 1024) / BlockSize)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ PrintErr (L"Partition is too small to be created", Status);
+ goto Exit;
+ }
+
+ if (GPT_DEBUG_LEVEL) {
+ Print (L"Requested SizeInMegaBytes = %ld\n", SizeInMegabytes);
+ Print (L"Resulting size in Blocks = %ld\n", BlocksToAllocate);
+ Print (L"Results size in Bytes = %ld\n", MultU64x32 (BlocksToAllocate, BlockSize));
+ }
+
+ if (AllZeroEntry != -1) {
+ Slot = AllZeroEntry;
+ } else {
+ Slot = OldFreeEntry;
+ }
+
+ GenerateGuid (&PartitionIdGuid);
+ Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Slot * PrimaryHeader->SizeOfPartitionEntry);
+
+ CopyMem (&Entry->PartitionTypeGUID, &PartTypeGuid, sizeof(EFI_GUID));
+ CopyMem (&Entry->UniquePartitionGUID, &PartitionIdGuid, sizeof(EFI_GUID));
+ if (OffsetSpecified) {
+ PartEntry[Slot].StartingLBA = StartBlock;
+ PartEntry[Slot].EndingLBA = EndBlock;
+ } else {
+ PartEntry[Slot].StartingLBA = HighSeen + 1;
+ PartEntry[Slot].EndingLBA = HighSeen + BlocksToAllocate;
+ }
+
+ if (!(((Entry->EndingLBA - Entry->StartingLBA) + 1) == BlocksToAllocate)) {
+ PrintErr (L"Wrong Size for new partiton", EFI_INVALID_PARAMETER);
+ goto Exit;
+ }
+
+ if ((Entry->StartingLBA < PrimaryHeader->FirstUsableLBA) ||
+ (Entry->EndingLBA > PrimaryHeader->LastUsableLBA)) {
+ PrintErr (L"New Partition out of bounds", EFI_INVALID_PARAMETER);
+ goto Exit;
+ }
+
+ Entry->Attributes = Attributes;
+ CopyMem (&(Entry->PartitionName[0]), PartName, MAX_PARTITION_NAME_LENGTH * sizeof(CHAR16));
+
+ DiskSizeBlocks = BlockIo->Media->LastBlock + 1;
+ if (DiskSizeBlocks > 0xffffffff) {
+ DiskSizeBlocks = 0xffffffff;
+ }
+
+ Status = WriteGPT ();
+
+ if (EFI_ERROR (Status)) {
+ PrintErr (L"Attempt to Write out partition table failed", Status);
+ }
+
+ Exit:
+ return Status;
+}
+
+/**
+ Modifiy a partition based on parameters.
+
+ @param Entry Pointer to an existing partition
+ @param Params Parameters to be modified
+ @param Flags Which parameter is to be modified
+
+ @return EFI_SUCCESS Successfully modified the partition
+ @return other Failed to modify a partition
+
+**/
+
+EFI_STATUS
+PartitionGptModifyPartition (
+ IN EFI_PARTITION_ENTRY *Entry,
+ IN MOD_PARAMS *Params,
+ IN MOD_FLAGS Flags
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (Entry);
+
+ Status = EFI_INVALID_PARAMETER;
+
+ switch (Flags) {
+ case MOD_DELETE:
+ ZeroMem (Entry, sizeof(EFI_PARTITION_ENTRY));
+ break;
+ case MOD_ATTR:
+ Entry->Attributes = Params->Attributes;
+ break;
+ case MOD_TYPE:
+ Entry->PartitionTypeGUID = Params->PartTypeGuid;
+ break;
+ case MOD_RENAME:
+ StrCpy (Entry->PartitionName, Params->NewName);
+ break;
+ default:
+ PrintErr (L"Unknown modification flag(s)", Status);
+ return Status;
+ }
+
+ return WriteGPT ();
+}
+
+EFI_KNOWN_PARTITION_TYPE *PartitionGetKnownType (
+ IN UINTN Index,
+ IN OUT OPTIONAL UINTN *NumEntries
+ )
+{
+ if (NumEntries) {
+ *NumEntries = ARRAY_SIZE(PartitionTypes);
+ }
+ if (Index > ARRAY_SIZE(PartitionTypes)) {
+ return NULL;
+ }
+
+ return &PartitionTypes[Index];
+}
+
diff --git a/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
new file mode 100644
index 000000000000..9efec5cefe94
--- /dev/null
+++ b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
@@ -0,0 +1,186 @@
+/*
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016 Broadcom. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Broadcom nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* GPT partitioner header file */
+
+#ifndef _GPTWORKER_H_
+#define _GPTWORKER_H_
+
+#include <Uefi.h>
+#include <ShellBase.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/ShellCommandLib.h>
+#include <Library/ShellLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiShellLib/UefiShellLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/PrintLib.h>
+#include <Library/ShellCEntryLib.h>
+#include <Library/HiiLib.h>
+#include <Library/FileHandleLib.h>
+#include <Protocol/DevicePath.h>
+#include <Library/DevicePathLib.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/DiskIo.h>
+#include <IndustryStandard/Mbr.h>
+
+typedef enum {
+ MOD_NAME = BIT0,
+ MOD_ATTR = BIT1,
+ MOD_TYPE = BIT2,
+ MOD_DELETE = BIT3,
+ MOD_RENAME = BIT4
+} MOD_FLAGS;
+
+typedef struct {
+ UINTN Attributes;
+ EFI_GUID PartTypeGuid;
+ CONST CHAR16 *PartName;
+ CONST CHAR16 *NewName;
+} MOD_PARAMS;
+
+typedef enum {
+ SRC_BY_NAME = BIT0,
+ SRC_BY_LBA = BIT1,
+ SRC_BY_NUM = BIT2,
+ SRC_ANY = BIT3
+} SEARCH_TYPE;
+
+#define MAX_PARTITION_NAME_LENGTH 36
+#define ENTRY_DEFAULT 128
+#define GPT_REVISION_1_0 0x00010000
+
+#define ARRAY_SIZE(x) \
+ (sizeof(x) / sizeof((x)[0]))
+
+//
+// Extract INT32 from char array
+//
+#define UNPACK_INT32(a) (INT32)( (((UINT8 *) a)[0] << 0) | \
+ (((UINT8 *) a)[1] << 8) | \
+ (((UINT8 *) a)[2] << 16) | \
+ (((UINT8 *) a)[3] << 24) )
+
+//
+// Extract UINT32 from char array
+//
+#define UNPACK_UINT32(a) (UINT32)( (((UINT8 *) a)[0] << 0) | \
+ (((UINT8 *) a)[1] << 8) | \
+ (((UINT8 *) a)[2] << 16) | \
+ (((UINT8 *) a)[3] << 24) )
+
+
+//
+// GPT Partition Entry Status
+//
+typedef struct {
+ BOOLEAN OutOfRange;
+ BOOLEAN Overlap;
+ BOOLEAN OsSpecific;
+} EFI_PARTITION_ENTRY_STATUS;
+
+typedef struct {
+ CONST EFI_GUID TypeGuid;
+ CONST CHAR16 *TypeName;
+
+} EFI_KNOWN_PARTITION_TYPE;
+
+EFI_KNOWN_PARTITION_TYPE *PartitionGetKnownType (
+ IN UINTN Index,
+ IN OUT OPTIONAL UINTN *NumEntries
+ );
+
+EFI_STATUS
+PartitionGetGptTables (
+ IN EFI_DISK_IO_PROTOCOL *DiskIoProt,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIoProt
+ );
+
+UINTN
+PartitionListGptEntries (
+ VOID
+ );
+
+VOID
+PartitionPrintGptPartInfo (
+ IN EFI_PARTITION_ENTRY *Entry
+ );
+
+EFI_STATUS
+GetPartitionTypeStr (
+ EFI_GUID Guid,
+ CHAR16 *PartTypeStr,
+ BOOLEAN NoGuidStr
+ );
+
+
+EFI_STATUS
+PartitionGptClearAll (
+ VOID
+ );
+
+EFI_STATUS
+PartitionGptCreatePartition (
+ CONST CHAR16 *PartName,
+ EFI_LBA StartLba,
+ EFI_LBA PartitionSize,
+ UINT64 Attributes,
+ EFI_GUID PartTypeGuid);
+
+EFI_STATUS
+PartitionGptModifyPartition (
+ EFI_PARTITION_ENTRY *Entry,
+ MOD_PARAMS *Params,
+ MOD_FLAGS Flags
+ );
+
+VOID
+GptCleanupGlobals (
+ VOID
+ );
+
+EFI_PARTITION_ENTRY *
+PartitionFindPartitionByCriteria (
+ CONST CHAR16 *Name,
+ EFI_LBA StartLba,
+ EFI_LBA EndingLba,
+ SEARCH_TYPE SearchType);
+
+VOID
+PrintErr (IN CONST CHAR16 *Message, IN EFI_STATUS Status);
+
+#endif //_GPTWORKER_H_
diff --git a/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
new file mode 100644
index 000000000000..a9d74a780911
--- /dev/null
+++ b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
@@ -0,0 +1,1135 @@
+/*******************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+/* Portions Copyright (C) 2016 Broadcom */
+
+#include "FatFormat.h"
+#include <Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.h>
+#include <Library/TimerLib.h>
+
+CONST CHAR16 gShellGptFileName[] = L"ShellCommand";
+STATIC CONST CHAR16 gAppName[] = L"gpt";
+EFI_HANDLE gShellGptHiiHandle = NULL;
+
+STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
+ // Partition-related operations
+ { L"clear", TypeFlag }, // Clears all partitions
+ { L"create", TypeFlag }, // Creates a partition
+ { L"delete", TypeFlag }, // Deletes a partition
+ { L"list", TypeFlag }, // Lists all partitions
+ { L"rename", TypeFlag }, // Renames a partition
+ { L"setattr", TypeFlag }, // Set attributes for a partition in partition table
+ { L"settype", TypeFlag },
+ { L"sync", TypeFlag }, // Synchronizes either master or alternative partition table
+ { L"typesinfo", TypeFlag }, // Verifies correctness of master and alternative partition tables
+ // BlockIo-related operations
+ { L"read", TypeFlag }, // Reads n bytes into memory address from a partition starting from a certain lba
+ { L"readfile", TypeFlag }, // Same as above, but instead of store it in memory saves into a file system
+ { L"write", TypeFlag }, // Writes n bytes from memory into a partition starting from a certain lba
+ { L"writefile", TypeFlag }, // Same as above, but instead of getting data from memory reads a file
+ { L"info", TypeFlag }, // Get information on a certain partition (startLba, lastLba, attributes)
+ { L"fatformat", TypeFlag }, // FAT format of a partition
+ { L"-type", TypeValue },
+ { L"-yes", TypeFlag },
+ { L"-verbose", TypeFlag },
+ { NULL, TypeMax }
+};
+
+typedef enum {
+ // Not requires presence
+ CLEAR = BIT0,
+ CREATE = BIT1,
+ LIST = BIT2,
+ SYNC = BIT3,
+ TYPES_INFO = BIT4,
+
+ // Requires presence
+ DELETE = BIT5,
+ INFO = BIT6,
+ READ = BIT7,
+ READ_FILE = BIT8,
+ RENAME = BIT9,
+ SETATTR = BIT10,
+ SETTYPE = BIT11,
+ WRITE = BIT12,
+ WRITE_FILE = BIT13,
+ FAT_FORMAT = BIT14,
+} Flags;
+
+/**
+ Return the file name of the help text file if not using HII.
+
+ @return The string pointer to the file name.
+**/
+CONST CHAR16 *
+EFIAPI
+ShellCommandGetManFileNameGpt (
+ VOID
+ )
+{
+
+ return gShellGptFileName;
+}
+
+STATIC
+EFI_STATUS
+OpenAndPrepareFile (
+ IN CHAR16 *FilePath,
+ OUT SHELL_FILE_HANDLE *FileHandle,
+ IN BOOLEAN WriteNeeded
+ )
+{
+ EFI_STATUS Status;
+ UINT64 OpenMode;
+
+ OpenMode = EFI_FILE_MODE_READ;
+
+ if (WriteNeeded) {
+ OpenMode |= EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE;
+ }
+
+ Status = ShellOpenFileByName (FilePath, FileHandle, OpenMode, 0);
+ if (EFI_ERROR (Status)) {
+ ShellPrintHiiEx (-1, -1,
+ NULL, STRING_TOKEN (STR_GPT_ERROR),
+ gShellGptHiiHandle,
+ gAppName,
+ Status,
+ L"Cannot open file"
+ );
+ return Status;
+ }
+
+ Status = FileHandleSetPosition (*FileHandle, 0);
+
+ if (EFI_ERROR (Status)) {
+ ShellPrintHiiEx (-1, -1,
+ NULL, STRING_TOKEN (STR_GPT_ERROR),
+ gShellGptHiiHandle,
+ gAppName,
+ Status,
+ "Cannot set file position to the first byte"
+ );
+
+ ShellCloseFile (FileHandle);
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+VOID
+PrintErr (
+ IN CONST CHAR16 *Message,
+ IN EFI_STATUS Status
+ )
+{
+ ShellPrintHiiEx (-1, -1,
+ NULL, STRING_TOKEN (STR_GPT_ERROR),
+ gShellGptHiiHandle,
+ gAppName,
+ Status,
+ Message
+ );
+}
+
+STATIC
+BOOLEAN
+IsPartitionableDevicePath (
+ IN EFI_DEVICE_PATH *DevicePath
+ )
+{
+ UINTN PathSize;
+ EFI_DEVICE_PATH *PathInstance;
+ BOOLEAN Partitionable;
+
+ Partitionable = TRUE;
+ while (DevicePath != NULL) {
+ PathInstance = GetNextDevicePathInstance (&DevicePath, &PathSize);
+
+ while (!IsDevicePathEnd (PathInstance)) {
+ if ((DevicePathType (PathInstance) == MEDIA_DEVICE_PATH)) {
+ Partitionable = FALSE;
+ }
+
+ PathInstance = NextDevicePathNode (PathInstance);
+ }
+ }
+ return Partitionable;
+}
+
+STATIC
+EFI_STATUS
+GptPromptYesNo (
+ IN CONST EFI_STRING_ID HiiFormatStringId
+ )
+{
+ EFI_STATUS Status;
+ VOID *Response;
+
+ Status = ShellPromptForResponseHii (ShellPromptResponseTypeYesNo, HiiFormatStringId, gShellGptHiiHandle, &Response);
+ if ((EFI_ERROR (Status)) || (*(SHELL_PROMPT_RESPONSE *)Response) != ShellPromptResponseYes) {
+ return EFI_ABORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+VOID FormatSize(
+ UINT64 Size, CHAR16 *Buffer)
+{
+#define MAX_SIZE_BUF_SIZE 32
+ UINT64 Base, Frac;
+ CHAR16 Metric;
+
+ Metric = L'B';
+ Frac = 0;
+ if (Size < SIZE_1KB) {
+ Base = Size;
+ } else if (Size < SIZE_1MB) {
+ Base = Size / SIZE_1KB;
+ Frac = ((Size % SIZE_1KB) * 10) >> 10;
+ Metric = L'K';
+ } else if (Size < SIZE_1GB) {
+ Base = Size / SIZE_1MB;
+ Frac = ((Size % SIZE_1MB) * 10) >> 20;
+ Metric = L'M';
+ } else if (Size < SIZE_1TB) {
+ Base = Size / SIZE_1GB;
+ Frac = ((Size % SIZE_1GB) * 10) >> 30;
+ Metric = L'G';
+ } else {
+ Base = Size / SIZE_1TB;
+ Frac = ((Size % SIZE_1TB) * 10) >> 40;
+ Metric = L'T';
+ }
+ if (Frac) {
+ UnicodeSPrint (Buffer, MAX_SIZE_BUF_SIZE, L"%d.%d%c", Base, Frac, Metric);
+ } else {
+ UnicodeSPrint (Buffer, MAX_SIZE_BUF_SIZE, L"%d%c", Base, Metric);
+ }
+}
+
+STATIC
+EFI_STATUS
+FindAndPrintPartitionableDevices (VOID)
+{
+ UINTN Index;
+ EFI_HANDLE *HandlePointer;
+ UINTN HandleCount;
+ UINTN DevCount;
+ EFI_STATUS Status;
+ BOOLEAN FirstTime;
+
+ Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &HandleCount, &HandlePointer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DevCount = 0;
+ FirstTime = TRUE;
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ EFI_DEVICE_PATH *DevicePath;
+ CONST CHAR16 *MapPath;
+ CHAR16 *Match;
+ EFI_BLOCK_IO *BlkIo;
+ EFI_DISK_IO *DiskIo;
+ CHAR16 *BufferForSize;
+
+ Status = gBS->HandleProtocol (HandlePointer[Index], &gEfiBlockIoProtocolGuid, (VOID **)&BlkIo);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ DevicePath = DevicePathFromHandle (HandlePointer[Index]);
+ if (!IsPartitionableDevicePath (DevicePath)) {
+ continue;
+ }
+ MapPath = gEfiShellProtocol->GetMapFromDevicePath (&DevicePath);
+ if (MapPath == NULL) {
+ continue;
+ }
+
+ Status = gBS->HandleProtocol (HandlePointer[Index], &gEfiDiskIoProtocolGuid, (VOID **)&DiskIo);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Match = StrStr (MapPath, L";BLK");
+ if (Match) {
+ MapPath = Match;
+ MapPath++;
+ }
+
+ if (FirstTime) {
+ BufferForSize = AllocateZeroPool (MAX_SIZE_BUF_SIZE * sizeof (CHAR16));
+ ASSERT (BufferForSize);
+ Print (L" Device\t Size Comments\n");
+ Print (L" ------ ------- ------------------------------------------------------------\n");
+ FirstTime = FALSE;
+ }
+ GptCleanupGlobals ();
+ FormatSize (MultU64x32 (BlkIo->Media->LastBlock + 1, BlkIo->Media->BlockSize), BufferForSize);
+ ShellPrintHiiEx (-1, -1,
+ NULL, STRING_TOKEN (STR_GPT_LIST_DEVS),
+ gShellGptHiiHandle,
+ MapPath,
+ BufferForSize);
+ if (BlkIo->Media->ReadOnly) {
+ Print (L"Read-Only! ");
+ }
+ if (!BlkIo->Media->MediaPresent) {
+ Print (L"No Media! ");
+ }
+ if (!EFI_ERROR (PartitionGetGptTables (DiskIo, BlkIo))) {
+ Print (L"Valid GPT. ");
+ }
+ if (BlkIo->Media->RemovableMedia) {
+ Print (L"Removable device.");
+ }
+ Print (L"\n");
+ DevCount++;
+ }
+ Print (L"\r\n");
+ if (DevCount) {
+ Print (L"%d potentially partitionable device(s) found\n", DevCount);
+ } else {
+ Print (L"No potentially partitionable device(s) found\n");
+ }
+
+ GptCleanupGlobals ();
+ return EFI_SUCCESS;
+}
+
+SHELL_STATUS
+EFIAPI
+ShellCommandRunGpt (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *CheckPackage;
+ EFI_PHYSICAL_ADDRESS Address = 0, Offset = 0;
+ UINT64 PartAttributes = 0;
+ EFI_GUID PartTypeGuid = { 0 };
+ SHELL_FILE_HANDLE FileHandle = NULL;
+ UINT64 ByteCount, FileSize;
+ UINTN I;
+ UINT8 *Buffer = NULL, *FileBuffer = NULL;
+
+ CHAR16 * ProblemParam,*FilePath;
+ CONST CHAR16 *AddressStr = NULL, *OffsetStr = NULL;
+ CONST CHAR16 *PartName = NULL, *NewPartName = NULL, *AttrStr = NULL,
+ *GuidStr = NULL, *VolumeName = NULL;
+ CONST CHAR16 *LengthStr = NULL, *FileStr = NULL;
+ BOOLEAN AddrFlag = FALSE, LengthFlag = TRUE, FileFlag = FALSE, GuidFlag = FALSE, OffsetFlag = TRUE;
+ BOOLEAN PartNameFlag = TRUE, NewPartNameFlag = FALSE, AttrFlag = FALSE;
+ UINTN Flag = 0, CheckFlag = 0;
+ CONST CHAR16 *BlockName;
+ EFI_DEVICE_PATH_PROTOCOL *DevPath;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ EFI_HANDLE BlockIoHandle;
+ MOD_PARAMS ModParams;
+ EFI_PARTITION_ENTRY *Entry;
+ UINTN NumKnownPartTypesEntries;
+ BOOLEAN TableNotEmpty, NoPrompt = FALSE, Quiet = TRUE;
+ UINT64 TimeStampB, TimeStampE, SpeedKB, Freq;
+
+ // Parse Shell command line
+ Status = ShellInitialize ();
+ if (EFI_ERROR (Status)) {
+ PrintErr (L"Cannot initialize Shell", Status);
+ ASSERT_EFI_ERROR (Status);
+ return SHELL_ABORTED;
+ }
+
+ Status = ShellCommandLineParse (ParamList, &CheckPackage, &ProblemParam, TRUE);
+ if (EFI_ERROR (Status)) {
+ PrintErr (L"Error while parsing command line", Status);
+ return SHELL_ABORTED;
+ }
+
+ TimeStampB = 0;
+ TimeStampE = 0;
+
+ NoPrompt = ShellCommandLineGetFlag (CheckPackage, L"-yes");
+ Quiet = !ShellCommandLineGetFlag (CheckPackage, L"-verbose");
+
+ Freq = GetPerformanceCounterProperties (NULL, NULL);
+
+ // Check flags provided by user
+ Flag |= (ShellCommandLineGetFlag (CheckPackage, L"clear") << 0);
+ Flag |= (ShellCommandLineGetFlag (CheckPackage, L"create") << 1);
+ Flag |= (ShellCommandLineGetFlag (CheckPackage, L"list") << 2);
+ Flag |= (ShellCommandLineGetFlag (CheckPackage, L"sync") << 3);
+ Flag |= (ShellCommandLineGetFlag (CheckPackage, L"typesinfo") << 4);
+ Flag |= (ShellCommandLineGetFlag (CheckPackage, L"delete") << 5);
+ Flag |= (ShellCommandLineGetFlag (CheckPackage, L"info") << 6);
+ Flag |= (ShellCommandLineGetFlag (CheckPackage, L"read") << 7);
+ Flag |= (ShellCommandLineGetFlag (CheckPackage, L"readfile") << 8);
+ Flag |= (ShellCommandLineGetFlag (CheckPackage, L"rename") << 9);
+ Flag |= (ShellCommandLineGetFlag (CheckPackage, L"setattr") << 10);
+ Flag |= (ShellCommandLineGetFlag (CheckPackage, L"settype") << 11);
+ Flag |= (ShellCommandLineGetFlag (CheckPackage, L"write") << 12);
+ Flag |= (ShellCommandLineGetFlag (CheckPackage, L"writefile") << 13);
+ Flag |= (ShellCommandLineGetFlag (CheckPackage, L"fatformat") << 14);
+
+ PartitionGetKnownType ((UINTN)(-1), &NumKnownPartTypesEntries);
+
+ if (Flag & TYPES_INFO) {
+ UINTN Index;
+
+ Print (L" No\t%-36s\tGUID\r\n", L"Type name");
+ Print (L" ---- ---------------------------------- ------------------------------------\n");
+ for (Index = 0; Index < NumKnownPartTypesEntries; Index++) {
+ EFI_KNOWN_PARTITION_TYPE *PartType;
+
+ PartType = PartitionGetKnownType (Index, NULL);
+ if (PartType == NULL) {
+ break;
+ }
+ Print (L" %3d\t%-36s\t%g\n", Index, PartType->TypeName, &PartType->TypeGuid);
+ }
+ if (Flag == TYPES_INFO) {
+ return SHELL_SUCCESS;
+ }
+ }
+ // Start parsing the command.
+ // Generally command is:
+ // block_name:bootpart_no addr or filename offset
+
+ BlockName = ShellCommandLineGetRawValue (CheckPackage, 1);
+ if (BlockName == NULL) {
+ if (Flag & LIST) {
+ Status = FindAndPrintPartitionableDevices ();
+ if (EFI_ERROR (Status)) {
+ PrintErr (L"Error getting list of partitionable devices", Status);
+ Status = SHELL_ABORTED;
+ }
+ return Status;
+ }
+ PrintErr (L"Missing block device name", EFI_INVALID_PARAMETER);
+ return SHELL_INVALID_PARAMETER;
+ }
+
+ // Find device handle by mapped name
+ if (gEfiShellProtocol->GetDevicePathFromMap (BlockName) == NULL) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellGptHiiHandle, gAppName, BlockName);
+ Status = SHELL_INVALID_PARAMETER;
+ } else {
+ DevPath = (EFI_DEVICE_PATH_PROTOCOL *)gEfiShellProtocol->GetDevicePathFromMap (BlockName);
+ if (gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &DevPath, NULL) == EFI_NOT_FOUND) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_MAP_PROTOCOL), gShellGptHiiHandle, gAppName, BlockName, L"BlockIo");
+ Status = SHELL_INVALID_PARAMETER;
+ }
+ }
+
+ if (Status) {
+ return SHELL_INVALID_PARAMETER;
+ }
+
+ BlockIoHandle = 0;
+
+ Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, (EFI_DEVICE_PATH_PROTOCOL **)&DevPath, &BlockIoHandle);
+ if (EFI_ERROR (Status)) {
+ goto CleanUp;
+ }
+
+ Status = gBS->OpenProtocol (BlockIoHandle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo, gImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (EFI_ERROR (Status)) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_MAP_PROTOCOL), gShellGptHiiHandle, gAppName, BlockName, L"BlockIo");
+ goto CleanUp;
+ }
+
+ Status = gBS->HandleProtocol (
+ BlockIoHandle,
+ &gEfiDiskIoProtocolGuid,
+ (VOID **)&DiskIo
+ );
+ if (EFI_ERROR (Status)) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_MAP_PROTOCOL), gShellGptHiiHandle, gAppName, BlockName, L"DiskIo");
+ goto CleanUp;
+ }
+
+ CheckFlag = Flag;
+ for (I = 0; CheckFlag; CheckFlag >>= 1) {
+ I += CheckFlag & 1;
+ if (I > 1) {
+ PrintErr (L"Too many flags", EFI_INVALID_PARAMETER);
+ Status = SHELL_INVALID_PARAMETER;
+ goto CleanUp;
+ }
+ }
+
+ if (Flag & SYNC) {
+ // Let the Partition table driver know that
+ // we want to reread the tables
+ Status = gBS->ReinstallProtocolInterface (
+ BlockIoHandle,
+ &gEfiBlockIoProtocolGuid,
+ BlockIo,
+ BlockIo
+ );
+ Status = SHELL_SUCCESS;
+ goto CleanUp;
+ }
+
+ if (!IsPartitionableDevicePath (DevicePathFromHandle (BlockIoHandle))) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellGptHiiHandle, gAppName, BlockName);
+ Print (L"%s is not a raw block device\n", BlockName);
+ Status = SHELL_INVALID_PARAMETER;
+ goto CleanUp;
+ }
+
+ if (!BlockIo->Media->MediaPresent) {
+ PrintErr (L"Media is not present!\n", EFI_NO_MEDIA);
+ Status = EFI_NO_MEDIA;
+ goto CleanUp;
+ }
+
+ // Preload GPT tables with validation
+ Status = PartitionGetGptTables (DiskIo, BlockIo);
+ if (EFI_ERROR (Status)) {
+ BOOLEAN CanContinue;
+
+ CanContinue = (Flag & CREATE) || (Flag & CLEAR) || (Flag & FAT_FORMAT);
+ if (Status != EFI_NOT_FOUND) {
+ PrintErr (L"Unexpected error getting GPT tables", Status);
+ goto CleanUp;
+ } else {
+ if (!CanContinue) {
+ PrintErr (L"No GPT table found. Create first", Status);
+ goto CleanUp;
+ }
+ }
+ }
+
+ // Do we have any partitions already?
+ TableNotEmpty = (PartitionFindPartitionByCriteria (NULL, 0, 0, SRC_ANY) != NULL);
+
+ Status = SHELL_INVALID_PARAMETER;
+
+ if ((Flag < LIST) ||
+ (Flag & DELETE) ||
+ (Flag > READ_FILE)
+ ) {
+ if (BlockIo->Media->ReadOnly) {
+ Status = EFI_INVALID_PARAMETER;
+ PrintErr (L"Cannot write to a read-only device", Status);
+ goto CleanUp;
+ }
+ }
+
+ if (BlockIo->Media->RemovableMedia) {
+ Print (L"%s is a removable device. Just a note\n", BlockName);
+ }
+
+ switch (Flag) {
+ case INFO:
+ PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
+ OffsetFlag = FALSE;
+ LengthFlag = FALSE;
+ break;
+ case LIST:
+ {
+ UINTN NumEntries;
+
+ NumEntries = PartitionListGptEntries ();
+ if (NumEntries == 0) {
+ Print (L"gpt: GPT is valid on %s, but no partition(s) defined yet. Use create\n", BlockName);
+ }
+ Status = SHELL_SUCCESS;
+ goto CleanUp;
+ break;
+ }
+ case CLEAR:
+ if (TableNotEmpty) {
+ // Tell the user what he/she is doing...
+ ShellPrintHiiEx (-1, -1,
+ NULL, STRING_TOKEN (STR_GPT_NOT_EMPTY),
+ gShellGptHiiHandle,
+ BlockName
+ );
+ }
+
+ // Even if GPT tables do not exist, there might be something.
+ // Warn the user and double sure it is the intention,
+ // to prevent a user from bricking a device (JTAG would be needed to recover)
+ // by overwriting an ATF boot device. However with NoPrompt on, the user is
+ // responsible for operation because there is no confirmation (assuming yes on all queries).
+ if ((NoPrompt) || (!GptPromptYesNo (STRING_TOKEN (STR_GPT_CLEAR_SURE)) &&
+ (!GptPromptYesNo (STRING_TOKEN (STR_GPT_ABSOLUTELY_SURE))))
+ ) {
+ PartitionGptClearAll ();
+ }
+ Status = SHELL_SUCCESS;
+ goto CleanUp;
+ break;
+ case CREATE:
+ PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
+ OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 3);
+ LengthStr = ShellCommandLineGetRawValue (CheckPackage, 4);
+ AttrStr = ShellCommandLineGetRawValue (CheckPackage, 5);
+ GuidStr = ShellCommandLineGetValue (CheckPackage, L"-type");
+ GuidFlag = TRUE;
+ break;
+ case DELETE:
+ PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
+ LengthFlag = FALSE;
+ OffsetFlag = FALSE;
+ break;
+ case RENAME:
+ PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
+ NewPartName = ShellCommandLineGetRawValue (CheckPackage, 3);
+ NewPartNameFlag = TRUE;
+ LengthFlag = FALSE;
+ OffsetFlag = FALSE;
+ break;
+ case SETATTR:
+ PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
+ AttrStr = ShellCommandLineGetRawValue (CheckPackage, 3);
+ AttrFlag = TRUE;
+ LengthFlag = FALSE;
+ OffsetFlag = FALSE;
+ break;
+ case SETTYPE:
+ PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
+ GuidStr = ShellCommandLineGetValue (CheckPackage, L"-type");
+ GuidFlag = TRUE;
+ LengthFlag = FALSE;
+ OffsetFlag = FALSE;
+ break;
+ case FAT_FORMAT:
+ PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
+ VolumeName = ShellCommandLineGetRawValue (CheckPackage, 3);
+ LengthFlag = FALSE;
+ OffsetFlag = FALSE;
+ PartNameFlag = (PartName != NULL);
+ if (!PartNameFlag && TableNotEmpty) {
+ // Tell the user what he/she is doing...
+ ShellPrintHiiEx (-1, -1,
+ NULL, STRING_TOKEN (STR_GPT_NOT_EMPTY),
+ gShellGptHiiHandle,
+ BlockName
+ );
+ }
+ break;
+ // Fall through
+ case READ:
+ case WRITE:
+ AddressStr = ShellCommandLineGetRawValue (CheckPackage, 2);
+ PartName = ShellCommandLineGetRawValue (CheckPackage, 3);
+ OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 4);
+ LengthStr = ShellCommandLineGetRawValue (CheckPackage, 5);
+ AddrFlag = TRUE;
+ break;
+ case READ_FILE:
+ FileStr = ShellCommandLineGetRawValue (CheckPackage, 2);
+ PartName = ShellCommandLineGetRawValue (CheckPackage, 3);
+ OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 4);
+ LengthStr = ShellCommandLineGetRawValue (CheckPackage, 5);
+ FileFlag = TRUE;
+ break;
+ case WRITE_FILE:
+ FileStr = ShellCommandLineGetRawValue (CheckPackage, 2);
+ PartName = ShellCommandLineGetRawValue (CheckPackage, 3);
+ OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 4);
+ LengthFlag = FALSE;
+ FileFlag = TRUE;
+ break;
+ default:
+ Print (L"%s: Unsupported command. Try \"help %s\"", gAppName);
+ Status = SHELL_INVALID_PARAMETER;
+ goto CleanUp;
+ }
+
+ // Read address parameter
+ if ((AddressStr == NULL) & AddrFlag) {
+ PrintErr (L"No address parameter", EFI_INVALID_PARAMETER);
+ goto CleanUp;
+ } else if (AddrFlag) {
+ Address = ShellHexStrToUintn (AddressStr);
+ if (Address == (UINTN)(-1)) {
+ PrintErr (L"Wrong address parameter", EFI_INVALID_PARAMETER);
+ goto CleanUp;
+ }
+ }
+
+ if ((PartName == NULL) & PartNameFlag) {
+ PrintErr (L"Missing partition name", EFI_INVALID_PARAMETER);
+ goto CleanUp;
+ } else if (PartNameFlag) {
+ if (StrSize (PartName) > MAX_PARTITION_NAME_LENGTH) {
+ PrintErr (L"Partition name is too long (max 36 chars)", EFI_INVALID_PARAMETER);
+ goto CleanUp;
+ }
+ }
+
+ // Read offset parameter
+ if ((OffsetStr == NULL) & OffsetFlag) {
+ PrintErr (L"No offset Parameter", EFI_INVALID_PARAMETER);
+ goto CleanUp;
+ } else if (OffsetFlag) {
+ Offset = ShellHexStrToUintn (OffsetStr);
+ if (Offset < 0) {
+ Print (L"%s: Wrong offset parameter: %s\n", gAppName, OffsetStr);
+ goto CleanUp;
+ }
+ }
+
+ // Read length parameter
+ if ((LengthStr == NULL) & LengthFlag) {
+ PrintErr (L"No length parameter", EFI_INVALID_PARAMETER);
+ goto CleanUp;
+ } else if (LengthFlag) {
+ ByteCount = (UINT64)ShellStrToUintn (LengthStr);
+ if (ByteCount < 0) {
+ Print (L"%s: Wrong length parameter %s!\n", gAppName, LengthStr);
+ goto CleanUp;
+ }
+ }
+
+ if ((NewPartName == NULL) & NewPartNameFlag) {
+ PrintErr (L"Missing name to be assigned to partition", EFI_INVALID_PARAMETER);
+ goto CleanUp;
+ } else if (NewPartNameFlag) {
+ if (StrSize (NewPartName) > MAX_PARTITION_NAME_LENGTH) {
+ PrintErr (L"Partition name is too long (max 36 chars)", EFI_INVALID_PARAMETER);
+ goto CleanUp;
+ }
+ }
+
+ if ((AttrStr == NULL) & AttrFlag) {
+ PrintErr (L"Missing attributes parameter", EFI_INVALID_PARAMETER);
+ goto CleanUp;
+ } else if (AttrStr) {
+ PartAttributes = (UINT64)ShellStrToUintn (AttrStr);
+ }
+
+ if ((GuidStr == NULL) & GuidFlag) {
+ PrintErr (L"Missing partition type GUID parameter", EFI_INVALID_PARAMETER);
+ goto CleanUp;
+ } else if (GuidFlag) {
+ Status = SHELL_INVALID_PARAMETER;
+ if (InternalShellIsHexOrDecimalNumber (GuidStr, FALSE, TRUE, FALSE)) {
+ UINTN Ordinal;
+
+ Ordinal = ShellStrToUintn (GuidStr);
+ if (Ordinal < NumKnownPartTypesEntries) {
+ PartTypeGuid = PartitionGetKnownType (Ordinal, NULL)->TypeGuid;
+ Status = SHELL_SUCCESS;
+ } else {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellGptHiiHandle, gAppName, GuidStr);
+ goto CleanUp;
+ }
+ } else {
+ Status = ConvertStringToGuid (GuidStr, &PartTypeGuid);
+ if ((EFI_ERROR (Status)) || (IsZeroGuid (&PartTypeGuid))) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellGptHiiHandle, gAppName, GuidStr);
+ Status = SHELL_INVALID_PARAMETER;
+ goto CleanUp;
+ }
+ }
+ }
+
+ if (FileFlag) {
+ // Read FilePath parameter
+ if (FileStr == NULL) {
+ PrintErr (L"No FilePath parameter", EFI_INVALID_PARAMETER);
+ goto CleanUp;
+ } else {
+ FilePath = (CHAR16 *)FileStr;
+ Status = ShellIsFile (FilePath);
+ // When read file into flash, file doesn't have to exist
+ if (EFI_ERROR (Status && !(Flag & READ_FILE))) {
+ PrintErr (L"Wrong FilePath parameter", Status);
+ Status = SHELL_INVALID_PARAMETER;
+ goto CleanUp;
+ }
+ }
+
+ Status = OpenAndPrepareFile (FilePath, &FileHandle, ((Flag & READ_FILE) != 0));
+ if (EFI_ERROR (Status)) {
+ Print (L"Error %r while preparing file %s", Status, FilePath);
+ Status = SHELL_ABORTED;
+ goto CleanUp;
+ }
+
+ // Get file size in order to check correctness at the end of transfer
+ if (Flag & (WRITE_FILE)) {
+ Status = FileHandleGetSize (FileHandle, &FileSize);
+ if (EFI_ERROR (Status)) {
+ PrintErr (L"Cannot get file size", Status);
+ Status = SHELL_ABORTED;
+ goto CleanUp;
+ }
+ ByteCount = (UINT64)FileSize;
+ }
+
+ FileBuffer = AllocateZeroPool ((UINTN)ByteCount);
+ if (FileBuffer == NULL) {
+ PrintErr (L"Cannot allocate memory", EFI_OUT_OF_RESOURCES);
+ Status = SHELL_OUT_OF_RESOURCES;
+ goto Error_Close_File;
+ }
+
+ // Read file content and store it in FileBuffer
+ if (Flag & (WRITE_FILE)) {
+ if (!Quiet) {
+ Print (L"Reading %s...\r", FilePath);
+ }
+ Status = FileHandleRead (FileHandle, &ByteCount, FileBuffer);
+ if (EFI_ERROR (Status)) {
+ PrintErr (L"Read from file error", Status);
+ Status = SHELL_ABORTED;
+ goto Error_Free_Buffer;
+ } else if (ByteCount != (UINTN)FileSize) {
+ PrintErr (L"Not whole file read. Abort", EFI_DEVICE_ERROR);
+ Status = SHELL_DEVICE_ERROR;
+ goto Error_Free_Buffer;
+ }
+ if (!Quiet) {
+ Print (L"Writing %s into device %s, partition %s...\n", FilePath, BlockName, PartName);
+ }
+ }
+ }
+
+ Buffer = (UINT8 *)Address;
+ if (FileFlag) {
+ Buffer = FileBuffer;
+ }
+
+ if (Flag > TYPES_INFO) {
+ Entry = PartitionFindPartitionByCriteria (PartName, 0, 0, SRC_BY_NAME);
+ if (!Entry && PartName && (InternalShellIsHexOrDecimalNumber (PartName, FALSE, TRUE, FALSE))) {
+ Entry = PartitionFindPartitionByCriteria (PartName, 0, 0, SRC_BY_NUM);
+ }
+ if ((!Entry) && (PartNameFlag)) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellGptHiiHandle, gAppName, PartName);
+ Print (L"Could not find partition %s (case-sensitive). Make sure the name is spelled properly\n", PartName);
+ Status = SHELL_NOT_FOUND;
+ goto CleanUp;
+ }
+ }
+
+ switch (Flag) {
+ case CREATE:
+ PartitionGptCreatePartition (
+ PartName,
+ Offset, // Lba. If 0, the next available is assumed
+ ByteCount, // in MegaBytes. If 0 the whole remaining space is assumed
+ PartAttributes,
+ PartTypeGuid);
+ break;
+ case DELETE:
+ ModParams.PartName = PartName;
+ ShellPrintHiiEx (-1, -1,
+ NULL, STRING_TOKEN (STR_GPT_DELETE_WARNING),
+ gShellGptHiiHandle,
+ Entry->PartitionName
+ );
+ if ((NoPrompt) || (!GptPromptYesNo (STRING_TOKEN (STR_GPT_ABSOLUTELY_SURE)))) {
+ Status = PartitionGptModifyPartition (
+ Entry, &ModParams, MOD_DELETE);
+ if (EFI_ERROR (Status)) {
+ PrintErr (L"Error deleting the partition", Status);
+ Status = SHELL_ABORTED;
+ goto CleanUp;
+ }
+ Status = SHELL_SUCCESS;
+ } else {
+ Status = SHELL_ABORTED;
+ }
+ break;
+ case FAT_FORMAT:
+ {
+ EFI_LBA StartingLBA, EndingLBA;
+ CHAR8 LabelName[12];
+
+ if (VolumeName) {
+ if (StrLen (VolumeName) > 11) {
+ Status = EFI_INVALID_PARAMETER;
+ PrintErr (L"The volume label is too long", Status);
+ Status = SHELL_INVALID_PARAMETER;
+ goto CleanUp;
+ }
+ UnicodeStrToAsciiStr (VolumeName, (CHAR8 *)LabelName);
+ }
+ ShellPrintHiiEx (-1, -1,
+ NULL, STRING_TOKEN (STR_GPT_FORMAT_WARNING),
+ gShellGptHiiHandle,
+ Entry ? Entry->PartitionName : BlockName
+ );
+
+ if ((NoPrompt) || (!GptPromptYesNo (STRING_TOKEN (STR_GPT_FORMAT_SURE)) &&
+ (!GptPromptYesNo (STRING_TOKEN (STR_GPT_ABSOLUTELY_SURE))))
+ ) {
+ StartingLBA = 0;
+ EndingLBA = BlockIo->Media->LastBlock;
+ if (Entry) {
+ StartingLBA = Entry->StartingLBA;
+ EndingLBA = Entry->EndingLBA;
+ }
+ if (!Quiet) {
+ Print (L"Formatting %s to FAT32...\r", PartNameFlag ? Entry->PartitionName : BlockName);
+ }
+ Status = FatFormat (StartingLBA, EndingLBA, BlockIo, DiskIo, VolumeName ? LabelName : NULL, TRUE);
+ if (EFI_ERROR (Status)) {
+ PrintErr (L"Error formatting the partition to FAT ", Status);
+ Status = SHELL_ABORTED;
+ goto CleanUp;
+ } else if (!Quiet) {
+ Print (L"%s successfully formatted to FAT. Formatted size %llu MiB\n",
+ PartNameFlag ? Entry->PartitionName : BlockName,
+ MultU64x32 (EndingLBA - StartingLBA + 1, BlockIo->Media->BlockSize) >> 20
+ );
+ }
+ } else {
+ Status = SHELL_ABORTED;
+ }
+ }
+ break;
+ case RENAME:
+ ModParams.PartName = PartName;
+ ModParams.NewName = NewPartName;
+ Status = PartitionGptModifyPartition (
+ Entry, &ModParams, MOD_RENAME);
+ break;
+ case SETATTR:
+ ModParams.Attributes = PartAttributes;
+ Status = PartitionGptModifyPartition (
+ Entry, &ModParams, MOD_ATTR);
+ break;
+ case SETTYPE:
+ ModParams.PartTypeGuid = PartTypeGuid;
+ Status = PartitionGptModifyPartition (
+ Entry, &ModParams, MOD_TYPE);
+ break;
+ case INFO:
+ PartitionPrintGptPartInfo (Entry);
+ Status = SHELL_SUCCESS;
+ break;
+ case READ:
+ case READ_FILE:
+ case WRITE:
+ case WRITE_FILE:
+ {
+ UINT64 MaxBytes;
+ BOOLEAN OpRead;
+
+ OpRead = ((Flag & READ) || (Flag & READ_FILE));
+ MaxBytes = MultU64x32 (
+ Entry->EndingLBA - Entry->StartingLBA,
+ BlockIo->Media->BlockSize) +
+ BlockIo->Media->BlockSize -
+ MultU64x32 (Offset, BlockIo->Media->BlockSize);
+ if (ByteCount > MaxBytes) {
+ Status = EFI_INVALID_PARAMETER;
+ ShellPrintHiiEx (-1, -1,
+ NULL, (OpRead) ?
+ STRING_TOKEN (STR_GPT_READ_BOUNDARY) :
+ STRING_TOKEN (STR_GPT_WRITE_BOUNDARY),
+ gShellGptHiiHandle,
+ gAppName,
+ Entry->PartitionName,
+ MaxBytes,
+ ByteCount
+ );
+ Status = SHELL_INVALID_PARAMETER;
+ goto CleanUp;
+ }
+
+ TimeStampB = GetPerformanceCounter ();
+ if (OpRead) {
+ Status = DiskIo->ReadDisk (DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 (Offset + Entry->StartingLBA, BlockIo->Media->BlockSize), ByteCount, Buffer);
+ } else {
+ Status = DiskIo->WriteDisk (DiskIo, BlockIo->Media->MediaId,
+ MultU64x32 (Offset + Entry->StartingLBA, BlockIo->Media->BlockSize), ByteCount, Buffer);
+ }
+ }
+ break;
+ default:
+ Status = SHELL_INVALID_PARAMETER;
+ PrintErr (L"Unknown command. Try \"help gpt\"", EFI_INVALID_PARAMETER);
+ goto CleanUp;
+ }
+
+ if (EFI_ERROR (Status)) {
+ PrintErr (L"Error while performing transfer\n", Status);
+ Status = SHELL_ABORTED;
+ goto CleanUp;
+ }
+
+ TimeStampE = ((GetPerformanceCounter () - TimeStampB) * 1000) / Freq;
+ SpeedKB = TimeStampE ? (ByteCount / (TimeStampE / 1000)) >> 10 : 0;
+
+ switch (Flag) {
+ case WRITE:
+ case WRITE_FILE:
+ if (!Quiet) {
+ ShellPrintHiiEx (-1, -1,
+ NULL,
+ STRING_TOKEN (STR_GPT_WRITE_OK),
+ gShellGptHiiHandle,
+ ByteCount,
+ Offset,
+ Entry->PartitionName,
+ TimeStampE,
+ SpeedKB
+ );
+ }
+ break;
+ case READ:
+ if (!Quiet) {
+ ShellPrintHiiEx (-1, -1,
+ NULL,
+ STRING_TOKEN (STR_GPT_READ_OK),
+ gShellGptHiiHandle,
+ ByteCount,
+ Offset,
+ Entry->PartitionName,
+ TimeStampE,
+ SpeedKB
+ );
+ }
+ break;
+ case READ_FILE:
+ Status = FileHandleWrite (FileHandle, &ByteCount, FileBuffer);
+ if (EFI_ERROR (Status)) {
+ ShellPrintHiiEx (-1, -1,
+ NULL,
+ STRING_TOKEN (STR_GPT_FILE_WRITE_FAIL),
+ gShellGptHiiHandle,
+ gAppName,
+ FilePath,
+ Status
+ );
+ Status = SHELL_DEVICE_ERROR;
+ goto Error_Free_Buffer;
+ }
+
+ if (!Quiet) {
+ ShellPrintHiiEx (-1, -1,
+ NULL,
+ STRING_TOKEN (STR_GPT_READFILE_OK),
+ gShellGptHiiHandle,
+ ByteCount,
+ Offset,
+ Entry->PartitionName,
+ FilePath,
+ TimeStampE,
+ SpeedKB
+ );
+ }
+ break;
+ }
+
+ if (FileFlag) {
+ SHELL_FREE_NON_NULL (FileBuffer);
+ if (FileHandle != NULL) {
+ ShellCloseFile (&FileHandle);
+ FileHandle = NULL;
+ }
+ }
+
+ Status = SHELL_SUCCESS;
+
+ Error_Free_Buffer:
+ SHELL_FREE_NON_NULL (FileBuffer);
+ Error_Close_File:
+ if (FileHandle) {
+ ShellCloseFile (&FileHandle);
+ }
+ CleanUp:
+ if (BlockIoHandle) {
+ // By UEFI Spec blocks must be flushed
+ BlockIo->FlushBlocks (BlockIo);
+ gBS->CloseProtocol (BlockIoHandle, &gEfiBlockIoProtocolGuid, gImageHandle, NULL);
+ }
+
+ GptCleanupGlobals ();
+
+ ShellCommandLineFreeVarList (CheckPackage);
+
+ if (EFI_ERROR (Status)) {
+ Status = SHELL_ABORTED;
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+ShellGptLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ gShellGptHiiHandle = NULL;
+
+ gShellGptHiiHandle = HiiAddPackages (
+ &gShellGptHiiGuid, gImageHandle,
+ UefiShellGptCommandLibStrings, NULL
+ );
+ if (gShellGptHiiHandle == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ ShellCommandRegisterCommandName (
+ gAppName, ShellCommandRunGpt, ShellCommandGetManFileNameGpt, 0,
+ gAppName, TRUE, gShellGptHiiHandle, STRING_TOKEN (STR_GET_HELP_GPT)
+ );
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+ShellGptLibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+
+ if (gShellGptHiiHandle != NULL) {
+ HiiRemovePackages (gShellGptHiiHandle);
+ }
+ return EFI_SUCCESS;
+}
diff --git a/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
new file mode 100644
index 000000000000..1be4b1ab0f11
--- /dev/null
+++ b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
@@ -0,0 +1,79 @@
+#
+# Marvell BSD License Option
+#
+# If you received this File from Marvell, you may opt to use, redistribute
+# and/or modify this File under the following licensing terms.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Marvell nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# Portions Copyright (C) 2016 Broadcom
+#
+
+[Defines]
+ INF_VERSION = 0x00010006
+ BASE_NAME = UefiShellGptCommandLib
+ FILE_GUID = F62ACF25-0D15-22F5-E642-FFB6515E00D7
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 0.1
+ LIBRARY_CLASS = NULL|UEFI_APPLICATION UEFI_DRIVER
+ CONSTRUCTOR = ShellGptLibConstructor
+ DESTRUCTOR = ShellGptLibDestructor
+
+[Sources]
+ FatFormat.c
+ GptWorker.c
+ UefiShellGptCommandLib.c
+ UefiShellGptCommandLib.uni
+
+[Packages]
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ ShellPkg/ShellPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ DevicePathLib
+ FileHandleLib
+ HiiLib
+ MemoryAllocationLib
+ PcdLib
+ ShellCommandLib
+ ShellLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ UefiLib
+
+[Protocols]
+ gEfiBlockIoProtocolGuid
+ gEfiDevicePathProtocolGuid
+ gEfiDiskIoProtocolGuid
+
+[Guids]
+ gShellGptHiiGuid
+ gEfiPartTypeUnusedGuid ## SOMETIMES_CONSUMES ## GUID
diff --git a/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
new file mode 100644
index 000000000000..55bcb42cfeb3
--- /dev/null
+++ b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
@@ -0,0 +1,117 @@
+/*******************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+/* Portions Copyright (C) 2016 Broadcom */
+/=#
+
+#langdef en-US "english"
+
+#string STR_GEN_PARAM_INV #language en-US "%H%s%N: Invalid argument - '%H%s%N'\r\n"
+#string STR_GEN_MAP_PROTOCOL #language en-US "%H%s%N: Mapped device '%B%s%N' does not have protocol %B%s%N\r\n"
+
+#string STR_GPT_ERROR #language en-US "%H%s%N: %r - %s\r\n"
+#string STR_GPT_NOT_EMPTY #language en-US "%H%s%N: WARNING!!! This device has valid GPT partition tables!\r\n"
+#string STR_GPT_CLEAR_SURE #language en-US "Are you sure you want to clear the GPT tables on this device? %BY%Nes, %BN%No "
+#string STR_GPT_ABSOLUTELY_SURE #language en-US "\r\nAre you *** ABSOLUTELY SURE *** you want to perform this operation ? %BY%Nes, %BN%No "
+#string STR_GPT_FORMAT_WARNING #language en-US "%H%s%N: WARNING!!! Formatting of this partition will destroy all data on it!\r\n"
+#string STR_GPT_FORMAT_SURE #language en-US "Are you sure you want to format this partition to FAT32 and destroy all data on it ? %BY%Nes, %BN%No "
+#string STR_GPT_DELETE_WARNING #language en-US "%H%s%N: Deleting of this partition will make data on it unreachable!\r\n"
+#string STR_GPT_READ_BOUNDARY #language en-US "%H%s%N: Attempt to read beyond %H%s%N partition boundary (can read upto %llu bytes from the given offset, requested %llu bytes)\r\n"
+#string STR_GPT_WRITE_BOUNDARY #language en-US "%H%s%N: Attempt to write beyond %H%s%N partition boundary (can write upto %llu bytes from the given offset, requested %llu bytes)\r\n"
+#string STR_GPT_FILE_WRITE_FAIL #language en-US "%H%s%N: Failed to write to the file %s, error %r\r\n"
+
+#string STR_GPT_WRITE_OK #language en-US "Written %llu bytes at offset 0x%x, partition %s. Elapsed time %llums (%llu KB/s)\r\n"
+#string STR_GPT_READ_OK #language en-US "Read %llu bytes from offset 0x%x, partition %s. Elapsed time %llums (%llu KB/s)\r\n"
+#string STR_GPT_READFILE_OK #language en-US "Read %llu bytes from offset 0x%x, partition %s into file %s. Elapsed time %llums (%llu KB/s)\r\n"
+#string STR_GPT_LIST_DEVS #language en-US " %H%+6s%N %+8s "
+
+#string STR_GET_HELP_GPT #language en-US ""
+".TH gpt 0 "GPT partition manager."\r\n"
+".SH NAME\r\n"
+"Manages GPT partitions on a block device.\r\n"
+".SH SYNOPSIS\r\n"
+" \r\n"
+"gpt [read | readfile | write | writefile | list | info | clear |\r\n"
+" create | delete | rename | setattrs | sync | fatformat | -typesinfo | -yes] \r\n"
+"This is a complex utility. Please see examples for usage info\r\n"
+".SH OPTIONS\r\n"
+" \r\n"
+" Device - Block device to be used for the operation\r\n"
+" Length - Number of bytes to transfer (for read/write))\r\n"
+" Address - Address in RAM to store/load data\r\n"
+" Offset - Offset (in blocks) from beggining of the specifie partition to store/load data\r\n"
+" FilePath - Path to file to read data into or write/update data from\r\n"
+" -yes - Assume yes for all queries, do not prompt\r\n\r\n"
+".SH EXAMPLES\r\n"
+" \r\n"
+"EXAMPLES:\r\n"
+"Get the list of available partitionable block device(s)\r\n"
+" gpt %Hlist%N\r\n"
+"Get info on the particular partition with name PartitionName on the block device blk0:\r\n"
+" gpt %Hinfo%N blk0: PartitionName\r\n"
+"List all available GPT partitions on the block device blk0:\r\n"
+" gpt list blk0:\r\n"
+"Note: the ordinal number shown by this command can be used as a partition name in any command requiring partition name\r\n"
+"Thus gpt info blk0: 1 is valid if there is a partition with ordinal 1 present in the output of gpt list command\r\n"
+"Get information on all recognized partition types\r\n"
+" gpt %Htypesinfo%N\r\n"
+"Clear partitions information and install empty GPT tables for a block device blk0:\r\n"
+" gpt %Hclear%N blk0:\r\n"
+"Create a GPT partition with name PartitionName and type EFI SYSTEM in the GPT table, using the next available LBA, with size\r\n"
+"64MiB, with system attribute, on block device blk0:\r\n"
+" gpt %Hcreate%N blk0: PartitionName 0 64 1 -type 0\r\n"
+"Same as above, but now the partition type is not known to the gpt utility, so use some GUID known to a 3rd party\r\n"
+" gpt create blk0: PartitionName 0 64 1 -type 44581A4A-C834-D1A6-2602-9D522A8F2307\r\n"
+"Rename the GPT partition PartitionName on blk0: to NewPartitionName\r\n"
+" gpt %Hrename%N blk0: PartitionName NewPartitionName\r\n"
+"Have the PartitionDxe driver to re-read GPT tables on a block device blk0:(after they were updated with gpt utility)\r\n"
+" gpt %Hsync%N blk0:\r\n"
+"Read 4K from block offset 0x0e000 in Partition named PartitionName of the block device at blk0: into RAM at address 0x100000\r\n"
+" gpt %Hread%N blk0: 0x100000 PartitionName 0xe000 4096\r\n"
+"Write 512 bytes from 0x200000 at RAM into the block device at blk0: partition PartitionName at offset 0x1000\r\n"
+" gpt %Hwrite%N blk0: 0x200000 PartitionName 0x1000 512\r\n"
+"Read 0x3000 bytes from 0x0 offset of Partition PartitionName at the block device blk0: into file fs2:file.bin\r\n"
+" gpt %Hreadfile%N blk0: fs2:file.bin PartitionName 0x0 0x3000\r\n"
+"Write contents of file fs2:file.bin into partition named PartitionName with offset (in lba) 0x10 on a block device blk0:\r\n"
+" gpt %Hwritefile%N blk0: fs2:file.bin PartitionName 0x10\r\n"
+"FAT Format the partition PartitionName on block device blk0:\r\n"
+" gpt %Hfatformat%N blk0: PartitionName\r\n"
+"FAT Format the whole device blk0:\r\n"
+" gpt fatformat blk0:\r\n"
+
+".SH RETURNVALUES\r\n"
+" \r\n"
+"RETURN VALUES:\r\n"
+" SHELL_SUCCESS The action was completed as requested.\r\n"
+" Specific Shell error Error while processing command\r\n"
diff --git a/ShellPkg/ShellPkg.dec b/ShellPkg/ShellPkg.dec
index 39f8012b98c1..5374a2a62d5f 100644
--- a/ShellPkg/ShellPkg.dec
+++ b/ShellPkg/ShellPkg.dec
@@ -56,6 +56,7 @@ [Guids]
gShellNetwork2HiiGuid = {0x174b2b5, 0xf505, 0x4b12, {0xaa, 0x60, 0x59, 0xdf, 0xf8, 0xd6, 0xea, 0x37}}
gShellTftpHiiGuid = {0x738a9314, 0x82c1, 0x4592, {0x8f, 0xf7, 0xc1, 0xbd, 0xf1, 0xb2, 0x0e, 0xd4}}
gShellBcfgHiiGuid = {0x5f5f605d, 0x1583, 0x4a2d, {0xa6, 0xb2, 0xeb, 0x12, 0xda, 0xb4, 0xa2, 0xb6}}
+ gShellGptHiiGuid = {0x5a1ed739, 0x5ef1, 0x429a, {0x8d, 0xf8, 0x28, 0xc9, 0x92, 0x64, 0xd7, 0xf8}}
[Protocols]
gEfiShellProtocolGuid = {0x6302d008, 0x7f9b, 0x4f30, {0x87, 0xac, 0x60, 0xc9, 0xfe, 0xf5, 0xda, 0x4e}}
diff --git a/ShellPkg/ShellPkg.dsc b/ShellPkg/ShellPkg.dsc
index 809bd4220af2..984c1d0ad48b 100644
--- a/ShellPkg/ShellPkg.dsc
+++ b/ShellPkg/ShellPkg.dsc
@@ -89,6 +89,7 @@ [Components]
ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.inf
ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.inf
ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.inf
+ ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLib.inf
ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf
ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.inf
@@ -119,6 +120,9 @@ [Components]
!ifdef $(INCLUDE_TFTP_COMMAND)
NULL|ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.inf
!endif #$(INCLUDE_TFTP_COMMAND)
+!ifdef $(INCLUDE_GPT_COMMAND)
+ NULL|ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
+!endif #$(INCLUDE_GPT_COMMAND)
!endif #$(NO_SHELL_PROFILES)
}
--
1.9.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH] GPT Shell Application/Library
2016-10-16 5:23 [PATCH] GPT Shell Application/Library Vladimir Olovyannikov
@ 2016-10-16 20:05 ` Laszlo Ersek
[not found] ` <CACmgjazi_K4Qo5=TeO_tCGK2cB26d0rqOEZh6TthP1UYbo6J6w@mail.gmail.com>
2016-10-18 1:45 ` Ni, Ruiyu
1 sibling, 1 reply; 20+ messages in thread
From: Laszlo Ersek @ 2016-10-16 20:05 UTC (permalink / raw)
To: Vladimir Olovyannikov; +Cc: jaben.carsey, edk2-devel, ruiyu.ni
On 10/16/16 07:23, Vladimir Olovyannikov wrote:
> This allows managing (create, delete, modify, fat format) of GPT
> partitions from within UEFI Shell.
> Syntax:
> gpt <command> [device_mapped_name] [parameters...]
> See usage examples in the .uni file
> ---
> .../Library/UefiShellGptCommandLib/FatFormat.c | 611 +++++++
> .../Library/UefiShellGptCommandLib/FatFormat.h | 111 ++
> .../Library/UefiShellGptCommandLib/GptWorker.c | 1902 ++++++++++++++++++++
> .../Library/UefiShellGptCommandLib/GptWorker.h | 186 ++
> .../UefiShellGptCommandLib.c | 1135 ++++++++++++
> .../UefiShellGptCommandLib.inf | 79 +
> .../UefiShellGptCommandLib.uni | 117 ++
> ShellPkg/ShellPkg.dec | 1 +
> ShellPkg/ShellPkg.dsc | 4 +
> 9 files changed, 4146 insertions(+)
> create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
This looks like a supremely welcome, long-awaited addition (latest
request:
<https://lists.01.org/pipermail/edk2-devel/2016-October/002667.html>),
but it really needs your Signed-off-by, and the Contributed-under line
above it:
ShellPkg/Contributions.txt
I would also suggest (simply based on what I've seen elsewhere in edk2)
to keep the copyright notices tightly collected in the file headings.
Someone will have to go over all the licenses too -- does the "Marvell
BSD License Option" for example correspond to the 3-clause BSDL?
On the technical side, I believe that as long as a shell command (or a
command option) is not standardized (in the shell spec), it usually
starts with an underscore (_), so as to prevent future name collisions.
(I could be wrong about this -- I now recall the TFTP command, which is
also not in the 2.2 spec.)
Just my two cents.
Thanks
Laszlo
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] GPT Shell Application/Library
[not found] ` <CACmgjaziUEF2EsSn73HY5JvL2rmRWrXS+rHMtOQ1HaRwPpXS+g@mail.gmail.com>
@ 2016-10-17 6:49 ` Vladimir Olovyannikov
2016-10-17 7:24 ` Michael Zimmermann
2016-10-17 9:43 ` Laszlo Ersek
0 siblings, 2 replies; 20+ messages in thread
From: Vladimir Olovyannikov @ 2016-10-17 6:49 UTC (permalink / raw)
To: Laszlo Ersek; +Cc: edk2-devel@lists.01.org, Jaben Carsey, ruiyu.ni
Thank you Laszlo,
Sorry, I missed the fields; it is my first contribution, I will add the
required lines, review the source according to your comments and will
resubmit the patch.
So do you think the command should be _gpt instead of gpt? I was following
TFTP and SF commands as a template.
Thank you,
Vladimir
On Oct 16, 2016 1:05 PM, "Laszlo Ersek" <lersek@redhat.com> wrote:
>
> On 10/16/16 07:23, Vladimir Olovyannikov wrote:
> > This allows managing (create, delete, modify, fat format) of GPT
> > partitions from within UEFI Shell.
> > Syntax:
> > gpt <command> [device_mapped_name] [parameters...]
> > See usage examples in the .uni file
> > ---
> > .../Library/UefiShellGptCommandLib/FatFormat.c | 611 +++++++
> > .../Library/UefiShellGptCommandLib/FatFormat.h | 111 ++
> > .../Library/UefiShellGptCommandLib/GptWorker.c | 1902
++++++++++++++++++++
> > .../Library/UefiShellGptCommandLib/GptWorker.h | 186 ++
> > .../UefiShellGptCommandLib.c | 1135 ++++++++++++
> > .../UefiShellGptCommandLib.inf | 79 +
> > .../UefiShellGptCommandLib.uni | 117 ++
> > ShellPkg/ShellPkg.dec | 1 +
> > ShellPkg/ShellPkg.dsc | 4 +
> > 9 files changed, 4146 insertions(+)
> > create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> > create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> > create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> > create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> > create mode 100644
ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> > create mode 100644
ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> > create mode 100644
ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
>
> This looks like a supremely welcome, long-awaited addition (latest
> request:
> <https://lists.01.org/pipermail/edk2-devel/2016-October/002667.html>),
> but it really needs your Signed-off-by, and the Contributed-under line
> above it:
>
> ShellPkg/Contributions.txt
>
> I would also suggest (simply based on what I've seen elsewhere in edk2)
> to keep the copyright notices tightly collected in the file headings.
>
> Someone will have to go over all the licenses too -- does the "Marvell
> BSD License Option" for example correspond to the 3-clause BSDL?
>
> On the technical side, I believe that as long as a shell command (or a
> command option) is not standardized (in the shell spec), it usually
> starts with an underscore (_), so as to prevent future name collisions.
> (I could be wrong about this -- I now recall the TFTP command, which is
> also not in the 2.2 spec.)
>
> Just my two cents.
>
> Thanks
> Laszlo
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] GPT Shell Application/Library
2016-10-17 6:49 ` Vladimir Olovyannikov
@ 2016-10-17 7:24 ` Michael Zimmermann
2016-10-17 17:52 ` Vladimir Olovyannikov
2016-10-17 9:43 ` Laszlo Ersek
1 sibling, 1 reply; 20+ messages in thread
From: Michael Zimmermann @ 2016-10-17 7:24 UTC (permalink / raw)
To: Vladimir Olovyannikov
Cc: Laszlo Ersek, Jaben Carsey, Ni, Ruiyu, edk2-devel@lists.01.org
Hi,
wouldn't it be better to make a generic gpt parsing library which is
independent of the shell so both the shell and PartitionDxe can use it?
It may also be useful for other applications which need additional
information like the gpt partition names.
Thanks
Michael
On Mon, Oct 17, 2016 at 8:49 AM, Vladimir Olovyannikov <
vladimir.olovyannikov@broadcom.com> wrote:
> Thank you Laszlo,
>
> Sorry, I missed the fields; it is my first contribution, I will add the
> required lines, review the source according to your comments and will
> resubmit the patch.
> So do you think the command should be _gpt instead of gpt? I was following
> TFTP and SF commands as a template.
>
> Thank you,
> Vladimir
>
> On Oct 16, 2016 1:05 PM, "Laszlo Ersek" <lersek@redhat.com> wrote:
> >
> > On 10/16/16 07:23, Vladimir Olovyannikov wrote:
> > > This allows managing (create, delete, modify, fat format) of GPT
> > > partitions from within UEFI Shell.
> > > Syntax:
> > > gpt <command> [device_mapped_name] [parameters...]
> > > See usage examples in the .uni file
> > > ---
> > > .../Library/UefiShellGptCommandLib/FatFormat.c | 611 +++++++
> > > .../Library/UefiShellGptCommandLib/FatFormat.h | 111 ++
> > > .../Library/UefiShellGptCommandLib/GptWorker.c | 1902
> ++++++++++++++++++++
> > > .../Library/UefiShellGptCommandLib/GptWorker.h | 186 ++
> > > .../UefiShellGptCommandLib.c | 1135 ++++++++++++
> > > .../UefiShellGptCommandLib.inf | 79 +
> > > .../UefiShellGptCommandLib.uni | 117 ++
> > > ShellPkg/ShellPkg.dec | 1 +
> > > ShellPkg/ShellPkg.dsc | 4 +
> > > 9 files changed, 4146 insertions(+)
> > > create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/
> FatFormat.c
> > > create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/
> FatFormat.h
> > > create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/
> GptWorker.c
> > > create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/
> GptWorker.h
> > > create mode 100644
> ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> > > create mode 100644
> ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> > > create mode 100644
> ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
> >
> > This looks like a supremely welcome, long-awaited addition (latest
> > request:
> > <https://lists.01.org/pipermail/edk2-devel/2016-October/002667.html>),
> > but it really needs your Signed-off-by, and the Contributed-under line
> > above it:
> >
> > ShellPkg/Contributions.txt
> >
> > I would also suggest (simply based on what I've seen elsewhere in edk2)
> > to keep the copyright notices tightly collected in the file headings.
> >
> > Someone will have to go over all the licenses too -- does the "Marvell
> > BSD License Option" for example correspond to the 3-clause BSDL?
> >
> > On the technical side, I believe that as long as a shell command (or a
> > command option) is not standardized (in the shell spec), it usually
> > starts with an underscore (_), so as to prevent future name collisions.
> > (I could be wrong about this -- I now recall the TFTP command, which is
> > also not in the 2.2 spec.)
> >
> > Just my two cents.
> >
> > Thanks
> > Laszlo
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel
>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] GPT Shell Application/Library
2016-10-17 6:49 ` Vladimir Olovyannikov
2016-10-17 7:24 ` Michael Zimmermann
@ 2016-10-17 9:43 ` Laszlo Ersek
2016-10-17 16:35 ` Carsey, Jaben
1 sibling, 1 reply; 20+ messages in thread
From: Laszlo Ersek @ 2016-10-17 9:43 UTC (permalink / raw)
To: Vladimir Olovyannikov; +Cc: edk2-devel@lists.01.org, Jaben Carsey, ruiyu.ni
On 10/17/16 08:49, Vladimir Olovyannikov wrote:
> Thank you Laszlo,
>
> Sorry, I missed the fields; it is my first contribution, I will add the
> required lines, review the source according to your comments and will
> resubmit the patch.
> So do you think the command should be _gpt instead of gpt? I was
> following TFTP and SF commands as a template.
Right, at this point I'm confused about TFTP even, in retrospect. It's
not in the spec, so I guess it should have been _TFTP. I hope Jaben and
Ray can advise us. :)
Thanks
Laszlo
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] GPT Shell Application/Library
2016-10-17 9:43 ` Laszlo Ersek
@ 2016-10-17 16:35 ` Carsey, Jaben
0 siblings, 0 replies; 20+ messages in thread
From: Carsey, Jaben @ 2016-10-17 16:35 UTC (permalink / raw)
To: Laszlo Ersek, Vladimir Olovyannikov
Cc: Ni, Ruiyu, edk2-devel@lists.01.org, Carsey, Jaben
Laszlo,
We don't have a hard and fast rule about command names. The simple thing is that we may have a conflict in the future, but I don't see that as likely at this point.
Your comment about _ was when a custom implementation wants to extend an existing defined command with a non-standard parameter. For example there is an _exit parameter to the shell that tells the shell to auto-close after running the initial command line passed into it.
-Jaben
> -----Original Message-----
> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
> Laszlo Ersek
> Sent: Monday, October 17, 2016 2:44 AM
> To: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>
> Cc: Carsey, Jaben <jaben.carsey@intel.com>; Ni, Ruiyu
> <ruiyu.ni@intel.com>; edk2-devel@lists.01.org <edk2-devel@ml01.01.org>
> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> Importance: High
>
> On 10/17/16 08:49, Vladimir Olovyannikov wrote:
> > Thank you Laszlo,
> >
> > Sorry, I missed the fields; it is my first contribution, I will add the
> > required lines, review the source according to your comments and will
> > resubmit the patch.
> > So do you think the command should be _gpt instead of gpt? I was
> > following TFTP and SF commands as a template.
>
> Right, at this point I'm confused about TFTP even, in retrospect. It's
> not in the spec, so I guess it should have been _TFTP. I hope Jaben and
> Ray can advise us. :)
>
> Thanks
> Laszlo
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] GPT Shell Application/Library
2016-10-17 7:24 ` Michael Zimmermann
@ 2016-10-17 17:52 ` Vladimir Olovyannikov
2016-10-17 17:56 ` Carsey, Jaben
0 siblings, 1 reply; 20+ messages in thread
From: Vladimir Olovyannikov @ 2016-10-17 17:52 UTC (permalink / raw)
To: Michael Zimmermann
Cc: Laszlo Ersek, Jaben Carsey, Ni, Ruiyu, edk2-devel@lists.01.org
Hi Michael,
I am absolutely agree with your proposal.
In the gpt Shell library/application I had to “borrow” some stuff from
PartitionDxe.c to not reinvent a wheel.
If the PartitionDxe maintainer agrees to have a separate library available
for everybody,
I would move all the GPT-related stuff from the GptWorker (and partially
from the PartitionDxe itself) to that independent library.
This could be a longer-term task.
Right now I just wanted to share the tool which could be useful for anybody
who would wish to manage
GPT partitions (and/or do a FAT32 format of either a disk or a GPT
partition) from within the Shell. What do you think?
Thank you,
Vladimir
*From:* Michael Zimmermann [mailto:sigmaepsilon92@gmail.com]
*Sent:* October-17-16 12:25 AM
*To:* Vladimir Olovyannikov
*Cc:* Laszlo Ersek; Jaben Carsey; Ni, Ruiyu; edk2-devel@lists.01.org
*Subject:* Re: [edk2] [PATCH] GPT Shell Application/Library
Hi,
wouldn't it be better to make a generic gpt parsing library which is
independent of the shell so both the shell and PartitionDxe can use it?
It may also be useful for other applications which need additional
information like the gpt partition names.
Thanks
Michael
On Mon, Oct 17, 2016 at 8:49 AM, Vladimir Olovyannikov <
vladimir.olovyannikov@broadcom.com> wrote:
Thank you Laszlo,
Sorry, I missed the fields; it is my first contribution, I will add the
required lines, review the source according to your comments and will
resubmit the patch.
So do you think the command should be _gpt instead of gpt? I was following
TFTP and SF commands as a template.
Thank you,
Vladimir
On Oct 16, 2016 1:05 PM, "Laszlo Ersek" <lersek@redhat.com> wrote:
>
> On 10/16/16 07:23, Vladimir Olovyannikov wrote:
> > This allows managing (create, delete, modify, fat format) of GPT
> > partitions from within UEFI Shell.
> > Syntax:
> > gpt <command> [device_mapped_name] [parameters...]
> > See usage examples in the .uni file
> > ---
> > .../Library/UefiShellGptCommandLib/FatFormat.c | 611 +++++++
> > .../Library/UefiShellGptCommandLib/FatFormat.h | 111 ++
> > .../Library/UefiShellGptCommandLib/GptWorker.c | 1902
++++++++++++++++++++
> > .../Library/UefiShellGptCommandLib/GptWorker.h | 186 ++
> > .../UefiShellGptCommandLib.c | 1135 ++++++++++++
> > .../UefiShellGptCommandLib.inf | 79 +
> > .../UefiShellGptCommandLib.uni | 117 ++
> > ShellPkg/ShellPkg.dec | 1 +
> > ShellPkg/ShellPkg.dsc | 4 +
> > 9 files changed, 4146 insertions(+)
> > create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> > create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> > create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> > create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> > create mode 100644
ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> > create mode 100644
ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> > create mode 100644
ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
>
> This looks like a supremely welcome, long-awaited addition (latest
> request:
> <https://lists.01.org/pipermail/edk2-devel/2016-October/002667.html>),
> but it really needs your Signed-off-by, and the Contributed-under line
> above it:
>
> ShellPkg/Contributions.txt
>
> I would also suggest (simply based on what I've seen elsewhere in edk2)
> to keep the copyright notices tightly collected in the file headings.
>
> Someone will have to go over all the licenses too -- does the "Marvell
> BSD License Option" for example correspond to the 3-clause BSDL?
>
> On the technical side, I believe that as long as a shell command (or a
> command option) is not standardized (in the shell spec), it usually
> starts with an underscore (_), so as to prevent future name collisions.
> (I could be wrong about this -- I now recall the TFTP command, which is
> also not in the 2.2 spec.)
>
> Just my two cents.
>
> Thanks
> Laszlo
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] GPT Shell Application/Library
2016-10-17 17:52 ` Vladimir Olovyannikov
@ 2016-10-17 17:56 ` Carsey, Jaben
2016-10-18 13:59 ` Shah, Tapan
0 siblings, 1 reply; 20+ messages in thread
From: Carsey, Jaben @ 2016-10-17 17:56 UTC (permalink / raw)
To: Vladimir Olovyannikov, Michael Zimmermann
Cc: Laszlo Ersek, Ni, Ruiyu, edk2-devel@lists.01.org, Arshi, Shala,
Carsey, Jaben
To the old question about license: I asked our people to check and was told that the license is compatible with our BSD and ok by Intel.
To the technical content – I really like this idea of a shared library. That would be a great way to share code and not have as much duplicate.
-Jaben
From: Vladimir Olovyannikov [mailto:vladimir.olovyannikov@broadcom.com]
Sent: Monday, October 17, 2016 10:52 AM
To: Michael Zimmermann <sigmaepsilon92@gmail.com>
Cc: Laszlo Ersek <lersek@redhat.com>; Carsey, Jaben <jaben.carsey@intel.com>; Ni, Ruiyu <ruiyu.ni@intel.com>; edk2-devel@lists.01.org <edk2-devel@ml01.01.org>
Subject: RE: [edk2] [PATCH] GPT Shell Application/Library
Importance: High
Hi Michael,
I am absolutely agree with your proposal.
In the gpt Shell library/application I had to “borrow” some stuff from PartitionDxe.c to not reinvent a wheel.
If the PartitionDxe maintainer agrees to have a separate library available for everybody,
I would move all the GPT-related stuff from the GptWorker (and partially from the PartitionDxe itself) to that independent library.
This could be a longer-term task.
Right now I just wanted to share the tool which could be useful for anybody who would wish to manage
GPT partitions (and/or do a FAT32 format of either a disk or a GPT partition) from within the Shell. What do you think?
Thank you,
Vladimir
From: Michael Zimmermann [mailto:sigmaepsilon92@gmail.com<mailto:sigmaepsilon92@gmail.com>]
Sent: October-17-16 12:25 AM
To: Vladimir Olovyannikov
Cc: Laszlo Ersek; Jaben Carsey; Ni, Ruiyu; edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
Hi,
wouldn't it be better to make a generic gpt parsing library which is independent of the shell so both the shell and PartitionDxe can use it?
It may also be useful for other applications which need additional information like the gpt partition names.
Thanks
Michael
On Mon, Oct 17, 2016 at 8:49 AM, Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com<mailto:vladimir.olovyannikov@broadcom.com>> wrote:
Thank you Laszlo,
Sorry, I missed the fields; it is my first contribution, I will add the
required lines, review the source according to your comments and will
resubmit the patch.
So do you think the command should be _gpt instead of gpt? I was following
TFTP and SF commands as a template.
Thank you,
Vladimir
On Oct 16, 2016 1:05 PM, "Laszlo Ersek" <lersek@redhat.com<mailto:lersek@redhat.com>> wrote:
>
> On 10/16/16 07:23, Vladimir Olovyannikov wrote:
> > This allows managing (create, delete, modify, fat format) of GPT
> > partitions from within UEFI Shell.
> > Syntax:
> > gpt <command> [device_mapped_name] [parameters...]
> > See usage examples in the .uni file
> > ---
> > .../Library/UefiShellGptCommandLib/FatFormat.c | 611 +++++++
> > .../Library/UefiShellGptCommandLib/FatFormat.h | 111 ++
> > .../Library/UefiShellGptCommandLib/GptWorker.c | 1902
++++++++++++++++++++
> > .../Library/UefiShellGptCommandLib/GptWorker.h | 186 ++
> > .../UefiShellGptCommandLib.c | 1135 ++++++++++++
> > .../UefiShellGptCommandLib.inf | 79 +
> > .../UefiShellGptCommandLib.uni | 117 ++
> > ShellPkg/ShellPkg.dec | 1 +
> > ShellPkg/ShellPkg.dsc | 4 +
> > 9 files changed, 4146 insertions(+)
> > create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> > create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> > create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> > create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> > create mode 100644
ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> > create mode 100644
ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> > create mode 100644
ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
>
> This looks like a supremely welcome, long-awaited addition (latest
> request:
> <https://lists.01.org/pipermail/edk2-devel/2016-October/002667.html>),
> but it really needs your Signed-off-by, and the Contributed-under line
> above it:
>
> ShellPkg/Contributions.txt
>
> I would also suggest (simply based on what I've seen elsewhere in edk2)
> to keep the copyright notices tightly collected in the file headings.
>
> Someone will have to go over all the licenses too -- does the "Marvell
> BSD License Option" for example correspond to the 3-clause BSDL?
>
> On the technical side, I believe that as long as a shell command (or a
> command option) is not standardized (in the shell spec), it usually
> starts with an underscore (_), so as to prevent future name collisions.
> (I could be wrong about this -- I now recall the TFTP command, which is
> also not in the 2.2 spec.)
>
> Just my two cents.
>
> Thanks
> Laszlo
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
https://lists.01.org/mailman/listinfo/edk2-devel
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] GPT Shell Application/Library
2016-10-16 5:23 [PATCH] GPT Shell Application/Library Vladimir Olovyannikov
2016-10-16 20:05 ` Laszlo Ersek
@ 2016-10-18 1:45 ` Ni, Ruiyu
2016-10-18 1:48 ` Tim Lewis
1 sibling, 1 reply; 20+ messages in thread
From: Ni, Ruiyu @ 2016-10-18 1:45 UTC (permalink / raw)
To: Vladimir Olovyannikov, Carsey, Jaben, edk2-devel@lists.01.org
Jaben,
Do you think that providing a standalone gpt.efi is better? So that Shell.efi only provides the internal commands listed in Shell spec.
Thanks/Ray
> -----Original Message-----
> From: Vladimir Olovyannikov [mailto:vladimir.olovyannikov@broadcom.com]
> Sent: Sunday, October 16, 2016 1:24 PM
> To: Carsey, Jaben <jaben.carsey@intel.com>; edk2-devel@lists.01.org; Ni,
> Ruiyu <ruiyu.ni@intel.com>
> Cc: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>
> Subject: [PATCH] GPT Shell Application/Library
>
> This allows managing (create, delete, modify, fat format) of GPT
> partitions from within UEFI Shell.
> Syntax:
> gpt <command> [device_mapped_name] [parameters...]
> See usage examples in the .uni file
> ---
> .../Library/UefiShellGptCommandLib/FatFormat.c | 611 +++++++
> .../Library/UefiShellGptCommandLib/FatFormat.h | 111 ++
> .../Library/UefiShellGptCommandLib/GptWorker.c | 1902
> ++++++++++++++++++++
> .../Library/UefiShellGptCommandLib/GptWorker.h | 186 ++
> .../UefiShellGptCommandLib.c | 1135 ++++++++++++
> .../UefiShellGptCommandLib.inf | 79 +
> .../UefiShellGptCommandLib.uni | 117 ++
> ShellPkg/ShellPkg.dec | 1 +
> ShellPkg/ShellPkg.dsc | 4 +
> 9 files changed, 4146 insertions(+)
> create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> create mode 100644
> ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> create mode 100644
> ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> create mode 100644
> ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> create mode 100644
> ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> create mode 100644
> ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> create mode 100644
> ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
>
> diff --git a/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> new file mode 100644
> index 000000000000..ba7904e6be28
> --- /dev/null
> +++ b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> @@ -0,0 +1,611 @@
> +/** @file
> +
> + Copyright (c) 2003 - 2012, Rob Riglar, Ultra-Embedded.com. All rights
> reserved<BR>
> +
> + This program and the accompanying materials
> + are licensed and made available under the terms and conditions of the BSD
> License
> + which accompanies this distribution. The full text of the license may be
> found at
> + http://opensource.org/licenses/bsd-license.php
> +
> + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +/* Portions Copyright (c) 2016, Broadcom. All rights reserved */
> +
> +#include "FatFormat.h"
> +
> +//-----------------------------------------------------------------------------
> +// Tables
> +//-----------------------------------------------------------------------------
> +typedef struct
> +{
> + UINT64 Sectors;
> + UINT8 SectorsPerCluster;
> +} SectorsPerClusterTable;
> +
> +STATIC SectorsPerClusterTable ClusterSizeTable16[] =
> +{
> + { 32680, 2 }, // 16MB - 1K
> + { 262144, 4 }, // 128MB - 2K
> + { 524288, 8 }, // 256MB - 4K
> + { 1048576, 16 }, // 512MB - 8K
> + { 2097152, 32 }, // 1GB - 16K
> + { 4194304, 64 }, // 2GB - 32K
> + { 8388608, 128 }, // 2GB - 64K [Warning only supported by Windows XP
> onwards]
> + { 0, 0 } // Invalid
> +};
> +
> +STATIC SectorsPerClusterTable ClusterSizeTable32[] =
> +{
> + { 532480, 1 }, // 260MB - 512b
> + { 16777216, 8 }, // 8GB - 4K
> + { 33554432, 16 }, // 16GB - 8K
> + { 67108864, 32 }, // 32GB - 16K
> + { 0xFFFFFFFF, 64 }, // >32GB - 32K
> + { 0, 0 } // Invalid
> +};
> +
> +STATIC
> +EFI_LBA LbaOfCluster (
> + IN FATFS *Fs,
> + IN UINT64 ClusterNumber
> + )
> +{
> + if (Fs->FatType == FAT_TYPE_16)
> + return (Fs->ClusterBeginLba +
> + (Fs->RootEntryCount * 32 / FAT_SECTOR_SIZE) +
> + ((ClusterNumber - 2) * Fs->SectorsPerCluster));
> + else
> + return ((Fs->ClusterBeginLba +
> + ((ClusterNumber - 2) * Fs->SectorsPerCluster)));
> +}
> +
> +//-----------------------------------------------------------------------------
> +// fatfs_calc_cluster_size: Calculate what cluster size should be used
> +//-----------------------------------------------------------------------------
> +STATIC
> +UINT8 CalcClusterSize (
> + IN UINTN Sectors,
> + IN BOOLEAN IsFat32)
> +{
> + UINTN Index;
> +
> + if (!IsFat32) {
> + for (Index = 0; ClusterSizeTable16[Index].SectorsPerCluster != 0; Index++)
> + if (Sectors <= ClusterSizeTable16[Index].Sectors)
> + return ClusterSizeTable16[Index].SectorsPerCluster;
> + } else {
> + for (Index = 0; ClusterSizeTable32[Index].SectorsPerCluster != 0; Index++)
> + if (Sectors <= ClusterSizeTable32[Index].Sectors)
> + return ClusterSizeTable32[Index].SectorsPerCluster;
> + }
> +
> + return 0;
> +}
> +//-----------------------------------------------------------------------------
> +// fatfs_erase_sectors: Erase a number of sectors
> +//-----------------------------------------------------------------------------
> +STATIC
> +EFI_STATUS
> +EraseSectors (
> + IN FATFS *Fs,
> + IN EFI_LBA Lba,
> + IN UINTN Count
> + )
> +{
> + UINTN Index;
> + EFI_STATUS Status;
> +
> + // Zero Sector first
> + ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE);
> +
> + for (Index = 0; Index < Count; Index++)
> + Status = Fs->DiskIo->WriteDisk (
> + Fs->DiskIo, Fs->BlockIo->Media->MediaId,
> + MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) +
> + MultU64x32 ((Lba + Index), FAT_SECTOR_SIZE),
> + FAT_SECTOR_SIZE, Fs->CurrentSector.Sector);
> +
> + return Status;
> +}
> +//-----------------------------------------------------------------------------
> +// fatfs_create_boot_sector: Create the boot Sector
> +//-----------------------------------------------------------------------------
> +STATIC
> +EFI_STATUS
> +CreateBootSector (
> + IN FATFS *Fs,
> + IN EFI_LBA BootSectorLba,
> + IN UINT64 VolSectors,
> + IN CONST CHAR8 *Name,
> + IN BOOLEAN IsFat32
> + )
> +{
> + UINTN TotalClusters;
> + UINTN Index;
> + EFI_STATUS Status;
> +
> + // Zero Sector initially
> + ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE);
> +
> + // OEM Name & Jump Code
> + Fs->CurrentSector.Sector[0] = 0xEB;
> + Fs->CurrentSector.Sector[1] = 0x3C;
> + Fs->CurrentSector.Sector[2] = 0x90;
> + Fs->CurrentSector.Sector[3] = 0x4D;
> + Fs->CurrentSector.Sector[4] = 0x53;
> + Fs->CurrentSector.Sector[5] = 0x44;
> + Fs->CurrentSector.Sector[6] = 0x4F;
> + Fs->CurrentSector.Sector[7] = 0x53;
> + Fs->CurrentSector.Sector[8] = 0x35;
> + Fs->CurrentSector.Sector[9] = 0x2E;
> + Fs->CurrentSector.Sector[10] = 0x30;
> +
> + // Bytes per Sector
> + Fs->CurrentSector.Sector[11] = (FAT_SECTOR_SIZE >> 0) & 0xFF;
> + Fs->CurrentSector.Sector[12] = (FAT_SECTOR_SIZE >> 8) & 0xFF;
> +
> + // Get sectors per cluster size for the disk
> + Fs->SectorsPerCluster = CalcClusterSize (VolSectors, IsFat32);
> + if (!Fs->SectorsPerCluster)
> + return 0; // Invalid disk size
> +
> + // Sectors per cluster
> + Fs->CurrentSector.Sector[13] = Fs->SectorsPerCluster;
> +
> + // Reserved Sectors
> + if (!IsFat32)
> + Fs->ReservedSectors = 8;
> + else
> + Fs->ReservedSectors = 32;
> + Fs->CurrentSector.Sector[14] = (Fs->ReservedSectors >> 0) & 0xFF;
> + Fs->CurrentSector.Sector[15] = (Fs->ReservedSectors >> 8) & 0xFF;
> +
> + // Number of FATS
> + Fs->NumOfFats = 2;
> + Fs->CurrentSector.Sector[16] = Fs->NumOfFats;
> +
> + // Max entries in root dir (FAT16 only)
> + if (!IsFat32) {
> + Fs->RootEntryCount = 512;
> + Fs->CurrentSector.Sector[17] = (Fs->RootEntryCount >> 0) & 0xFF;
> + Fs->CurrentSector.Sector[18] = (Fs->RootEntryCount >> 8) & 0xFF;
> + } else {
> + Fs->RootEntryCount = 0;
> + Fs->CurrentSector.Sector[17] = 0;
> + Fs->CurrentSector.Sector[18] = 0;
> + }
> +
> + // [FAT16] Total sectors (use FAT32 count instead)
> + Fs->CurrentSector.Sector[19] = 0x00;
> + Fs->CurrentSector.Sector[20] = 0x00;
> +
> + // Media type
> + Fs->CurrentSector.Sector[21] = 0xF8;
> +
> +
> + // FAT16 BS Details
> + if (!IsFat32) {
> + // Count of sectors used by the FAT table (FAT16 only)
> + TotalClusters = (VolSectors / Fs->SectorsPerCluster) + 1;
> + Fs->FatSectors = (TotalClusters / (FAT_SECTOR_SIZE / 2)) + 1;
> + Fs->CurrentSector.Sector[22] = (UINT8)((Fs->FatSectors >> 0) & 0xFF);
> + Fs->CurrentSector.Sector[23] = (UINT8)((Fs->FatSectors >> 8) & 0xFF);
> +
> + // Sectors per track
> + Fs->CurrentSector.Sector[24] = 0x00;
> + Fs->CurrentSector.Sector[25] = 0x00;
> +
> + // Heads
> + Fs->CurrentSector.Sector[26] = 0x00;
> + Fs->CurrentSector.Sector[27] = 0x00;
> +
> + // Hidden sectors
> + Fs->CurrentSector.Sector[28] = 0x20;
> + Fs->CurrentSector.Sector[29] = 0x00;
> + Fs->CurrentSector.Sector[30] = 0x00;
> + Fs->CurrentSector.Sector[31] = 0x00;
> +
> + // Total sectors for this volume
> + Fs->CurrentSector.Sector[32] = (UINT8)((VolSectors >> 0) & 0xFF);
> + Fs->CurrentSector.Sector[33] = (UINT8)((VolSectors >> 8) & 0xFF);
> + Fs->CurrentSector.Sector[34] = (UINT8)((VolSectors >> 16) & 0xFF);
> + Fs->CurrentSector.Sector[35] = (UINT8)((VolSectors >> 24) & 0xFF);
> +
> + // Drive number
> + Fs->CurrentSector.Sector[36] = 0x00;
> +
> + // Reserved
> + Fs->CurrentSector.Sector[37] = 0x00;
> +
> + // Boot signature
> + Fs->CurrentSector.Sector[38] = 0x29;
> +
> + // Volume ID
> + Fs->CurrentSector.Sector[39] = 0x12;
> + Fs->CurrentSector.Sector[40] = 0x34;
> + Fs->CurrentSector.Sector[41] = 0x56;
> + Fs->CurrentSector.Sector[42] = 0x78;
> +
> + // Volume name
> + for (Index = 0; Index < 11; Index++) {
> + if (Index < AsciiStrLen (Name))
> + Fs->CurrentSector.Sector[Index + 43] = Name[Index];
> + else
> + Fs->CurrentSector.Sector[Index + 43] = ' ';
> + }
> +
> + // File sys type
> + Fs->CurrentSector.Sector[54] = 'F';
> + Fs->CurrentSector.Sector[55] = 'A';
> + Fs->CurrentSector.Sector[56] = 'T';
> + Fs->CurrentSector.Sector[57] = '1';
> + Fs->CurrentSector.Sector[58] = '6';
> + Fs->CurrentSector.Sector[59] = ' ';
> + Fs->CurrentSector.Sector[60] = ' ';
> + Fs->CurrentSector.Sector[61] = ' ';
> +
> + // Signature
> + Fs->CurrentSector.Sector[510] = 0x55;
> + Fs->CurrentSector.Sector[511] = 0xAA;
> + }
> + // FAT32 BS Details
> + else {
> + // Count of sectors used by the FAT table (FAT16 only)
> + Fs->CurrentSector.Sector[22] = 0;
> + Fs->CurrentSector.Sector[23] = 0;
> +
> + // Sectors per track (default)
> + Fs->CurrentSector.Sector[24] = 0x3F;
> + Fs->CurrentSector.Sector[25] = 0x00;
> +
> + // Heads (default)
> + Fs->CurrentSector.Sector[26] = 0xFF;
> + Fs->CurrentSector.Sector[27] = 0x00;
> +
> + // Hidden sectors
> + Fs->CurrentSector.Sector[28] = 0x00;
> + Fs->CurrentSector.Sector[29] = 0x00;
> + Fs->CurrentSector.Sector[30] = 0x00;
> + Fs->CurrentSector.Sector[31] = 0x00;
> +
> + // Total sectors for this volume
> + Fs->CurrentSector.Sector[32] = (UINT8)((VolSectors >> 0) & 0xFF);
> + Fs->CurrentSector.Sector[33] = (UINT8)((VolSectors >> 8) & 0xFF);
> + Fs->CurrentSector.Sector[34] = (UINT8)((VolSectors >> 16) & 0xFF);
> + Fs->CurrentSector.Sector[35] = (UINT8)((VolSectors >> 24) & 0xFF);
> +
> + TotalClusters = (VolSectors / Fs->SectorsPerCluster) + 1;
> + Fs->FatSectors = (TotalClusters / (FAT_SECTOR_SIZE / 4)) + 1;
> +
> + // BPB_FATSz32
> + Fs->CurrentSector.Sector[36] = (UINT8)((Fs->FatSectors >> 0) & 0xFF);
> + Fs->CurrentSector.Sector[37] = (UINT8)((Fs->FatSectors >> 8) & 0xFF);
> + Fs->CurrentSector.Sector[38] = (UINT8)((Fs->FatSectors >> 16) & 0xFF);
> + Fs->CurrentSector.Sector[39] = (UINT8)((Fs->FatSectors >> 24) & 0xFF);
> +
> + // BPB_ExtFlags
> + Fs->CurrentSector.Sector[40] = 0;
> + Fs->CurrentSector.Sector[41] = 0;
> +
> + // BPB_FSVer
> + Fs->CurrentSector.Sector[42] = 0;
> + Fs->CurrentSector.Sector[43] = 0;
> +
> + // BPB_RootClus
> + Fs->CurrentSector.Sector[44] = (UINT8)((Fs->RootdirFirstCluster >> 0) &
> 0xFF);
> + Fs->CurrentSector.Sector[45] = (UINT8)((Fs->RootdirFirstCluster >> 8) &
> 0xFF);
> + Fs->CurrentSector.Sector[46] = (UINT8)((Fs->RootdirFirstCluster >> 16) &
> 0xFF);
> + Fs->CurrentSector.Sector[47] = (UINT8)((Fs->RootdirFirstCluster >> 24) &
> 0xFF);
> +
> + // BPB_FSInfo
> + Fs->CurrentSector.Sector[48] = (UINT8)((Fs->FsInfoSector >> 0) & 0xFF);
> + Fs->CurrentSector.Sector[49] = (UINT8)((Fs->FsInfoSector >> 8) & 0xFF);
> +
> + // BPB_BkBootSec
> + Fs->CurrentSector.Sector[50] = 6;
> + Fs->CurrentSector.Sector[51] = 0;
> +
> + // Drive number
> + Fs->CurrentSector.Sector[64] = 0x00;
> +
> + // Boot signature
> + Fs->CurrentSector.Sector[66] = 0x29;
> +
> + // Volume ID
> + Fs->CurrentSector.Sector[67] = 0x12;
> + Fs->CurrentSector.Sector[68] = 0x34;
> + Fs->CurrentSector.Sector[69] = 0x56;
> + Fs->CurrentSector.Sector[70] = 0x78;
> +
> + // Volume name
> + for (Index = 0; Index < 11; Index++) {
> + if (Index < (int)AsciiStrLen (Name))
> + Fs->CurrentSector.Sector[Index + 71] = Name[Index];
> + else
> + Fs->CurrentSector.Sector[Index + 71] = ' ';
> + }
> +
> + // File sys type
> + Fs->CurrentSector.Sector[82] = 'F';
> + Fs->CurrentSector.Sector[83] = 'A';
> + Fs->CurrentSector.Sector[84] = 'T';
> + Fs->CurrentSector.Sector[85] = '3';
> + Fs->CurrentSector.Sector[86] = '2';
> + Fs->CurrentSector.Sector[87] = ' ';
> + Fs->CurrentSector.Sector[88] = ' ';
> + Fs->CurrentSector.Sector[89] = ' ';
> +
> + // Signature
> + Fs->CurrentSector.Sector[510] = 0x55;
> + Fs->CurrentSector.Sector[511] = 0xAA;
> + }
> +
> + Status = Fs->DiskIo->WriteDisk (
> + Fs->DiskIo, Fs->BlockIo->Media->MediaId,
> + MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) +
> + MultU64x32 (Fs->FatBeginLba, FAT_SECTOR_SIZE),
> + FAT_SECTOR_SIZE,
> + Fs->CurrentSector.Sector);
> +
> + return Status;
> +}
> +//-----------------------------------------------------------------------------
> +// fatfs_create_fsinfo_sector: Create the FSInfo Sector (FAT32)
> +//-----------------------------------------------------------------------------
> +STATIC
> +EFI_STATUS
> +CreateFsinfoSector (
> + IN FATFS *Fs,
> + IN EFI_LBA SectorLba
> + )
> +{
> + EFI_STATUS Status;
> +
> + // Zero Sector initially
> + ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE);
> +
> + // FSI_LeadSig
> + Fs->CurrentSector.Sector[0] = 0x52;
> + Fs->CurrentSector.Sector[1] = 0x52;
> + Fs->CurrentSector.Sector[2] = 0x61;
> + Fs->CurrentSector.Sector[3] = 0x41;
> +
> + // FSI_StrucSig
> + Fs->CurrentSector.Sector[484] = 0x72;
> + Fs->CurrentSector.Sector[485] = 0x72;
> + Fs->CurrentSector.Sector[486] = 0x41;
> + Fs->CurrentSector.Sector[487] = 0x61;
> +
> + // FSI_Free_Count
> + Fs->CurrentSector.Sector[488] = 0xFF;
> + Fs->CurrentSector.Sector[489] = 0xFF;
> + Fs->CurrentSector.Sector[490] = 0xFF;
> + Fs->CurrentSector.Sector[491] = 0xFF;
> +
> + // FSI_Nxt_Free
> + Fs->CurrentSector.Sector[492] = 0xFF;
> + Fs->CurrentSector.Sector[493] = 0xFF;
> + Fs->CurrentSector.Sector[494] = 0xFF;
> + Fs->CurrentSector.Sector[495] = 0xFF;
> +
> + // Signature
> + Fs->CurrentSector.Sector[510] = 0x55;
> + Fs->CurrentSector.Sector[511] = 0xAA;
> +
> + Status = Fs->DiskIo->WriteDisk (
> + Fs->DiskIo, Fs->BlockIo->Media->MediaId,
> + MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) +
> + MultU64x32 (SectorLba, FAT_SECTOR_SIZE),
> + FAT_SECTOR_SIZE,
> + Fs->CurrentSector.Sector);
> +
> + return Status;
> +}
> +//-----------------------------------------------------------------------------
> +// fatfs_erase_fat: Erase FAT table using fs details in fs struct
> +//-----------------------------------------------------------------------------
> +STATIC
> +EFI_STATUS
> +EraseFat (
> + IN FATFS *Fs,
> + IN BOOLEAN IsFat32)
> +{
> + UINTN Index;
> + EFI_STATUS Status;
> +
> + // Zero Sector initially
> + ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE);
> +
> + // Initialise default allocate / reserved clusters
> + if (!IsFat32) {
> + SET_16BIT_WORD (Fs->CurrentSector.Sector, 0, 0xFFF8);
> + SET_16BIT_WORD (Fs->CurrentSector.Sector, 2, 0xFFFF);
> + } else {
> + SET_32BIT_WORD (Fs->CurrentSector.Sector, 0, 0x0FFFFFF8);
> + SET_32BIT_WORD (Fs->CurrentSector.Sector, 4, 0xFFFFFFFF);
> + SET_32BIT_WORD (Fs->CurrentSector.Sector, 8, 0x0FFFFFFF);
> + }
> +
> + Status = Fs->DiskIo->WriteDisk (
> + Fs->DiskIo, Fs->BlockIo->Media->MediaId,
> + MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) +
> + MultU64x32 (Fs->FatBeginLba, FAT_SECTOR_SIZE),
> + FAT_SECTOR_SIZE,
> + Fs->CurrentSector.Sector);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + // Zero remaining FAT sectors
> + ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE);
> + for (Index = 1; Index < Fs->FatSectors * Fs->NumOfFats; Index++) {
> + Status = Fs->DiskIo->WriteDisk (
> + Fs->DiskIo,
> + Fs->BlockIo->Media->MediaId,
> + MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) +
> + MultU64x32 ((Fs->FatBeginLba + Index), FAT_SECTOR_SIZE),
> + FAT_SECTOR_SIZE,
> + Fs->CurrentSector.Sector);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + }
> + return Status;
> +}
> +//-----------------------------------------------------------------------------
> +// fatfs_format_fat16: Format a FAT16 partition
> +//-----------------------------------------------------------------------------
> +STATIC
> +EFI_STATUS
> +FormatFat16 (
> + IN FATFS *Fs,
> + IN UINT64 VolumeSectors,
> + IN CONST CHAR8 *Name
> + )
> +{
> + EFI_STATUS Status;
> +
> + Fs->CurrentSector.Address = FAT32_INVALID_CLUSTER;
> + Fs->CurrentSector.Dirty = 0;
> +
> + Fs->NextFreeCluster = 0; // Invalid
> +
> + // Volume is FAT16
> + Fs->FatType = FAT_TYPE_16;
> +
> + // Not valid for FAT16
> + Fs->FsInfoSector = 0;
> + Fs->RootdirFirstCluster = 0;
> +
> + Fs->LbaBegin = 0;
> + Status = CreateBootSector (Fs, Fs->LbaBegin, VolumeSectors, Name, 0);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + // For FAT16 (which this may be), RootdirFirstCluster is actuall
> RootdirFirstSector
> + Fs->RootdirFirstSector = Fs->ReservedSectors + (Fs->NumOfFats * Fs-
> >FatSectors);
> + Fs->RootdirSectors = ((Fs->RootEntryCount * 32) +
> + (FAT_SECTOR_SIZE - 1)) / FAT_SECTOR_SIZE;
> +
> + // First FAT LBA Address
> + Fs->FatBeginLba = Fs->LbaBegin + Fs->ReservedSectors;
> +
> + // The Address of the first data cluster on this volume
> + Fs->ClusterBeginLba = Fs->FatBeginLba +
> + (Fs->NumOfFats * Fs->FatSectors);
> +
> + // Initialise FAT sectors
> + Status = EraseFat (Fs, 0);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + // Erase Root directory
> + Status = EraseSectors (
> + Fs,
> + Fs->LbaBegin + Fs->RootdirFirstSector,
> + Fs->RootdirSectors);
> +
> + return Status;
> +}
> +//-----------------------------------------------------------------------------
> +// fatfs_format_fat32: Format a FAT32 partition
> +//-----------------------------------------------------------------------------
> +STATIC
> +EFI_STATUS
> +FormatFat32 (
> + IN FATFS *Fs,
> + IN UINTN VolumeSectors,
> + IN CONST CHAR8 *Name
> + )
> +{
> + EFI_STATUS Status;
> +
> + Fs->CurrentSector.Address = FAT32_INVALID_CLUSTER;
> + Fs->CurrentSector.Dirty = 0;
> +
> + Fs->NextFreeCluster = 0; // Invalid
> +
> + // Volume is FAT32
> + Fs->FatType = FAT_TYPE_32;
> +
> + // Basic defaults for normal FAT32 partitions
> + Fs->FsInfoSector = 1;
> + Fs->RootdirFirstCluster = 2;
> +
> + // Sector 0: Boot Sector
> + // NOTE: We don't need an MBR, it is a waste of a good Sector!
> + Fs->LbaBegin = 0;
> + Status = CreateBootSector (Fs, Fs->LbaBegin, VolumeSectors, Name, 1);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + // First FAT LBA address
> + Fs->FatBeginLba = Fs->LbaBegin + Fs->ReservedSectors;
> +
> + // The address of the first data cluster on this volume
> + Fs->ClusterBeginLba = Fs->FatBeginLba + (Fs->NumOfFats * Fs-
> >FatSectors);
> +
> + // Initialise FSInfo sector
> + Status = CreateFsinfoSector (Fs, Fs->FsInfoSector);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + // Initialise FAT sectors
> + Status = EraseFat (Fs, 1);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + // Erase Root directory
> + Status = EraseSectors (
> + Fs,
> + LbaOfCluster (Fs, Fs->RootdirFirstCluster),
> + Fs->SectorsPerCluster);
> +
> + return Status;
> +}
> +//-----------------------------------------------------------------------------
> +// fatfs_format: Format a partition with either FAT16 or FAT32 based on size
> +//-----------------------------------------------------------------------------
> +EFI_STATUS
> +FatFormat (
> + IN EFI_LBA StartingLBA,
> + IN EFI_LBA EndingLBA,
> + IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
> + IN EFI_DISK_IO_PROTOCOL *DiskIo,
> + IN CHAR8 *VolumeName,
> + IN BOOLEAN ForceFat32
> + )
> +{
> + FATFS Fs;
> + UINT64 VolumeSectors;
> +
> + VolumeSectors = DivU64x32 (
> + MultU64x32 (
> + EndingLBA - StartingLBA + 1, BlockIo->Media->BlockSize),
> + FAT_SECTOR_SIZE);
> +
> + if (VolumeName == NULL) {
> + VolumeName = DEFAULT_FAT_LABEL_NAME;
> + }
> +
> + ZeroMem (&Fs, sizeof(Fs));
> +
> + Fs.StartingLBA = StartingLBA;
> + Fs.EndingLBA = EndingLBA;
> + Fs.BlockIo = BlockIo;
> + Fs.DiskIo = DiskIo;
> + // 2GB - 32K limit for safe behaviour for FAT16
> + if ((VolumeSectors <= 4194304) && (!ForceFat32)) {
> + return FormatFat16 (&Fs, VolumeSectors, VolumeName);
> + } else {
> + return FormatFat32 (&Fs, VolumeSectors, VolumeName);
> + }
> +}
> diff --git a/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> new file mode 100644
> index 000000000000..d1a325a57abe
> --- /dev/null
> +++ b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> @@ -0,0 +1,111 @@
> +/** @file
> +
> + Copyright (c) 2003 - 2012, Ultra-Embedded.com. All rights reserved<BR>
> +
> + This program and the accompanying materials
> + are licensed and made available under the terms and conditions of the BSD
> License
> + which accompanies this distribution. The full text of the license may be
> found at
> + http://opensource.org/licenses/bsd-license.php
> +
> + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +/* Portions Copyright (c) 2016, Broadcom. All rights reserved */
> +
> +#ifndef __FAT_FORMAT_H__
> +#define __FAT_FORMAT_H__
> +
> +#include "GptWorker.h"
> +
> +#define FAT_SECTOR_SIZE 512
> +#define FAT_BUFFER_SECTORS 1
> +#define FAT32_LAST_CLUSTER 0xFFFFFFFF
> +#define FAT32_INVALID_CLUSTER 0xFFFFFFFF
> +#define FAT_DIR_ENTRY_SIZE 32
> +#define FAT_BUFFERS 1
> +#define DEFAULT_FAT_LABEL_NAME "EFIVOL"
> +
> +#define GET_32BIT_WORD(Buffer, Location)
> ( ((UINT32)Buffer[Location + 3] << 24) + \
> + ((UINT32)Buffer[Location + 2] <<16 ) + \
> + ((UINT32)Buffer[Location + 1] << 8) + \
> + (UINT32)Buffer[Location+0] )
> +
> +#define GET_16BIT_WORD(Buffer, Location)
> ( ((UINT16)Buffer[Location + 1] << 8) + \
> + (UINT16)Buffer[Location+0])
> +
> +#define SET_32BIT_WORD(Buffer, Location, Value) { Buffer[Location + 0] =
> (UINT8)((Value) & 0xFF); \
> + Buffer[Location + 1] = (UINT8)((Value >> 8) & 0xFF);
> \
> + Buffer[Location + 2] = (UINT8)((Value >> 16) &
> 0xFF); \
> + Buffer[Location + 3] = (UINT8)((Value >> 24) &
> 0xFF); }
> +
> +#define SET_16BIT_WORD(Buffer, Location, Value) { Buffer[Location + 0] =
> (UINT8)((Value) & 0xFF); \
> + Buffer[Location + 1] = (UINT8)((Value >> 8) &
> 0xFF); }
> +
> +typedef enum eFatType
> +{
> + FAT_TYPE_16,
> + FAT_TYPE_32
> +} FAT_FS_TYPE;
> +
> +
> +// Forward declaration
> +typedef struct _FAT_BUFFER FAT_BUFFER;
> +
> +struct _FAT_BUFFER {
> + UINT8 Sector[FAT_SECTOR_SIZE * FAT_BUFFER_SECTORS];
> + UINTN Address;
> + BOOLEAN Dirty;
> + UINT8 *Ptr;
> +
> + // Next in chain of sector buffers
> + struct FAT_BUFFER *NextBuf;
> +};
> +
> +typedef struct
> +{
> + // Filesystem globals
> + UINT8 SectorsPerCluster;
> + EFI_LBA ClusterBeginLba;
> + UINTN RootdirFirstCluster;
> + UINTN RootdirFirstSector;
> + UINTN RootdirSectors;
> + EFI_LBA FatBeginLba;
> + UINT16 FsInfoSector;
> + EFI_LBA LbaBegin;
> + UINTN FatSectors;
> + UINTN NextFreeCluster;
> + UINT16 RootEntryCount;
> + UINT16 ReservedSectors;
> + UINT8 NumOfFats;
> + FAT_FS_TYPE FatType;
> +
> + // Working buffer
> + FAT_BUFFER CurrentSector;
> + // FAT Buffer
> + FAT_BUFFER *FatBufferHead;
> + FAT_BUFFER FatBuffers[FAT_BUFFERS];
> + EFI_LBA StartingLBA;
> + EFI_LBA EndingLBA;
> + EFI_BLOCK_IO_PROTOCOL *BlockIo;
> + EFI_DISK_IO_PROTOCOL *DiskIo;
> +
> +} FATFS;
> +
> +
> +
> +//-----------------------------------------------------------------------------
> +// Prototypes
> +//-----------------------------------------------------------------------------
> +EFI_STATUS
> +FatFormat (
> + IN EFI_LBA StartingLBA,
> + IN EFI_LBA EndingLBA,
> + IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
> + IN EFI_DISK_IO_PROTOCOL *DiskIo,
> + IN CHAR8 *VolumeName,
> + IN BOOLEAN ForceFat32
> + );
> +
> +#endif
> diff --git a/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> new file mode 100644
> index 000000000000..0546c94488b0
> --- /dev/null
> +++ b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> @@ -0,0 +1,1902 @@
> +/** @file
> +Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2016, Broadcom. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution. The full text of the license may be
> found at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#include "GptWorker.h"
> +
> +#define GPT_DEBUG_LEVEL 0
> +
> +STATIC EFI_PARTITION_TABLE_HEADER *PrimaryHeader = NULL;
> +STATIC EFI_PARTITION_TABLE_HEADER *BackupHeader = NULL;
> +STATIC EFI_PARTITION_ENTRY *PartEntry = NULL;
> +STATIC EFI_PARTITION_ENTRY_STATUS *PEntryStatus = NULL;
> +
> +STATIC EFI_BLOCK_IO_PROTOCOL *BlockIo;
> +STATIC EFI_DISK_IO_PROTOCOL *DiskIo;
> +
> +STATIC BOOLEAN MbrValid;
> +STATIC BOOLEAN GptValid;
> +
> +STATIC EFI_KNOWN_PARTITION_TYPE PartitionTypes[] =
> +{
> + // Known Partition type GUIDs
> + // Expand this table as needed.
> + // Starting with EFI System partition
> + { { 0xC12A7328L, 0xF81F, 0x11D2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9,
> 0x3B } }, L"EFI System" },
> + // Known Windows partition types
> + { { 0xE3C9E316L, 0x0B5C, 0x4DB8, { 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15,
> 0xAE } }, L"MS Windows Reserved (MSR)" },
> + { { 0xEBD0A0A2L, 0xB9E5, 0x4433, { 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99,
> 0xC7 } }, L"MS Windows Basic Data" },
> + { { 0x5808C8AAL, 0x7E8F, 0x42E0, { 0x85, 0xD2, 0xE1, 0xE9, 0x04, 0x34, 0xCF,
> 0xB3 } }, L"MS Windows LDM Metadata" },
> + { { 0xAF9B60A0L, 0x1431, 0x4F62, { 0xBC, 0x68, 0x33, 0x11, 0x71, 0x4A, 0x69,
> 0xAD } }, L"MS Windows LDM Data" },
> + { { 0xDE94BBA4L, 0x06D1, 0x4D40, { 0xA1, 0x6A, 0xBF, 0xD5, 0x01, 0x79,
> 0xD6, 0xAC } }, L"MS Windows Recovery Environment" },
> + { { 0xE75CAF8FL, 0xF680, 0x4CEE, { 0xAF, 0xA3, 0xB0, 0x01, 0xE5, 0x6E, 0xFC,
> 0x2D } }, L"MS Windows Storage Spaces" },
> + // Known Linux partition types
> + { { 0x0FC63DAFL, 0x8483, 0x4772, { 0x8E, 0x79, 0x3D, 0x69, 0xD8, 0x47, 0x7D,
> 0xE4 } }, L"Linux Filesystem Data" },
> + { { 0xA19D880FL, 0x05FC, 0x4D3B, { 0xA0, 0x06, 0x74, 0x3F, 0x0F, 0x84, 0x91,
> 0x1E } }, L"Linux RAID" },
> + { { 0x44479540L, 0xF297, 0x41B2, { 0x9A, 0xF7, 0xD1, 0x31, 0xD5, 0xF0, 0x45,
> 0x8A } }, L"Linux Root (x86)" },
> + { { 0x4F68BCE3L, 0xE8CD, 0x4DB1, { 0x96, 0xE7, 0xFB, 0xCA, 0xF9, 0x84, 0xB7,
> 0x09 } }, L"Linux Root (x86-64)" },
> + { { 0x69DAD710L, 0x2CE4, 0x4E3C, { 0xB1, 0x6C, 0x21, 0xA1, 0xD4, 0x9A,
> 0xBe, 0xD3 } }, L"Linux Root (ARM 32-bit)" },
> + { { 0xB921B045L, 0x1DF0, 0x41C3, { 0xAF, 0x44, 0x4C, 0x6F, 0x28, 0x0D, 0x3F,
> 0xAE } }, L"Linux Root (ARM 64-bit/AARCH64)" },
> + { { 0x0657FD6DL, 0xA4AB, 0x43C4, { 0x84, 0xE5, 0x09, 0x33, 0xC8, 0x4B, 0x4F,
> 0x4F } }, L"Linux Swap" },
> + { { 0xE6D6D379L, 0xF507, 0x44C2, { 0xA2, 0x3C, 0x23, 0x8F, 0x2A, 0x3D, 0xF9,
> 0x28 } }, L"Linux Logical Volume Manager (LVM)" },
> + { { 0x933AC7E1L, 0x2EB4, 0x4F13, { 0xB8, 0x44, 0x0E, 0x14, 0xE2, 0xAE, 0xF9,
> 0x15 } }, L"Linux /home" },
> + { { 0x3B8F8425L, 0x20E0, 0x4F3B, { 0x90, 0x7F, 0x1A, 0x25, 0xA7, 0x6F, 0x98,
> 0xE8 } }, L"Linux /srv (server data)" },
> + { { 0x7FFEC5C9L, 0x2D00, 0x49B7, { 0x89, 0x41, 0x3E, 0xA1, 0x0A, 0x55, 0x86,
> 0xB7 } }, L"Linux Plain dm-crypt" },
> + { { 0xCA7D7CCBL, 0x63ED, 0x4C53, { 0x86, 0x1C, 0x17, 0x42, 0x53, 0x60, 0x59,
> 0xCC } }, L"Linux LUKS" },
> + { { 0x8DA63339L, 0x0007, 0x60C0, { 0xC4, 0x36, 0x08, 0x3A, 0xC8, 0x23, 0x09,
> 0x08 } }, L"Linux Reserved" },
> +};
> +
> +MASTER_BOOT_RECORD ProtectiveMbrTemplate = {
> + { 0 }, // BoostStrapCode [440]
> + { 0 }, // UniqueMbrSignature[4] (unused)
> + { 0 }, // Unknown[2]
> +
> + // PARTITIONS
> + {
> + // MBR_PARTITION_RECORD
> + {
> + 0, // BootIndicator
> + 0, // StartHead
> + 0x1, // StartSector
> + 0x1, // StartTrack
> + PMBR_GPT_PARTITION, // OSIndicator
> + 0xff, // EndHead
> + 0xff, // EndSector
> + 0xff, // EndTrack
> + { 0x1, 0x0, 0x0, 0x0 }, // StartingLba[4]
> + { 0xff, 0xff, 0xff, 0xff }, // SizeInLba[4]
> + },
> + { 0 }, { 0 }, { 0 }, // Unused partitions
> + },
> +
> + MBR_SIGNATURE // Signature
> +};
> +
> +STATIC UINT32 CurRand = 1;
> +
> +/**
> + Get random seed based on the RTC
> +
> +**/
> +
> +STATIC
> +VOID
> +Srand (VOID)
> +{
> + EFI_TIME Time;
> + UINT32 Seed;
> + UINT64 MonotonicCount;
> +
> + gRT->GetTime (&Time, NULL);
> + Seed = (~Time.Hour << 24 | Time.Day << 16 | Time.Minute << 8 |
> Time.Second);
> + Seed ^= Time.Nanosecond;
> + Seed ^= Time.Year << 7;
> +
> + gBS->GetNextMonotonicCount (&MonotonicCount);
> + Seed += (UINT32)MonotonicCount;
> +
> + /* Store this seed */
> + CurRand = (UINT32)Seed;
> +}
> +
> +/**
> + Get a pseudo-random number
> +
> + @retval A pseudo-random number in the range 0 - 0x7fff
> +**/
> +
> +STATIC UINTN Rand (VOID)
> +{
> + /* return a pseudo-random in range 0 - 0x7fff */
> + return ((CurRand = CurRand * 214013L + 2531011L) >> 16) & 0x7fff;
> +}
> +
> +/**
> + Generate a GUID
> +
> + @param[in] Guid A pointer to a GUID receiving a generated value
> +**/
> +
> +STATIC VOID
> +GenerateGuid (OUT GUID *Guid)
> +{
> + UINTN Index;
> + UINT16 Buffer[sizeof(GUID)];
> +
> + /* Generates 128 random bits for new UUID */
> + for (Index = 0; Index < sizeof(GUID); Index++) {
> + UINTN V;
> +
> + V = Rand () >> 7;
> + Buffer[Index] = (UINT16)V;
> + }
> + /* set variant 10x and version 4 as required by RFC 4122 */
> + Buffer[8] = 0x80 | (Buffer[8] & 0x3f);
> + Buffer[6] = 0x40 | (Buffer[6] & 0xf);
> + CopyGuid (Guid, (CONST GUID *)Buffer);
> +}
> +
> +/**
> + Clean up globals
> +**/
> +VOID
> +GptCleanupGlobals (VOID)
> +{
> + SHELL_FREE_NON_NULL (PrimaryHeader);
> + SHELL_FREE_NON_NULL (BackupHeader);
> + SHELL_FREE_NON_NULL (PartEntry);
> + SHELL_FREE_NON_NULL (PEntryStatus);
> + GptValid = FALSE;
> + MbrValid = FALSE;
> +}
> +
> +/**
> + Caution: This function may receive untrusted input.
> + The GPT partition table header is external input, so this routine
> + will do basic validation for GPT partition table header before return.
> +
> + @param[in] Lba The starting Lba of the Partition Table
> + @param[out] PartHeader Stores the partition table that is read
> +
> + @retval EFI_SUCCESS The partition table is valid
> + @retval ERROR The partition table is not valid
> +
> +**/
> +STATIC
> +EFI_STATUS
> +PartitionValidGptTable (
> + IN EFI_LBA Lba,
> + OUT EFI_PARTITION_TABLE_HEADER *PartHeader
> + );
> +
> +/**
> + Check if the CRC field in the Partition table header is valid
> + for Partition entry array.
> +
> + @param[in] PartHeader Partition table header structure
> +
> + @retval TRUE the CRC is valid
> + @retval FALSE the CRC is invalid
> +
> +**/
> +STATIC
> +BOOLEAN
> +PartitionCheckGptEntryArrayCRC (
> + IN EFI_PARTITION_TABLE_HEADER *PartHeader
> + );
> +
> +
> +/**
> + Restore Partition Table to its alternate place
> + (Primary -> Backup or Backup -> Primary).
> +
> + @param[in] PartHeader Partition table header structure.
> +
> + @retval TRUE Restoring succeeds
> + @retval FALSE Restoring failed
> +
> +**/
> +STATIC
> +BOOLEAN
> +PartitionRestoreGptTable (
> + IN EFI_PARTITION_TABLE_HEADER *PartHeader
> + );
> +
> +
> +/**
> + This routine will check GPT partition entry and return entry status.
> +
> + Caution: This function may receive untrusted input.
> + The GPT partition entry is external input, so this routine
> + will do basic validation for GPT partition entry and report status.
> +
> + @param[in] PartHeader Partition table header structure
> + @param[in] PartEntry The partition entry array
> + @param[out] PEntryStatus the partition entry status array
> + recording the status of each partition
> +
> +**/
> +STATIC
> +VOID
> +PartitionCheckGptEntry (
> + IN EFI_PARTITION_TABLE_HEADER *PartHeader,
> + IN EFI_PARTITION_ENTRY *PartEntry,
> + OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus
> + );
> +
> +
> +/**
> + Checks the CRC32 value in the table header.
> +
> + @param MaxSize Max Size limit
> + @param Size The size of the table
> + @param Hdr Table to check
> +
> + @return TRUE CRC Valid
> + @return FALSE CRC Invalid
> +
> +**/
> +STATIC
> +BOOLEAN
> +PartitionCheckCrcAltSize (
> + IN UINTN MaxSize,
> + IN UINTN Size,
> + IN OUT EFI_TABLE_HEADER *Hdr
> + );
> +
> +
> +/**
> + Checks the CRC32 value in the table header.
> +
> + @param MaxSize Max Size limit
> + @param Hdr Table to check
> +
> + @return TRUE CRC Valid
> + @return FALSE CRC Invalid
> +
> +**/
> +STATIC
> +BOOLEAN
> +PartitionCheckCrc (
> + IN UINTN MaxSize,
> + IN OUT EFI_TABLE_HEADER *Hdr
> + );
> +
> +
> +/**
> + Updates the CRC32 value in the table header.
> +
> + @param Size The size of the table
> + @param Hdr Table to update
> +
> +**/
> +STATIC
> +VOID
> +PartitionSetCrcAltSize (
> + IN UINTN Size,
> + IN OUT EFI_TABLE_HEADER *Hdr
> + );
> +
> +
> +/**
> + Updates the CRC32 value in the table header.
> +
> + @param Hdr Table to update
> +
> +**/
> +STATIC
> +VOID
> +PartitionSetCrc (
> + IN OUT EFI_TABLE_HEADER *Hdr
> + );
> +
> +
> +/**
> + Get GPT tables.
> +
> + Caution: This function may receive untrusted input.
> + The GPT partition table is external input, so this routine
> + will do basic validation for GPT partition table before install
> + child handle for each GPT partition.
> +
> + @param[in] DiskIoProt DiskIo interface.
> + @param[in] BlockIoProt BlockIo interface.
> +
> + @retval EFI_SUCCESS Valid GPT disk.
> + @retval EFI_MEDIA_CHANGED Media changed Detected.
> + @retval other Not a valid GPT disk.
> +
> +**/
> +EFI_STATUS
> +PartitionGetGptTables (
> + IN EFI_DISK_IO_PROTOCOL *DiskIoProt,
> + IN EFI_BLOCK_IO_PROTOCOL *BlockIoProt
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 BlockSize;
> + EFI_LBA LastBlock;
> + UINTN Index;
> + EFI_STATUS GptValidStatus;
> + UINT32 MediaId;
> + MASTER_BOOT_RECORD *ProtectiveMbr;
> +
> + // Clear leftovers
> + GptCleanupGlobals ();
> +
> + MbrValid = FALSE;
> + GptValid = FALSE;
> +
> + ProtectiveMbr = NULL;
> +
> + BlockIo = BlockIoProt;
> + DiskIo = DiskIoProt;
> +
> + if (CurRand == 1) {
> + Srand ();
> + }
> +
> + BlockSize = BlockIo->Media->BlockSize;
> + LastBlock = BlockIo->Media->LastBlock;
> + MediaId = BlockIo->Media->MediaId;
> +
> + DEBUG ((EFI_D_VERBOSE, " BlockSize : %d \n", BlockSize));
> + DEBUG ((EFI_D_VERBOSE, " LastBlock : %lx \n", LastBlock));
> +
> + GptValidStatus = EFI_NOT_FOUND;
> + GptValid = FALSE;
> + MbrValid = FALSE;
> +
> + //
> + // Allocate a buffer for the Protective MBR
> + //
> + ProtectiveMbr = AllocatePool (BlockSize);
> + if (ProtectiveMbr == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + //
> + // Read the Protective MBR from LBA #0
> + //
> + Status = DiskIo->ReadDisk (
> + DiskIo,
> + MediaId,
> + 0,
> + BlockSize,
> + ProtectiveMbr
> + );
> + if (EFI_ERROR (Status)) {
> + GptValidStatus = Status;
> + goto Done;
> + }
> +
> + //
> + // Verify that the Protective MBR is valid
> + //
> + for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
> + if (ProtectiveMbr->Partition[Index].BootIndicator == 0x00 &&
> + ProtectiveMbr->Partition[Index].OSIndicator ==
> PMBR_GPT_PARTITION &&
> + UNPACK_UINT32 (ProtectiveMbr->Partition[Index].StartingLBA) == 1
> + ) {
> + break;
> + }
> + }
> + if (Index == MAX_MBR_PARTITIONS) {
> + goto Done;
> + }
> +
> + MbrValid = TRUE;
> +
> + //
> + // Allocate the GPT structures
> + //
> + PrimaryHeader = AllocateZeroPool
> (sizeof(EFI_PARTITION_TABLE_HEADER));
> + if (PrimaryHeader == NULL) {
> + goto Done;
> + }
> +
> + BackupHeader = AllocateZeroPool
> (sizeof(EFI_PARTITION_TABLE_HEADER));
> + if (BackupHeader == NULL) {
> + goto Done;
> + }
> +
> + //
> + // Check primary and backup partition tables
> + //
> + Status = PartitionValidGptTable (PRIMARY_PART_HEADER_LBA,
> PrimaryHeader);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((EFI_D_INFO, " Not Valid primary partition table\n"));
> +
> + Status = PartitionValidGptTable (LastBlock, BackupHeader);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((EFI_D_INFO, " Not Valid backup partition table\n"));
> + goto Done;
> + } else {
> + DEBUG ((EFI_D_INFO, " Valid backup partition table\n"));
> + DEBUG ((EFI_D_INFO, " Restore primary partition table by the
> backup\n"));
> + if (!PartitionRestoreGptTable (BackupHeader)) {
> + DEBUG ((EFI_D_INFO, " Restore primary partition table error\n"));
> + }
> +
> + Status = PartitionValidGptTable (BackupHeader->AlternateLBA,
> PrimaryHeader);
> + if (!EFI_ERROR (Status)) {
> + DEBUG ((EFI_D_INFO, " Restore backup partition table success\n"));
> + }
> + }
> + } else if (EFI_ERROR (PartitionValidGptTable (PrimaryHeader-
> >AlternateLBA, BackupHeader))) {
> + DEBUG ((EFI_D_INFO, " Valid primary and !Valid backup partition
> table\n"));
> + DEBUG ((EFI_D_INFO, " Restore backup partition table by the
> primary\n"));
> + if (!PartitionRestoreGptTable (PrimaryHeader)) {
> + DEBUG ((EFI_D_INFO, " Restore backup partition table error\n"));
> + }
> +
> + Status = PartitionValidGptTable (PrimaryHeader->AlternateLBA,
> BackupHeader);
> + if (!EFI_ERROR (Status)) {
> + DEBUG ((EFI_D_INFO, " Restore backup partition table success\n"));
> + }
> + }
> +
> + DEBUG ((EFI_D_VERBOSE, " Valid primary and Valid backup partition
> table\n"));
> +
> + //
> + // Read the EFI Partition Entries
> + //
> + PartEntry = AllocatePool (PrimaryHeader->NumberOfPartitionEntries *
> PrimaryHeader->SizeOfPartitionEntry);
> + if (PartEntry == NULL) {
> + DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
> + goto Done;
> + }
> +
> + Status = DiskIo->ReadDisk (
> + DiskIo,
> + MediaId,
> + MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockSize),
> + PrimaryHeader->NumberOfPartitionEntries * (PrimaryHeader-
> >SizeOfPartitionEntry),
> + PartEntry
> + );
> + if (EFI_ERROR (Status)) {
> + GptValidStatus = Status;
> + DEBUG ((EFI_D_ERROR, " Partition Entry ReadDisk error\n"));
> + goto Done;
> + }
> +
> + DEBUG ((EFI_D_VERBOSE, " Partition entries read block success\n"));
> +
> + DEBUG ((EFI_D_VERBOSE, " Number of partition entries: %d\n",
> PrimaryHeader->NumberOfPartitionEntries));
> +
> + PEntryStatus = AllocateZeroPool (PrimaryHeader-
> >NumberOfPartitionEntries * sizeof(EFI_PARTITION_ENTRY_STATUS));
> + if (PEntryStatus == NULL) {
> + DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
> + goto Done;
> + }
> +
> + //
> + // Check the integrity of partition entries
> + //
> + PartitionCheckGptEntry (PrimaryHeader, PartEntry, PEntryStatus);
> +
> + //
> + // If we got this far the GPT layout of the disk is valid and we should return
> true
> + //
> + GptValidStatus = EFI_SUCCESS;
> +
> + Done:
> + SHELL_FREE_NON_NULL (ProtectiveMbr);
> + if (EFI_ERROR (GptValidStatus)) {
> + SHELL_FREE_NON_NULL (PrimaryHeader);
> + SHELL_FREE_NON_NULL (BackupHeader);
> + SHELL_FREE_NON_NULL (PartEntry);
> + SHELL_FREE_NON_NULL (PEntryStatus);
> + } else {
> + GptValid = TRUE;
> + }
> +
> + return GptValidStatus;
> +}
> +
> +/**
> + This routine will read GPT partition table header and return it.
> +
> + Caution: This function may receive untrusted input.
> + The GPT partition table header is external input, so this routine
> + will do basic validation for GPT partition table header before return.
> +
> + @param[in] Lba The starting Lba of the Partition Table
> + @param[out] PartHeader Stores the partition table that is read
> +
> + @retval TRUE The partition table is valid
> + @retval FALSE The partition table is not valid
> +
> +**/
> +STATIC
> +EFI_STATUS
> +PartitionValidGptTable (
> + IN EFI_LBA Lba,
> + OUT EFI_PARTITION_TABLE_HEADER *PartHeader
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 BlockSize;
> + EFI_PARTITION_TABLE_HEADER *PartHdr;
> + UINT32 MediaId;
> +
> + BlockSize = BlockIo->Media->BlockSize;
> + MediaId = BlockIo->Media->MediaId;
> + PartHdr = AllocateZeroPool (BlockSize);
> +
> + if (PartHdr == NULL) {
> + DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
> + return EFI_OUT_OF_RESOURCES;
> + }
> + //
> + // Read the EFI Partition Table Header
> + //
> + Status = DiskIo->ReadDisk (
> + DiskIo,
> + MediaId,
> + MultU64x32 (Lba, BlockSize),
> + BlockSize,
> + PartHdr
> + );
> + if (EFI_ERROR (Status)) {
> + FreePool (PartHdr);
> + return Status;
> + }
> +
> + if ((PartHdr->Header.Signature != EFI_PTAB_HEADER_ID) ||
> + !PartitionCheckCrc (BlockSize, &PartHdr->Header) ||
> + PartHdr->MyLBA != Lba ||
> + (PartHdr->SizeOfPartitionEntry < sizeof(EFI_PARTITION_ENTRY))
> + ) {
> + DEBUG ((EFI_D_ERROR, "Invalid efi partition table header\n"));
> + FreePool (PartHdr);
> + return EFI_VOLUME_CORRUPTED;
> + }
> +
> + //
> + // Ensure the NumberOfPartitionEntries * SizeOfPartitionEntry doesn't
> overflow.
> + //
> + if (PartHdr->NumberOfPartitionEntries > DivU64x32 (MAX_UINTN,
> PartHdr->SizeOfPartitionEntry)) {
> + FreePool (PartHdr);
> + return EFI_VOLUME_CORRUPTED;
> + }
> +
> + CopyMem (PartHeader, PartHdr, sizeof(EFI_PARTITION_TABLE_HEADER));
> + if (!PartitionCheckGptEntryArrayCRC (PartHeader)) {
> + FreePool (PartHdr);
> + return EFI_VOLUME_CORRUPTED;
> + }
> +
> + DEBUG ((EFI_D_VERBOSE, " Valid efi partition table header\n"));
> + FreePool (PartHdr);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Check if the CRC field in the Partition table header is valid
> + for Partition entry array.
> +
> + @param[in] PartHeader Partition table header structure
> +
> + @retval TRUE the CRC is valid
> + @retval FALSE the CRC is invalid
> +
> +**/
> +STATIC
> +BOOLEAN
> +PartitionCheckGptEntryArrayCRC (
> + IN EFI_PARTITION_TABLE_HEADER *PartHeader
> + )
> +{
> + EFI_STATUS Status;
> + UINT8 *Ptr;
> + UINT32 Crc;
> + UINTN Size;
> +
> + //
> + // Read the EFI Partition Entries
> + //
> + Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader-
> >SizeOfPartitionEntry);
> + if (Ptr == NULL) {
> + DEBUG ((EFI_D_ERROR, " Allocate pool error\n"));
> + return FALSE;
> + }
> +
> + Status = DiskIo->ReadDisk (
> + DiskIo,
> + BlockIo->Media->MediaId,
> + MultU64x32 (PartHeader->PartitionEntryLBA, BlockIo->Media->BlockSize),
> + PartHeader->NumberOfPartitionEntries * PartHeader-
> >SizeOfPartitionEntry,
> + Ptr
> + );
> + if (EFI_ERROR (Status)) {
> + FreePool (Ptr);
> + return FALSE;
> + }
> +
> + Size = PartHeader->NumberOfPartitionEntries * PartHeader-
> >SizeOfPartitionEntry;
> +
> + Status = gBS->CalculateCrc32 (Ptr, Size, &Crc);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((EFI_D_ERROR, "CheckPEntryArrayCRC: Crc calculation failed\n"));
> + FreePool (Ptr);
> + return FALSE;
> + }
> +
> + FreePool (Ptr);
> +
> + return (BOOLEAN)(PartHeader->PartitionEntryArrayCRC32 == Crc);
> +}
> +
> +
> +/**
> + Restore Partition Table to its alternate place
> + (Primary -> Backup or Backup -> Primary).
> +
> + @param[in] PartHeader Partition table header structure.
> +
> + @retval TRUE Restoring succeeds
> + @retval FALSE Restoring failed
> +
> +**/
> +STATIC
> +BOOLEAN
> +PartitionRestoreGptTable (
> + IN EFI_PARTITION_TABLE_HEADER *PartHeader
> + )
> +{
> + EFI_STATUS Status;
> + UINTN BlockSize;
> + EFI_PARTITION_TABLE_HEADER *PartHdr;
> + EFI_LBA PEntryLBA;
> + UINT8 *Ptr;
> + UINT32 MediaId;
> +
> + PartHdr = NULL;
> + Ptr = NULL;
> +
> + BlockSize = BlockIo->Media->BlockSize;
> + MediaId = BlockIo->Media->MediaId;
> +
> + PartHdr = AllocateZeroPool (BlockSize);
> +
> + if (PartHdr == NULL) {
> + DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
> + return FALSE;
> + }
> +
> + PEntryLBA = (PartHeader->MyLBA == PRIMARY_PART_HEADER_LBA) ?\
> + (PartHeader->LastUsableLBA + 1) :\
> + (PRIMARY_PART_HEADER_LBA + 1);
> +
> + CopyMem (PartHdr, PartHeader, sizeof(EFI_PARTITION_TABLE_HEADER));
> +
> + PartHdr->MyLBA = PartHeader->AlternateLBA;
> + PartHdr->AlternateLBA = PartHeader->MyLBA;
> + PartHdr->PartitionEntryLBA = PEntryLBA;
> + PartitionSetCrc ((EFI_TABLE_HEADER *)PartHdr);
> +
> + Status = DiskIo->WriteDisk (
> + DiskIo,
> + MediaId,
> + MultU64x32 (PartHdr->MyLBA, (UINT32)BlockSize),
> + BlockSize,
> + PartHdr
> + );
> + if (EFI_ERROR (Status)) {
> + goto Done;
> + }
> +
> + Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader-
> >SizeOfPartitionEntry);
> + if (Ptr == NULL) {
> + DEBUG ((EFI_D_ERROR, " Allocate pool error\n"));
> + Status = EFI_OUT_OF_RESOURCES;
> + goto Done;
> + }
> +
> + Status = DiskIo->ReadDisk (
> + DiskIo,
> + MediaId,
> + MultU64x32 (PartHeader->PartitionEntryLBA, (UINT32)BlockSize),
> + PartHeader->NumberOfPartitionEntries * PartHeader-
> >SizeOfPartitionEntry,
> + Ptr
> + );
> + if (EFI_ERROR (Status)) {
> + goto Done;
> + }
> +
> + Status = DiskIo->WriteDisk (
> + DiskIo,
> + MediaId,
> + MultU64x32 (PEntryLBA, (UINT32)BlockSize),
> + PartHeader->NumberOfPartitionEntries * PartHeader-
> >SizeOfPartitionEntry,
> + Ptr
> + );
> +
> + Done:
> + FreePool (PartHdr);
> +
> + if (Ptr != NULL) {
> + FreePool (Ptr);
> + }
> +
> + if (EFI_ERROR (Status)) {
> + return FALSE;
> + }
> +
> + return TRUE;
> +}
> +
> +/**
> + This routine will check GPT partition entry and return entry status.
> +
> + Caution: This function may receive untrusted input.
> + The GPT partition entry is external input, so this routine
> + will do basic validation for GPT partition entry and report status.
> +
> + @param[in] PartHeader Partition table header structure
> + @param[in] PartEntry The partition entry array
> + @param[out] PEntryStatus the partition entry status array
> + recording the status of each partition
> +
> +**/
> +STATIC
> +VOID
> +PartitionCheckGptEntry (
> + IN EFI_PARTITION_TABLE_HEADER *PartHeader,
> + IN EFI_PARTITION_ENTRY *PartEntry,
> + OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus
> + )
> +{
> + EFI_LBA StartingLBA;
> + EFI_LBA EndingLBA;
> + EFI_PARTITION_ENTRY *Entry;
> + UINTN Index1;
> + UINTN Index2;
> +
> + DEBUG ((EFI_D_VERBOSE, " start check partition entries\n"));
> + for (Index1 = 0; Index1 < PartHeader->NumberOfPartitionEntries;
> Index1++) {
> + Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index1 *
> PartHeader->SizeOfPartitionEntry);
> + if (CompareGuid (&Entry->PartitionTypeGUID,
> &gEfiPartTypeUnusedGuid)) {
> + continue;
> + }
> +
> + StartingLBA = Entry->StartingLBA;
> + EndingLBA = Entry->EndingLBA;
> + if (StartingLBA > EndingLBA ||
> + StartingLBA < PartHeader->FirstUsableLBA ||
> + StartingLBA > PartHeader->LastUsableLBA ||
> + EndingLBA < PartHeader->FirstUsableLBA ||
> + EndingLBA > PartHeader->LastUsableLBA
> + ) {
> + PEntryStatus[Index1].OutOfRange = TRUE;
> + continue;
> + }
> +
> + if ((Entry->Attributes & BIT1) != 0) {
> + //
> + // If Bit 1 is set, this indicate that this is an OS specific GUID partition.
> + //
> + PEntryStatus[Index1].OsSpecific = TRUE;
> + }
> +
> + for (Index2 = Index1 + 1; Index2 < PartHeader-
> >NumberOfPartitionEntries; Index2++) {
> + Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index2 *
> PartHeader->SizeOfPartitionEntry);
> + if (CompareGuid (&Entry->PartitionTypeGUID,
> &gEfiPartTypeUnusedGuid)) {
> + continue;
> + }
> +
> + if (Entry->EndingLBA >= StartingLBA && Entry->StartingLBA <= EndingLBA)
> {
> + //
> + // This region overlaps with the Index1'th region
> + //
> + PEntryStatus[Index1].Overlap = TRUE;
> + PEntryStatus[Index2].Overlap = TRUE;
> + continue;
> + }
> + }
> + }
> +
> + DEBUG ((EFI_D_VERBOSE, " End check partition entries\n"));
> +}
> +
> +
> +/**
> + Updates the CRC32 value in the table header.
> +
> + @param Hdr Table to update
> +
> +**/
> +STATIC
> +VOID
> +PartitionSetCrc (
> + IN OUT EFI_TABLE_HEADER *Hdr
> + )
> +{
> + PartitionSetCrcAltSize (Hdr->HeaderSize, Hdr);
> +}
> +
> +
> +/**
> + Updates the CRC32 value in the table header.
> +
> + @param Size The size of the table
> + @param Hdr Table to update
> +
> +**/
> +STATIC
> +VOID
> +PartitionSetCrcAltSize (
> + IN UINTN Size,
> + IN OUT EFI_TABLE_HEADER *Hdr
> + )
> +{
> + UINT32 Crc;
> +
> + Hdr->CRC32 = 0;
> + gBS->CalculateCrc32 ((UINT8 *)Hdr, Size, &Crc);
> + Hdr->CRC32 = Crc;
> +}
> +
> +
> +/**
> + Checks the CRC32 value in the table header.
> +
> + @param MaxSize Max Size limit
> + @param Hdr Table to check
> +
> + @return TRUE CRC Valid
> + @return FALSE CRC Invalid
> +
> +**/
> +STATIC
> +BOOLEAN
> +PartitionCheckCrc (
> + IN UINTN MaxSize,
> + IN OUT EFI_TABLE_HEADER *Hdr
> + )
> +{
> + return PartitionCheckCrcAltSize (MaxSize, Hdr->HeaderSize, Hdr);
> +}
> +
> +
> +/**
> + Checks the CRC32 value in the table header.
> +
> + @param MaxSize Max Size limit
> + @param Size The size of the table
> + @param Hdr Table to check
> +
> + @return TRUE CRC Valid
> + @return FALSE CRC Invalid
> +
> +**/
> +STATIC
> +BOOLEAN
> +PartitionCheckCrcAltSize (
> + IN UINTN MaxSize,
> + IN UINTN Size,
> + IN OUT EFI_TABLE_HEADER *Hdr
> + )
> +{
> + UINT32 Crc;
> + UINT32 OrgCrc;
> + EFI_STATUS Status;
> +
> + Crc = 0;
> +
> + if (Size == 0) {
> + //
> + // If header size is 0 CRC will pass so return FALSE here
> + //
> + return FALSE;
> + }
> +
> + if ((MaxSize != 0) && (Size > MaxSize)) {
> + DEBUG ((EFI_D_ERROR, "CheckCrc32: Size > MaxSize\n"));
> + return FALSE;
> + }
> + //
> + // clear old crc from header
> + //
> + OrgCrc = Hdr->CRC32;
> + Hdr->CRC32 = 0;
> +
> + Status = gBS->CalculateCrc32 ((UINT8 *)Hdr, Size, &Crc);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc calculation failed\n"));
> + return FALSE;
> + }
> + //
> + // set results
> + //
> + Hdr->CRC32 = Crc;
> +
> + //
> + // return status
> + //
> + DEBUG_CODE_BEGIN ();
> + if (OrgCrc != Crc) {
> + DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc check failed\n"));
> + }
> + DEBUG_CODE_END ();
> +
> + return (BOOLEAN)(OrgCrc == Crc);
> +}
> +
> +/**
> + Converts a GUID into a unicode string.
> +
> + @param [in] Guid A GUID to be converted
> + @param [out] Buffer A pointer to a buffer receiving the string
> + @param [in] BufferSize Size of the buffer
> +
> + @return EFI_SUCCESS Successful conversion
> + @return EFI_INVALID_PARAMETER Conversion failed
> +
> +**/
> +
> +STATIC
> +EFI_STATUS
> +GuidToString (
> + IN EFI_GUID *Guid,
> + OUT CHAR16 *Buffer,
> + IN UINTN BufferSize
> + )
> +{
> + UINTN Size;
> + EFI_STATUS Status;
> +
> + Status = EFI_SUCCESS;
> +
> + Size = UnicodeSPrint (
> + Buffer,
> + BufferSize,
> + L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
> + (UINTN)Guid->Data1,
> + (UINTN)Guid->Data2,
> + (UINTN)Guid->Data3,
> + (UINTN)Guid->Data4[0],
> + (UINTN)Guid->Data4[1],
> + (UINTN)Guid->Data4[2],
> + (UINTN)Guid->Data4[3],
> + (UINTN)Guid->Data4[4],
> + (UINTN)Guid->Data4[5],
> + (UINTN)Guid->Data4[6],
> + (UINTN)Guid->Data4[7]
> + );
> + if (!Size) {
> + Status = EFI_INVALID_PARAMETER;
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Get a string representation of a known
> + partition type GUID. If partition GUID is not
> + known, gets a string representation of the GUID
> +
> + @param GUID Guid to be searched for
> + @param PartTypeStr Buffer receiving the string
> + @param NoGuidStr Do not convert GUID to string
> + for an unknown partition type
> +
> + @return EFI_SUCCESS GUID type is known
> + @return EFI_NOT_FOUND Unknown GUID partition type
> +
> +**/
> +EFI_STATUS
> +GetPartitionTypeStr (
> + IN EFI_GUID Guid,
> + OUT CHAR16 *PartTypeStr,
> + IN BOOLEAN NoGuidStr)
> +{
> + UINTN Index;
> + EFI_STATUS Status;
> +
> + Status = EFI_SUCCESS;
> + for (Index = 0; Index < ARRAY_SIZE (PartitionTypes); Index++) {
> + if (CompareGuid (&Guid, &PartitionTypes[Index].TypeGuid)) {
> + StrnCpy (PartTypeStr, PartitionTypes[Index].TypeName,
> MAX_PARTITION_NAME_LENGTH);
> + return Status;
> + }
> + }
> + if (!NoGuidStr) {
> + GuidToString (&Guid, PartTypeStr, (MAX_PARTITION_NAME_LENGTH + 1)
> * sizeof(CHAR16));
> + }
> + return EFI_NOT_FOUND;
> +}
> +
> +/**
> + Lists partitions on a block device.
> +
> + @return Number of partitions used
> +**/
> +
> +UINTN
> +PartitionListGptEntries (VOID)
> +{
> + UINTN Index;
> + EFI_PARTITION_ENTRY *Entry;
> + EFI_LBA Length;
> + UINTN NumEntries; // Used entries
> + UINTN BlockSize;
> + BOOLEAN FirstTime;
> + UINT64 BlocksOccupied;
> +
> + NumEntries = 0;
> + BlockSize = BlockIo->Media->BlockSize;
> + FirstTime = TRUE;
> +
> + if (!GptValid) {
> + return 0;
> + }
> +
> + BlocksOccupied = 0;
> +
> + for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries;
> Index++) {
> +
> + BOOLEAN Specific;
> + CHAR16 PartTypeStr[MAX_PARTITION_NAME_LENGTH + 1];
> +
> + Specific = FALSE;
> +
> + Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index *
> PrimaryHeader->SizeOfPartitionEntry);
> +
> + Length = Entry->EndingLBA - Entry->StartingLBA + 1;
> +
> + if (CompareGuid (&Entry->PartitionTypeGUID,
> &gEfiPartTypeUnusedGuid)) {
> + continue;
> + }
> +
> + if (FirstTime) {
> + Print (L" No \t%-36s\tStart (LBA)\tEnd (LBA)\tSize (MiB)\t Partition
> Type\r\n", L"Name");
> + Print (L" ---- -------------------------------------- ----------- ----------- -----
> ----- -------------------------------\r\n");
> + FirstTime = FALSE;
> + }
> + NumEntries++;
> + if (PEntryStatus[Index].OutOfRange ||
> + PEntryStatus[Index].Overlap ||
> + PEntryStatus[Index].OsSpecific) {
> + Specific = TRUE;
> + }
> +
> + BlocksOccupied += Length;
> +
> + GetPartitionTypeStr (Entry->PartitionTypeGUID, (CHAR16 *)&PartTypeStr,
> FALSE);
> +
> + Print (L"%1s %-3d\t%-36s\t0x%09llx\t0x%09llx\t%06llu\t %s\r\n",
> + Specific ? L"S" : L"",
> + Index + 1,
> + Entry->PartitionName,
> + (UINT64)Entry->StartingLBA,
> + (UINT64)Entry->EndingLBA,
> + (MultU64x32 (Length, BlockSize)) >> 20,
> + PartTypeStr);
> + }
> +
> + // This code block is to provide additional info
> + {
> + UINT64 DiskSizeMiB, SizeOccupiedMiB;
> +
> + DiskSizeMiB = MultU64x32 (PrimaryHeader->LastUsableLBA -
> PrimaryHeader->FirstUsableLBA + 1, BlockIo->Media->BlockSize) >> 20;
> + SizeOccupiedMiB = MultU64x32 (BlocksOccupied, BlockIo->Media-
> >BlockSize) >> 20;
> + Print (L"\r\n%d partition(s) used out of %d\r\n", NumEntries,
> PrimaryHeader->NumberOfPartitionEntries);
> + Print (L"Total device capacity (minus GPT service blocks): %llu
> MiB\r\nPartitioned space: %llu MiB\r\n",
> + DiskSizeMiB,
> + SizeOccupiedMiB);
> + Print (L"Unpartitioned space available: %llu MiB (%d%%)\n",
> + DiskSizeMiB - SizeOccupiedMiB,
> + (100 * (DiskSizeMiB - SizeOccupiedMiB)) / DiskSizeMiB);
> + }
> +
> + return NumEntries;
> +}
> +
> +/**
> + Locate a partition by criteria
> +
> + @param Name Partition name (or ordinal represented a string)
> + @param StartLba StartLba of the partition to search for
> + @param EndingLba EndingLba of the partition to search for
> + @param SearchType A combination (OR) of search options.
> + Options are:
> + SRC_BY_NAME = search by partition name
> + SRC_BY_LBA = search by Start/Ending lba
> + SRC_ANY = returns a first used partition
> + SRC_BY_NUM = search by ordinal
> +
> +
> + @return Non-NULL Pointer to th partition found
> + @return NULL No partition found
> +
> +**/
> +EFI_PARTITION_ENTRY *
> +PartitionFindPartitionByCriteria (
> + IN OPTIONAL CONST CHAR16 *Name,
> + IN OPTIONAL EFI_LBA StartLba,
> + IN OPTIONAL EFI_LBA EndingLba,
> + IN SEARCH_TYPE SearchType
> + )
> +{
> + UINTN Index;
> + EFI_PARTITION_ENTRY *Entry;
> +
> + if (!GptValid) {
> + return NULL;
> + }
> +
> + if (!Name && (SearchType & SRC_BY_NAME)) {
> + return NULL;
> + }
> +
> + for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries;
> Index++) {
> + Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index *
> PrimaryHeader->SizeOfPartitionEntry);
> +
> + if (CompareGuid (&Entry->PartitionTypeGUID,
> &gEfiPartTypeUnusedGuid)) {
> + continue;
> + }
> +
> + if (SearchType & SRC_ANY) {
> + return Entry;
> + }
> +
> + if (SearchType & SRC_BY_NAME) {
> + if (!StrCmp (Name, Entry->PartitionName)) {
> + return Entry;
> + }
> + }
> + if (SearchType & SRC_BY_NUM) {
> + UINTN Ordinal;
> +
> + Ordinal = ShellStrToUintn (Name);
> + if (Index == (Ordinal - 1)) {
> + return Entry;
> + }
> + }
> + if (SearchType & SRC_BY_LBA) {
> + if (
> + ((StartLba >= Entry->StartingLBA) &&
> + (StartLba <= Entry->EndingLBA)
> + ) ||
> + ((EndingLba >= Entry->StartingLBA) &&
> + (EndingLba <= Entry->EndingLBA)
> + )
> + ) {
> + return Entry;
> + }
> + }
> + }
> + return NULL;
> +}
> +
> +/**
> + Prints information on a given partition.
> +
> + @param Entry Pointer to the Partition of interest
> +**/
> +
> +VOID
> +PartitionPrintGptPartInfo (
> + IN EFI_PARTITION_ENTRY *Entry
> + )
> +{
> + CONST CHAR16 PartStr[MAX_PARTITION_NAME_LENGTH + 1] = { L'\0' };
> + CONST CHAR16 *StrUnknown = L"Unknown";
> + EFI_STATUS Status;
> + EFI_LBA Length;
> +
> + ASSERT (Entry);
> +
> + Status = GetPartitionTypeStr (Entry->PartitionTypeGUID, (CHAR16
> *)&PartStr, TRUE);
> + if (EFI_ERROR (Status)) {
> + StrCpy ((CHAR16 *)&PartStr, StrUnknown);
> + }
> +
> + Length = Entry->EndingLBA - Entry->StartingLBA + 1;
> +
> + Print (L"Partition name: %s\r\n", Entry->PartitionName);
> + Print (L"Starting LBA : 0x%09llx\r\nEnding LBA : 0x%09llx\r\n",
> + (UINT64)Entry->StartingLBA, (UINT64)Entry->EndingLBA);
> + Print (L"Partition Size: %llu MiB (0x%llx blocks)\n",
> + (MultU64x32 (Length, BlockIo->Media->BlockSize)) >> 20, Length);
> + Print (L"Attributes : 0x%09llx\r\n", Entry->Attributes);
> + Print (L"Type/GUID : %s/%g\r\n", PartStr, &Entry->PartitionTypeGUID);
> + Print (L"Unique GUID : %g\n", &Entry->UniquePartitionGUID);
> +}
> +
> +
> +/**
> + Writes protective MBR to a block device.
> +
> + @return EFI_SUCCESS MBR written successfully
> + @return other Failed to write an MBR
> +
> +**/
> +
> +STATIC
> +EFI_STATUS
> +WriteProtectiveMbr (
> + VOID
> + )
> +{
> + UINT32 BlockSize;
> + UINT64 DiskSize;
> + EFI_STATUS Status;
> + MBR_PARTITION_RECORD *Partition;
> + MASTER_BOOT_RECORD *ProtectiveMbr;
> +
> + BlockSize = BlockIo->Media->BlockSize;
> +
> + ProtectiveMbr = NULL;
> + ProtectiveMbr = AllocateZeroPool (BlockSize);
> + if (ProtectiveMbr == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + DiskSize = BlockIo->Media->LastBlock + 1;
> + if (DiskSize > 0xffffffff) {
> + DiskSize = 0xffffffff;
> + }
> +
> + CopyMem (ProtectiveMbr, &ProtectiveMbrTemplate,
> sizeof(MASTER_BOOT_RECORD));
> +
> + Partition = &ProtectiveMbr->Partition[0];
> +
> + Partition->BootIndicator = 0;
> + Partition->StartSector = 1;
> +
> + //
> + // We don't actually know this data, so we'll make up
> + // something that seems likely.
> + //
> +
> + //
> + // Old software is expecting the Partition to start on
> + // a Track boundary, so we'll set track to 1 to avoid "overlay"
> + // with the MBR
> + //
> +
> + Partition->StartTrack = 1;
> +
> + Status = DiskIo->WriteDisk (
> + DiskIo,
> + BlockIo->Media->MediaId,
> + 0,
> + BlockSize,
> + ProtectiveMbr
> + );
> +
> + MbrValid = !EFI_ERROR (Status);
> +
> + SHELL_FREE_NON_NULL (ProtectiveMbr);
> +
> + return Status;
> +}
> +
> +/**
> + Write GPT tables to the block device.
> +
> + @return EFI_SUCCESS GPT tables were successfully written/updated
> + @return other Failed to write/update GPT tables
> +
> +**/
> +
> +STATIC
> +EFI_STATUS
> +WriteGPT (
> + VOID
> + )
> +/*
> + CALLER is expected to fill in:
> + FirstUseableLBA
> + LastUseableLBA
> + EntryCount
> + DiskGUID
> +
> + We fill in the rest, and blast it out.
> +
> + Returns a status.
> +
> +*/
> +{
> + UINT32 BlockSize;
> + UINT32 TableSize;
> + EFI_STATUS Status = EFI_SUCCESS;
> +
> + BlockSize = BlockIo->Media->BlockSize;
> + TableSize = PrimaryHeader->NumberOfPartitionEntries *
> sizeof(EFI_PARTITION_ENTRY);
> +
> + if (!MbrValid) {
> + WriteProtectiveMbr ();
> + }
> + //
> + // Write out the primary header...
> + //
> + PrimaryHeader->Header.Signature = EFI_PTAB_HEADER_ID;
> + PrimaryHeader->Header.Revision = GPT_REVISION_1_0;
> + PrimaryHeader->Header.HeaderSize =
> sizeof(EFI_PARTITION_TABLE_HEADER);
> +
> + PrimaryHeader->AlternateLBA = BackupHeader->MyLBA;
> +
> + PrimaryHeader->SizeOfPartitionEntry = sizeof(EFI_PARTITION_ENTRY);
> +
> + Status = gBS->CalculateCrc32 ((UINT8 *)PartEntry, TableSize,
> &PrimaryHeader->PartitionEntryArrayCRC32);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + // Write primary header
> + PartitionSetCrc (&PrimaryHeader->Header);
> +
> + Status = DiskIo->WriteDisk (
> + DiskIo,
> + BlockIo->Media->MediaId,
> + MultU64x32 (PrimaryHeader->MyLBA, (UINT32)BlockSize),
> + BlockSize,
> + PrimaryHeader
> + );
> +
> +
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + //
> + // Write out the primary table ...
> + //
> + Status = DiskIo->WriteDisk (
> + DiskIo,
> + BlockIo->Media->MediaId,
> + MultU64x32 (PrimaryHeader->PartitionEntryLBA, (UINT32)BlockSize),
> + TableSize,
> + PartEntry
> + );
> +
> +
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + //
> + // Write out the secondary header and table by calling restore
> + //
> +
> + if (!PartitionRestoreGptTable (PrimaryHeader)) {
> + return EFI_VOLUME_CORRUPTED;
> + }
> + BlockIo->FlushBlocks (BlockIo);
> + GptValid = !EFI_ERROR (Status);
> +
> + return Status;
> +}
> +
> +/**
> + (Re)initialize GPT tables on the block device
> +
> + @return EFI_SUCCESS Successfully (re)initialized GPT Tables
> + @return other Failed to (re)initialize GPT tables
> +
> +**/
> +STATIC
> +EFI_STATUS
> +TableCreateEmptyGpt (VOID)
> +{
> + UINTN EntryCount;
> + UINTN BlockFit;
> + UINTN BlockSize;
> + UINTN EntryBlocks;
> + UINT64 DiskSize;
> + UINTN TableSize;
> + EFI_LBA Header1_LBA;
> + EFI_LBA Table1_LBA;
> + EFI_LBA Header2_LBA;
> + EFI_LBA Table2_LBA;
> + EFI_LBA FirstUsableLBA;
> + EFI_LBA LastUsableLBA;
> + EFI_STATUS Status;
> +
> + EntryCount = ENTRY_DEFAULT;
> + BlockSize = BlockIo->Media->BlockSize;
> + BlockFit = BlockSize / sizeof(EFI_PARTITION_ENTRY);
> +
> + if (BlockFit > ENTRY_DEFAULT) {
> + EntryCount = BlockFit;
> + }
> + EntryBlocks = EntryCount / BlockFit;
> +
> + if ((EntryBlocks * BlockFit) != EntryCount) {
> + Status = EFI_VOLUME_CORRUPTED;
> + PrintErr (L"Invalid Entry blocks and Entry count combination\n", Status);
> + return Status;
> + }
> +
> + DiskSize = BlockIo->Media->LastBlock + 1;
> +
> + SHELL_FREE_NON_NULL (PrimaryHeader);
> + SHELL_FREE_NON_NULL (BackupHeader);
> + SHELL_FREE_NON_NULL (PartEntry);
> +
> + PrimaryHeader = AllocateZeroPool (BlockSize);
> + if (PrimaryHeader == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + BackupHeader = AllocateZeroPool (BlockSize);
> + if (BackupHeader == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + Header1_LBA = 1;
> + Table1_LBA = 2;
> + FirstUsableLBA = Table1_LBA + EntryBlocks;
> +
> + Header2_LBA = DiskSize - 1;
> + Table2_LBA = Header2_LBA - EntryBlocks;
> + LastUsableLBA = Table2_LBA - 1;
> +
> + TableSize = EntryBlocks * BlockSize;
> +
> + if (TableSize != (EntryCount * sizeof(EFI_PARTITION_ENTRY))) {
> + Status = EFI_VOLUME_CORRUPTED;
> + PrintErr (L"Invalid Table size and Entry count combination\n", Status);
> + return Status;
> + }
> +
> + if (GPT_DEBUG_LEVEL) {
> + Print (L"DiskSize = %lx\n", DiskSize);
> + Print (L"BlockSize = %x\n", BlockSize);
> + Print (L"Header1_LBA = %lx\n", Header1_LBA);
> + Print (L"Table1_LBA = %lx\n", Table1_LBA);
> + Print (L"FirstUsableLBA = %lx\n", FirstUsableLBA);
> + Print (L"Header2_LBA = %lx\n", Header2_LBA);
> + Print (L"Table2_LBA = %lx\n", Table2_LBA);
> + Print (L"LastUsableLBA = %lx\n", LastUsableLBA);
> + Print (L"EntryCount = %x\n", EntryCount);
> + Print (L"EntryBlocks = %x\n", EntryBlocks);
> + }
> +
> + //
> + // Since we're making empty tables, we just write zeros...
> + //
> +
> + PartEntry = AllocateZeroPool (TableSize);
> + if (PartEntry == NULL) {
> + SHELL_FREE_NON_NULL (PrimaryHeader);
> + SHELL_FREE_NON_NULL (BackupHeader);
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + PEntryStatus = AllocateZeroPool (TableSize);
> +
> + PrimaryHeader->FirstUsableLBA = FirstUsableLBA;
> + PrimaryHeader->LastUsableLBA = LastUsableLBA;
> + PrimaryHeader->NumberOfPartitionEntries = (UINT32)EntryCount;
> + GenerateGuid (&PrimaryHeader->DiskGUID);
> +
> + PrimaryHeader->MyLBA = Header1_LBA;
> + BackupHeader->MyLBA = Header2_LBA;
> + PrimaryHeader->PartitionEntryLBA = Table1_LBA;
> + BackupHeader->PartitionEntryLBA = Table2_LBA;
> +
> + Status = WriteGPT ();
> +
> + return Status;
> +}
> +
> +/**
> + Clear GPT partitions.
> +
> + @return EFI_SUCCESS Cleared successfully
> + @return FALSE Failed to clear
> +
> +**/
> +
> +EFI_STATUS
> +PartitionGptClearAll (VOID)
> +{
> + GptCleanupGlobals ();
> + GptValid = FALSE;
> + MbrValid = FALSE;
> + return TableCreateEmptyGpt ();
> +}
> +
> +/**
> + Create a GPT partition.
> +
> + @param PartName Partition Name
> + @param StartLba Starting LBA of the partition.
> + if zero, will be calculated
> + @param SizeInMegaBytes Size of the partition in MB
> + @param Attributes Partition attributes
> + @param PartTypeGuid a Type GUID to be assigned to the partition
> (not a partition unique GUID)
> +
> +
> + @return EFI_SUCCESS Partition successfully created
> + @return EFI_INVALID_PARAMETER Either partition exists, or wrong
> parameters specified
> + @return other Failed to create a partition
> +**/
> +EFI_STATUS
> +PartitionGptCreatePartition (
> + IN CONST CHAR16 *PartName,
> + IN EFI_LBA StartLba,
> + IN UINT64 SizeInMegabytes,
> + IN UINT64 Attributes,
> + IN EFI_GUID PartTypeGuid)
> +{
> + EFI_GUID Guid, PartitionIdGuid;
> + EFI_STATUS Status;
> + UINT64 StartBlock;
> + UINT64 EndBlock;
> + UINT64 SizeInBytes = 0;
> + UINT32 BlockSize;
> + UINT64 DiskSizeBlocks;
> + UINT8 *p;
> + BOOLEAN OffsetSpecified = FALSE;
> + BOOLEAN AllZeros;
> + INTN AllZeroEntry;
> + INTN OldFreeEntry;
> + UINT64 AvailBlocks;
> + UINT64 BlocksToAllocate;
> + UINT64 HighSeen;
> + UINTN Slot;
> + UINT64 LowestAlignedLba;
> + UINT32 OptimalTransferBlocks;
> + UINTN i, j;
> + CHAR16 PartNameUsed[MAX_PARTITION_NAME_LENGTH + 1] = { L'\0' };
> + EFI_PARTITION_ENTRY *Entry;
> +
> + LowestAlignedLba = 0;
> + OptimalTransferBlocks = 1;
> +
> + AllZeroEntry = -1;
> + OldFreeEntry = -1;
> +
> + BlockSize = BlockIo->Media->BlockSize;
> + OffsetSpecified = (StartLba != 0);
> + CopyMem (&PartNameUsed, PartName, sizeof(CHAR16) * StrSize
> (PartName));
> +
> + GenerateGuid (&Guid);
> +
> + // Creating a new partition
> + if (!GptValid) {
> + // Creating a GPT for the first time
> + Status = TableCreateEmptyGpt ();
> + if (!EFI_ERROR (Status)) {
> + // Fill in the structures
> + Status = PartitionGetGptTables (DiskIo, BlockIo);
> + }
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + }
> +
> + Entry = PartitionFindPartitionByCriteria (PartName, 0, 0, SRC_BY_NAME);
> + if (Entry) {
> + Status = EFI_INVALID_PARAMETER;
> + PrintErr (L"Partition with this name already exists", Status);
> + return Status;
> + }
> + HighSeen = PrimaryHeader->FirstUsableLBA - 1;
> +
> + if (StartLba) {
> + //
> + // if offset is specified, compute the start and end blocks
> + //
> + StartBlock = StartLba;
> + //
> + // StartBlock should be aligned to OptimalTransferBlocks, the least
> common multiple of:
> + // a). the physical block boundary, if any
> + // b). the optimal transfer length granularity, if any
> + //
> + if (StartBlock < LowestAlignedLba) {
> + StartBlock = LowestAlignedLba;
> + } else {
> + while (((StartBlock - LowestAlignedLba) % OptimalTransferBlocks) != 0) {
> + StartBlock++;
> + }
> + }
> +
> + if (StartBlock < PrimaryHeader->FirstUsableLBA ||
> + StartBlock > PrimaryHeader->LastUsableLBA) {
> + //
> + // Offset specified is too large
> + //
> + Status = EFI_INVALID_PARAMETER;
> + PrintErr (L"Specified offset is too large", EFI_INVALID_PARAMETER);
> + goto Exit;
> + }
> +
> + SizeInBytes = MultU64x32 (SizeInMegabytes, (1024 * 1024));
> + if (SizeInBytes < SizeInMegabytes || SizeInBytes == 0) {
> + //
> + // If size is not specified or too large,
> + // try to make the partition as big as it can be
> + //
> + BlocksToAllocate = EndBlock = SizeInBytes = 0xffffffffffffffff;
> + } else {
> + BlocksToAllocate = DivU64x32 (SizeInBytes, BlockSize);
> + EndBlock = StartBlock + BlocksToAllocate - 1;
> + if (EndBlock > PrimaryHeader->LastUsableLBA) {
> + EndBlock = PrimaryHeader->LastUsableLBA;
> + BlocksToAllocate = EndBlock - StartBlock + 1;
> + }
> + }
> + }
> +
> + for (i = 0; i < PrimaryHeader->NumberOfPartitionEntries; i++) {
> + Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + i *
> PrimaryHeader->SizeOfPartitionEntry);
> + if (!CompareGuid (&Entry->PartitionTypeGUID,
> &gEfiPartTypeUnusedGuid)) {
> +
> + //
> + // Type not null, so it's allocated
> + //
> + if (Entry->EndingLBA > HighSeen) {
> + HighSeen = Entry->EndingLBA;
> + }
> + if (OffsetSpecified) {
> + //
> + // make sure new partition does not overlap with existing partitions
> + //
> + if (Entry->StartingLBA <= StartBlock &&
> + StartBlock <= Entry->EndingLBA) {
> + //
> + // starting block is inside an existing partition
> + //
> + Status = EFI_INVALID_PARAMETER;
> + PrintErr (L"Starting block is inside an existing partition", Status);
> + goto Exit;
> + }
> + if ((Entry->StartingLBA <= EndBlock &&
> + EndBlock <= Entry->EndingLBA) ||
> + (StartBlock <= Entry->StartingLBA &&
> + Entry->StartingLBA <= EndBlock) ||
> + (StartBlock <= Entry->EndingLBA &&
> + Entry->EndingLBA <= EndBlock)) {
> + //
> + // new partition overlaps with an existing partition
> + // readjust new partition size to avoid overlapping
> + //
> + EndBlock = Entry->StartingLBA - 1;
> + if (EndBlock < StartBlock) {
> + Status = EFI_INVALID_PARAMETER;
> + PrintErr (L"Cannot readjust new partition size - overlapping", Status);
> + goto Exit;
> + } else {
> + BlocksToAllocate = EndBlock - StartBlock + 1;
> + }
> + }
> + }
> + } else {
> + p = (UINT8 *)(Entry);
> + AllZeros = TRUE;
> + for (j = 0; j < sizeof(EFI_PARTITION_ENTRY); j++) {
> + if (p[j] != 0) {
> + AllZeros = FALSE;
> + }
> + }
> + if (AllZeros) {
> + if (AllZeroEntry == -1) {
> + AllZeroEntry = i;
> + }
> + } else if (OldFreeEntry == -1) {
> + OldFreeEntry = i;
> + }
> + }
> + }
> +
> + //
> + // AllZeroEntry - if not -1, is pointer to a never before used entry (free)
> + // OldFreeEntry - if not -1, is pointer to some pre-used free entry
> + //
> + if ((AllZeroEntry == -1) && (OldFreeEntry == -1)) {
> + //
> + // TABLE IS FULL!!
> + //
> + Status = EFI_OUT_OF_RESOURCES;
> + PrintErr (L"Table is full", Status);
> + goto Exit;
> + }
> +
> + if (OffsetSpecified) {
> + //
> + // the user haven't specified the new partition size and we haven't
> + // run into any partition that will limit the size of this new partition.
> + // So, use the max it can
> + //
> + if (BlocksToAllocate == -1) {
> + EndBlock = PrimaryHeader->LastUsableLBA;
> + BlocksToAllocate = EndBlock - StartBlock + 1;
> + }
> + } else {
> + //
> + // Because HighSeen is the last LBA of the used blocks, let HighSeen align
> to the least common multiple of:
> + // a). the physical block boundary, if any
> + // b). the optimal transfer length granularity, if any
> + //
> + if (HighSeen + 1 < LowestAlignedLba) {
> + HighSeen = LowestAlignedLba - 1;
> + } else {
> + while (((HighSeen + 1 - LowestAlignedLba) % OptimalTransferBlocks) != 0)
> {
> + HighSeen++;
> + }
> + }
> +
> + if (PrimaryHeader->LastUsableLBA <= HighSeen) {
> + Status = EFI_OUT_OF_RESOURCES;
> + PrintErr (L"Disk has no free blocks (FULL) cannot create", Status);
> + goto Exit;
> + }
> + //
> + // [HighSeen+1 ... LastUsableLBA] is available...
> + // avail = (LastUsableLBA - (HighSeen+1)) + 1 => LastUsabbleLBA -
> HighSeen
> + //
> + AvailBlocks = PrimaryHeader->LastUsableLBA - HighSeen;
> +
> + SizeInBytes = MultU64x32 (SizeInMegabytes, (1024 * 1024));
> + if (SizeInBytes < SizeInMegabytes) {
> + //
> + // overflow, force a very big answer
> + //
> + SizeInBytes = 0xffffffffffffffff;
> + }
> +
> + if ((SizeInBytes == 0) ||
> + (SizeInBytes > (MultU64x32 (AvailBlocks, BlockSize)))) {
> + //
> + // User asked for zero, or for more than we've got,
> + // so give them all that is left
> + //
> + BlocksToAllocate = AvailBlocks;
> +
> + } else {
> +
> + //
> + // We would have to have a BlockSize > 1mb for Remainder to
> + // not be 0. Since we cannot actually test this case, we
> + // ingore it...
> + //
> + BlocksToAllocate = DivU64x32 (SizeInBytes, BlockSize);
> +
> + }
> + }
> +
> + //
> + // We have a name
> + // We have a type guid
> + // We have a size in blocks
> + // We have an attribute mask
> + //
> +
> + if (BlocksToAllocate < ((1024 * 1024) / BlockSize)) {
> + Status = EFI_OUT_OF_RESOURCES;
> + PrintErr (L"Partition is too small to be created", Status);
> + goto Exit;
> + }
> +
> + if (GPT_DEBUG_LEVEL) {
> + Print (L"Requested SizeInMegaBytes = %ld\n", SizeInMegabytes);
> + Print (L"Resulting size in Blocks = %ld\n", BlocksToAllocate);
> + Print (L"Results size in Bytes = %ld\n", MultU64x32 (BlocksToAllocate,
> BlockSize));
> + }
> +
> + if (AllZeroEntry != -1) {
> + Slot = AllZeroEntry;
> + } else {
> + Slot = OldFreeEntry;
> + }
> +
> + GenerateGuid (&PartitionIdGuid);
> + Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Slot *
> PrimaryHeader->SizeOfPartitionEntry);
> +
> + CopyMem (&Entry->PartitionTypeGUID, &PartTypeGuid,
> sizeof(EFI_GUID));
> + CopyMem (&Entry->UniquePartitionGUID, &PartitionIdGuid,
> sizeof(EFI_GUID));
> + if (OffsetSpecified) {
> + PartEntry[Slot].StartingLBA = StartBlock;
> + PartEntry[Slot].EndingLBA = EndBlock;
> + } else {
> + PartEntry[Slot].StartingLBA = HighSeen + 1;
> + PartEntry[Slot].EndingLBA = HighSeen + BlocksToAllocate;
> + }
> +
> + if (!(((Entry->EndingLBA - Entry->StartingLBA) + 1) == BlocksToAllocate)) {
> + PrintErr (L"Wrong Size for new partiton", EFI_INVALID_PARAMETER);
> + goto Exit;
> + }
> +
> + if ((Entry->StartingLBA < PrimaryHeader->FirstUsableLBA) ||
> + (Entry->EndingLBA > PrimaryHeader->LastUsableLBA)) {
> + PrintErr (L"New Partition out of bounds", EFI_INVALID_PARAMETER);
> + goto Exit;
> + }
> +
> + Entry->Attributes = Attributes;
> + CopyMem (&(Entry->PartitionName[0]), PartName,
> MAX_PARTITION_NAME_LENGTH * sizeof(CHAR16));
> +
> + DiskSizeBlocks = BlockIo->Media->LastBlock + 1;
> + if (DiskSizeBlocks > 0xffffffff) {
> + DiskSizeBlocks = 0xffffffff;
> + }
> +
> + Status = WriteGPT ();
> +
> + if (EFI_ERROR (Status)) {
> + PrintErr (L"Attempt to Write out partition table failed", Status);
> + }
> +
> + Exit:
> + return Status;
> +}
> +
> +/**
> + Modifiy a partition based on parameters.
> +
> + @param Entry Pointer to an existing partition
> + @param Params Parameters to be modified
> + @param Flags Which parameter is to be modified
> +
> + @return EFI_SUCCESS Successfully modified the partition
> + @return other Failed to modify a partition
> +
> +**/
> +
> +EFI_STATUS
> +PartitionGptModifyPartition (
> + IN EFI_PARTITION_ENTRY *Entry,
> + IN MOD_PARAMS *Params,
> + IN MOD_FLAGS Flags
> + )
> +{
> + EFI_STATUS Status;
> +
> + ASSERT (Entry);
> +
> + Status = EFI_INVALID_PARAMETER;
> +
> + switch (Flags) {
> + case MOD_DELETE:
> + ZeroMem (Entry, sizeof(EFI_PARTITION_ENTRY));
> + break;
> + case MOD_ATTR:
> + Entry->Attributes = Params->Attributes;
> + break;
> + case MOD_TYPE:
> + Entry->PartitionTypeGUID = Params->PartTypeGuid;
> + break;
> + case MOD_RENAME:
> + StrCpy (Entry->PartitionName, Params->NewName);
> + break;
> + default:
> + PrintErr (L"Unknown modification flag(s)", Status);
> + return Status;
> + }
> +
> + return WriteGPT ();
> +}
> +
> +EFI_KNOWN_PARTITION_TYPE *PartitionGetKnownType (
> + IN UINTN Index,
> + IN OUT OPTIONAL UINTN *NumEntries
> + )
> +{
> + if (NumEntries) {
> + *NumEntries = ARRAY_SIZE(PartitionTypes);
> + }
> + if (Index > ARRAY_SIZE(PartitionTypes)) {
> + return NULL;
> + }
> +
> + return &PartitionTypes[Index];
> +}
> +
> diff --git a/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> new file mode 100644
> index 000000000000..9efec5cefe94
> --- /dev/null
> +++ b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> @@ -0,0 +1,186 @@
> +/*
> + * BSD LICENSE
> + *
> + * Copyright(c) 2016 Broadcom. All rights reserved.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + *
> + * * Redistributions of source code must retain the above copyright
> + * notice, this list of conditions and the following disclaimer.
> + * * Redistributions in binary form must reproduce the above copyright
> + * notice, this list of conditions and the following disclaimer in
> + * the documentation and/or other materials provided with the
> + * distribution.
> + * * Neither the name of Broadcom nor the names of its
> + * contributors may be used to endorse or promote products derived
> + * from this software without specific prior written permission.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> CONTRIBUTORS
> + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
> NOT
> + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
> FITNESS FOR
> + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
> COPYRIGHT
> + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> NOT
> + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
> OF USE,
> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
> AND ON ANY
> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
> THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> DAMAGE.
> + */
> +
> +/* GPT partitioner header file */
> +
> +#ifndef _GPTWORKER_H_
> +#define _GPTWORKER_H_
> +
> +#include <Uefi.h>
> +#include <ShellBase.h>
> +
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/ShellCommandLib.h>
> +#include <Library/ShellLib.h>
> +#include <Library/UefiLib.h>
> +#include <Library/UefiShellLib/UefiShellLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiRuntimeServicesTableLib.h>
> +#include <Library/PrintLib.h>
> +#include <Library/ShellCEntryLib.h>
> +#include <Library/HiiLib.h>
> +#include <Library/FileHandleLib.h>
> +#include <Protocol/DevicePath.h>
> +#include <Library/DevicePathLib.h>
> +#include <Protocol/BlockIo.h>
> +#include <Protocol/DiskIo.h>
> +#include <IndustryStandard/Mbr.h>
> +
> +typedef enum {
> + MOD_NAME = BIT0,
> + MOD_ATTR = BIT1,
> + MOD_TYPE = BIT2,
> + MOD_DELETE = BIT3,
> + MOD_RENAME = BIT4
> +} MOD_FLAGS;
> +
> +typedef struct {
> + UINTN Attributes;
> + EFI_GUID PartTypeGuid;
> + CONST CHAR16 *PartName;
> + CONST CHAR16 *NewName;
> +} MOD_PARAMS;
> +
> +typedef enum {
> + SRC_BY_NAME = BIT0,
> + SRC_BY_LBA = BIT1,
> + SRC_BY_NUM = BIT2,
> + SRC_ANY = BIT3
> +} SEARCH_TYPE;
> +
> +#define MAX_PARTITION_NAME_LENGTH 36
> +#define ENTRY_DEFAULT 128
> +#define GPT_REVISION_1_0 0x00010000
> +
> +#define ARRAY_SIZE(x) \
> + (sizeof(x) / sizeof((x)[0]))
> +
> +//
> +// Extract INT32 from char array
> +//
> +#define UNPACK_INT32(a) (INT32)( (((UINT8 *) a)[0] << 0) | \
> + (((UINT8 *) a)[1] << 8) | \
> + (((UINT8 *) a)[2] << 16) | \
> + (((UINT8 *) a)[3] << 24) )
> +
> +//
> +// Extract UINT32 from char array
> +//
> +#define UNPACK_UINT32(a) (UINT32)( (((UINT8 *) a)[0] << 0) | \
> + (((UINT8 *) a)[1] << 8) | \
> + (((UINT8 *) a)[2] << 16) | \
> + (((UINT8 *) a)[3] << 24) )
> +
> +
> +//
> +// GPT Partition Entry Status
> +//
> +typedef struct {
> + BOOLEAN OutOfRange;
> + BOOLEAN Overlap;
> + BOOLEAN OsSpecific;
> +} EFI_PARTITION_ENTRY_STATUS;
> +
> +typedef struct {
> + CONST EFI_GUID TypeGuid;
> + CONST CHAR16 *TypeName;
> +
> +} EFI_KNOWN_PARTITION_TYPE;
> +
> +EFI_KNOWN_PARTITION_TYPE *PartitionGetKnownType (
> + IN UINTN Index,
> + IN OUT OPTIONAL UINTN *NumEntries
> + );
> +
> +EFI_STATUS
> +PartitionGetGptTables (
> + IN EFI_DISK_IO_PROTOCOL *DiskIoProt,
> + IN EFI_BLOCK_IO_PROTOCOL *BlockIoProt
> + );
> +
> +UINTN
> +PartitionListGptEntries (
> + VOID
> + );
> +
> +VOID
> +PartitionPrintGptPartInfo (
> + IN EFI_PARTITION_ENTRY *Entry
> + );
> +
> +EFI_STATUS
> +GetPartitionTypeStr (
> + EFI_GUID Guid,
> + CHAR16 *PartTypeStr,
> + BOOLEAN NoGuidStr
> + );
> +
> +
> +EFI_STATUS
> +PartitionGptClearAll (
> + VOID
> + );
> +
> +EFI_STATUS
> +PartitionGptCreatePartition (
> + CONST CHAR16 *PartName,
> + EFI_LBA StartLba,
> + EFI_LBA PartitionSize,
> + UINT64 Attributes,
> + EFI_GUID PartTypeGuid);
> +
> +EFI_STATUS
> +PartitionGptModifyPartition (
> + EFI_PARTITION_ENTRY *Entry,
> + MOD_PARAMS *Params,
> + MOD_FLAGS Flags
> + );
> +
> +VOID
> +GptCleanupGlobals (
> + VOID
> + );
> +
> +EFI_PARTITION_ENTRY *
> +PartitionFindPartitionByCriteria (
> + CONST CHAR16 *Name,
> + EFI_LBA StartLba,
> + EFI_LBA EndingLba,
> + SEARCH_TYPE SearchType);
> +
> +VOID
> +PrintErr (IN CONST CHAR16 *Message, IN EFI_STATUS Status);
> +
> +#endif //_GPTWORKER_H_
> diff --git
> a/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> new file mode 100644
> index 000000000000..a9d74a780911
> --- /dev/null
> +++
> b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> @@ -0,0 +1,1135 @@
> +/*********************************************************
> **********************
> +Copyright (C) 2016 Marvell International Ltd.
> +
> +Marvell BSD License Option
> +
> +If you received this File from Marvell, you may opt to use, redistribute
> and/or
> +modify this File under the following licensing terms.
> +Redistribution and use in source and binary forms, with or without
> modification,
> +are permitted provided that the following conditions are met:
> +
> +* Redistributions of source code must retain the above copyright notice,
> + this list of conditions and the following disclaimer.
> +
> +* Redistributions in binary form must reproduce the above copyright
> + notice, this list of conditions and the following disclaimer in the
> + documentation and/or other materials provided with the distribution.
> +
> +* Neither the name of Marvell nor the names of its contributors may be
> + used to endorse or promote products derived from this software without
> + specific prior written permission.
> +
> +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> CONTRIBUTORS "AS IS" AND
> +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
> THE IMPLIED
> +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> PURPOSE ARE
> +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> CONTRIBUTORS BE LIABLE FOR
> +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> CONSEQUENTIAL DAMAGES
> +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
> OR SERVICES;
> +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
> CAUSED AND ON
> +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> TORT
> +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
> THE USE OF THIS
> +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +
> +*********************************************************
> **********************/
> +
> +/* Portions Copyright (C) 2016 Broadcom */
> +
> +#include "FatFormat.h"
> +#include
> <Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.h>
> +#include <Library/TimerLib.h>
> +
> +CONST CHAR16 gShellGptFileName[] = L"ShellCommand";
> +STATIC CONST CHAR16 gAppName[] = L"gpt";
> +EFI_HANDLE gShellGptHiiHandle = NULL;
> +
> +STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
> + // Partition-related operations
> + { L"clear", TypeFlag }, // Clears all partitions
> + { L"create", TypeFlag }, // Creates a partition
> + { L"delete", TypeFlag }, // Deletes a partition
> + { L"list", TypeFlag }, // Lists all partitions
> + { L"rename", TypeFlag }, // Renames a partition
> + { L"setattr", TypeFlag }, // Set attributes for a partition in partition
> table
> + { L"settype", TypeFlag },
> + { L"sync", TypeFlag }, // Synchronizes either master or alternative
> partition table
> + { L"typesinfo", TypeFlag }, // Verifies correctness of master and
> alternative partition tables
> + // BlockIo-related operations
> + { L"read", TypeFlag }, // Reads n bytes into memory address from
> a partition starting from a certain lba
> + { L"readfile", TypeFlag }, // Same as above, but instead of store it in
> memory saves into a file system
> + { L"write", TypeFlag }, // Writes n bytes from memory into a
> partition starting from a certain lba
> + { L"writefile", TypeFlag }, // Same as above, but instead of getting
> data from memory reads a file
> + { L"info", TypeFlag }, // Get information on a certain partition
> (startLba, lastLba, attributes)
> + { L"fatformat", TypeFlag }, // FAT format of a partition
> + { L"-type", TypeValue },
> + { L"-yes", TypeFlag },
> + { L"-verbose", TypeFlag },
> + { NULL, TypeMax }
> +};
> +
> +typedef enum {
> + // Not requires presence
> + CLEAR = BIT0,
> + CREATE = BIT1,
> + LIST = BIT2,
> + SYNC = BIT3,
> + TYPES_INFO = BIT4,
> +
> + // Requires presence
> + DELETE = BIT5,
> + INFO = BIT6,
> + READ = BIT7,
> + READ_FILE = BIT8,
> + RENAME = BIT9,
> + SETATTR = BIT10,
> + SETTYPE = BIT11,
> + WRITE = BIT12,
> + WRITE_FILE = BIT13,
> + FAT_FORMAT = BIT14,
> +} Flags;
> +
> +/**
> + Return the file name of the help text file if not using HII.
> +
> + @return The string pointer to the file name.
> +**/
> +CONST CHAR16 *
> +EFIAPI
> +ShellCommandGetManFileNameGpt (
> + VOID
> + )
> +{
> +
> + return gShellGptFileName;
> +}
> +
> +STATIC
> +EFI_STATUS
> +OpenAndPrepareFile (
> + IN CHAR16 *FilePath,
> + OUT SHELL_FILE_HANDLE *FileHandle,
> + IN BOOLEAN WriteNeeded
> + )
> +{
> + EFI_STATUS Status;
> + UINT64 OpenMode;
> +
> + OpenMode = EFI_FILE_MODE_READ;
> +
> + if (WriteNeeded) {
> + OpenMode |= EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE;
> + }
> +
> + Status = ShellOpenFileByName (FilePath, FileHandle, OpenMode, 0);
> + if (EFI_ERROR (Status)) {
> + ShellPrintHiiEx (-1, -1,
> + NULL, STRING_TOKEN (STR_GPT_ERROR),
> + gShellGptHiiHandle,
> + gAppName,
> + Status,
> + L"Cannot open file"
> + );
> + return Status;
> + }
> +
> + Status = FileHandleSetPosition (*FileHandle, 0);
> +
> + if (EFI_ERROR (Status)) {
> + ShellPrintHiiEx (-1, -1,
> + NULL, STRING_TOKEN (STR_GPT_ERROR),
> + gShellGptHiiHandle,
> + gAppName,
> + Status,
> + "Cannot set file position to the first byte"
> + );
> +
> + ShellCloseFile (FileHandle);
> + return Status;
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +VOID
> +PrintErr (
> + IN CONST CHAR16 *Message,
> + IN EFI_STATUS Status
> + )
> +{
> + ShellPrintHiiEx (-1, -1,
> + NULL, STRING_TOKEN (STR_GPT_ERROR),
> + gShellGptHiiHandle,
> + gAppName,
> + Status,
> + Message
> + );
> +}
> +
> +STATIC
> +BOOLEAN
> +IsPartitionableDevicePath (
> + IN EFI_DEVICE_PATH *DevicePath
> + )
> +{
> + UINTN PathSize;
> + EFI_DEVICE_PATH *PathInstance;
> + BOOLEAN Partitionable;
> +
> + Partitionable = TRUE;
> + while (DevicePath != NULL) {
> + PathInstance = GetNextDevicePathInstance (&DevicePath, &PathSize);
> +
> + while (!IsDevicePathEnd (PathInstance)) {
> + if ((DevicePathType (PathInstance) == MEDIA_DEVICE_PATH)) {
> + Partitionable = FALSE;
> + }
> +
> + PathInstance = NextDevicePathNode (PathInstance);
> + }
> + }
> + return Partitionable;
> +}
> +
> +STATIC
> +EFI_STATUS
> +GptPromptYesNo (
> + IN CONST EFI_STRING_ID HiiFormatStringId
> + )
> +{
> + EFI_STATUS Status;
> + VOID *Response;
> +
> + Status = ShellPromptForResponseHii (ShellPromptResponseTypeYesNo,
> HiiFormatStringId, gShellGptHiiHandle, &Response);
> + if ((EFI_ERROR (Status)) || (*(SHELL_PROMPT_RESPONSE *)Response) !=
> ShellPromptResponseYes) {
> + return EFI_ABORTED;
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +STATIC
> +VOID FormatSize(
> + UINT64 Size, CHAR16 *Buffer)
> +{
> +#define MAX_SIZE_BUF_SIZE 32
> + UINT64 Base, Frac;
> + CHAR16 Metric;
> +
> + Metric = L'B';
> + Frac = 0;
> + if (Size < SIZE_1KB) {
> + Base = Size;
> + } else if (Size < SIZE_1MB) {
> + Base = Size / SIZE_1KB;
> + Frac = ((Size % SIZE_1KB) * 10) >> 10;
> + Metric = L'K';
> + } else if (Size < SIZE_1GB) {
> + Base = Size / SIZE_1MB;
> + Frac = ((Size % SIZE_1MB) * 10) >> 20;
> + Metric = L'M';
> + } else if (Size < SIZE_1TB) {
> + Base = Size / SIZE_1GB;
> + Frac = ((Size % SIZE_1GB) * 10) >> 30;
> + Metric = L'G';
> + } else {
> + Base = Size / SIZE_1TB;
> + Frac = ((Size % SIZE_1TB) * 10) >> 40;
> + Metric = L'T';
> + }
> + if (Frac) {
> + UnicodeSPrint (Buffer, MAX_SIZE_BUF_SIZE, L"%d.%d%c", Base, Frac,
> Metric);
> + } else {
> + UnicodeSPrint (Buffer, MAX_SIZE_BUF_SIZE, L"%d%c", Base, Metric);
> + }
> +}
> +
> +STATIC
> +EFI_STATUS
> +FindAndPrintPartitionableDevices (VOID)
> +{
> + UINTN Index;
> + EFI_HANDLE *HandlePointer;
> + UINTN HandleCount;
> + UINTN DevCount;
> + EFI_STATUS Status;
> + BOOLEAN FirstTime;
> +
> + Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid,
> NULL, &HandleCount, &HandlePointer);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + DevCount = 0;
> + FirstTime = TRUE;
> +
> + for (Index = 0; Index < HandleCount; Index++) {
> + EFI_DEVICE_PATH *DevicePath;
> + CONST CHAR16 *MapPath;
> + CHAR16 *Match;
> + EFI_BLOCK_IO *BlkIo;
> + EFI_DISK_IO *DiskIo;
> + CHAR16 *BufferForSize;
> +
> + Status = gBS->HandleProtocol (HandlePointer[Index],
> &gEfiBlockIoProtocolGuid, (VOID **)&BlkIo);
> + if (EFI_ERROR (Status)) {
> + continue;
> + }
> +
> + DevicePath = DevicePathFromHandle (HandlePointer[Index]);
> + if (!IsPartitionableDevicePath (DevicePath)) {
> + continue;
> + }
> + MapPath = gEfiShellProtocol->GetMapFromDevicePath (&DevicePath);
> + if (MapPath == NULL) {
> + continue;
> + }
> +
> + Status = gBS->HandleProtocol (HandlePointer[Index],
> &gEfiDiskIoProtocolGuid, (VOID **)&DiskIo);
> + if (EFI_ERROR (Status)) {
> + continue;
> + }
> +
> + Match = StrStr (MapPath, L";BLK");
> + if (Match) {
> + MapPath = Match;
> + MapPath++;
> + }
> +
> + if (FirstTime) {
> + BufferForSize = AllocateZeroPool (MAX_SIZE_BUF_SIZE * sizeof
> (CHAR16));
> + ASSERT (BufferForSize);
> + Print (L" Device\t Size Comments\n");
> + Print (L" ------ ------- ------------------------------------------------------------
> \n");
> + FirstTime = FALSE;
> + }
> + GptCleanupGlobals ();
> + FormatSize (MultU64x32 (BlkIo->Media->LastBlock + 1, BlkIo->Media-
> >BlockSize), BufferForSize);
> + ShellPrintHiiEx (-1, -1,
> + NULL, STRING_TOKEN (STR_GPT_LIST_DEVS),
> + gShellGptHiiHandle,
> + MapPath,
> + BufferForSize);
> + if (BlkIo->Media->ReadOnly) {
> + Print (L"Read-Only! ");
> + }
> + if (!BlkIo->Media->MediaPresent) {
> + Print (L"No Media! ");
> + }
> + if (!EFI_ERROR (PartitionGetGptTables (DiskIo, BlkIo))) {
> + Print (L"Valid GPT. ");
> + }
> + if (BlkIo->Media->RemovableMedia) {
> + Print (L"Removable device.");
> + }
> + Print (L"\n");
> + DevCount++;
> + }
> + Print (L"\r\n");
> + if (DevCount) {
> + Print (L"%d potentially partitionable device(s) found\n", DevCount);
> + } else {
> + Print (L"No potentially partitionable device(s) found\n");
> + }
> +
> + GptCleanupGlobals ();
> + return EFI_SUCCESS;
> +}
> +
> +SHELL_STATUS
> +EFIAPI
> +ShellCommandRunGpt (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE *SystemTable
> + )
> +{
> + EFI_STATUS Status;
> + LIST_ENTRY *CheckPackage;
> + EFI_PHYSICAL_ADDRESS Address = 0, Offset = 0;
> + UINT64 PartAttributes = 0;
> + EFI_GUID PartTypeGuid = { 0 };
> + SHELL_FILE_HANDLE FileHandle = NULL;
> + UINT64 ByteCount, FileSize;
> + UINTN I;
> + UINT8 *Buffer = NULL, *FileBuffer = NULL;
> +
> + CHAR16 * ProblemParam,*FilePath;
> + CONST CHAR16 *AddressStr = NULL, *OffsetStr = NULL;
> + CONST CHAR16 *PartName = NULL, *NewPartName = NULL,
> *AttrStr = NULL,
> + *GuidStr = NULL, *VolumeName = NULL;
> + CONST CHAR16 *LengthStr = NULL, *FileStr = NULL;
> + BOOLEAN AddrFlag = FALSE, LengthFlag = TRUE, FileFlag = FALSE,
> GuidFlag = FALSE, OffsetFlag = TRUE;
> + BOOLEAN PartNameFlag = TRUE, NewPartNameFlag = FALSE,
> AttrFlag = FALSE;
> + UINTN Flag = 0, CheckFlag = 0;
> + CONST CHAR16 *BlockName;
> + EFI_DEVICE_PATH_PROTOCOL *DevPath;
> + EFI_BLOCK_IO_PROTOCOL *BlockIo;
> + EFI_DISK_IO_PROTOCOL *DiskIo;
> + EFI_HANDLE BlockIoHandle;
> + MOD_PARAMS ModParams;
> + EFI_PARTITION_ENTRY *Entry;
> + UINTN NumKnownPartTypesEntries;
> + BOOLEAN TableNotEmpty, NoPrompt = FALSE, Quiet = TRUE;
> + UINT64 TimeStampB, TimeStampE, SpeedKB, Freq;
> +
> + // Parse Shell command line
> + Status = ShellInitialize ();
> + if (EFI_ERROR (Status)) {
> + PrintErr (L"Cannot initialize Shell", Status);
> + ASSERT_EFI_ERROR (Status);
> + return SHELL_ABORTED;
> + }
> +
> + Status = ShellCommandLineParse (ParamList, &CheckPackage,
> &ProblemParam, TRUE);
> + if (EFI_ERROR (Status)) {
> + PrintErr (L"Error while parsing command line", Status);
> + return SHELL_ABORTED;
> + }
> +
> + TimeStampB = 0;
> + TimeStampE = 0;
> +
> + NoPrompt = ShellCommandLineGetFlag (CheckPackage, L"-yes");
> + Quiet = !ShellCommandLineGetFlag (CheckPackage, L"-verbose");
> +
> + Freq = GetPerformanceCounterProperties (NULL, NULL);
> +
> + // Check flags provided by user
> + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"clear") << 0);
> + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"create") << 1);
> + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"list") << 2);
> + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"sync") << 3);
> + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"typesinfo") << 4);
> + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"delete") << 5);
> + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"info") << 6);
> + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"read") << 7);
> + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"readfile") << 8);
> + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"rename") << 9);
> + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"setattr") << 10);
> + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"settype") << 11);
> + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"write") << 12);
> + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"writefile") << 13);
> + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"fatformat") << 14);
> +
> + PartitionGetKnownType ((UINTN)(-1), &NumKnownPartTypesEntries);
> +
> + if (Flag & TYPES_INFO) {
> + UINTN Index;
> +
> + Print (L" No\t%-36s\tGUID\r\n", L"Type name");
> + Print (L" ---- ---------------------------------- ------------------------------------
> \n");
> + for (Index = 0; Index < NumKnownPartTypesEntries; Index++) {
> + EFI_KNOWN_PARTITION_TYPE *PartType;
> +
> + PartType = PartitionGetKnownType (Index, NULL);
> + if (PartType == NULL) {
> + break;
> + }
> + Print (L" %3d\t%-36s\t%g\n", Index, PartType->TypeName, &PartType-
> >TypeGuid);
> + }
> + if (Flag == TYPES_INFO) {
> + return SHELL_SUCCESS;
> + }
> + }
> + // Start parsing the command.
> + // Generally command is:
> + // block_name:bootpart_no addr or filename offset
> +
> + BlockName = ShellCommandLineGetRawValue (CheckPackage, 1);
> + if (BlockName == NULL) {
> + if (Flag & LIST) {
> + Status = FindAndPrintPartitionableDevices ();
> + if (EFI_ERROR (Status)) {
> + PrintErr (L"Error getting list of partitionable devices", Status);
> + Status = SHELL_ABORTED;
> + }
> + return Status;
> + }
> + PrintErr (L"Missing block device name", EFI_INVALID_PARAMETER);
> + return SHELL_INVALID_PARAMETER;
> + }
> +
> + // Find device handle by mapped name
> + if (gEfiShellProtocol->GetDevicePathFromMap (BlockName) == NULL) {
> + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
> gShellGptHiiHandle, gAppName, BlockName);
> + Status = SHELL_INVALID_PARAMETER;
> + } else {
> + DevPath = (EFI_DEVICE_PATH_PROTOCOL *)gEfiShellProtocol-
> >GetDevicePathFromMap (BlockName);
> + if (gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &DevPath, NULL)
> == EFI_NOT_FOUND) {
> + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN
> (STR_GEN_MAP_PROTOCOL), gShellGptHiiHandle, gAppName, BlockName,
> L"BlockIo");
> + Status = SHELL_INVALID_PARAMETER;
> + }
> + }
> +
> + if (Status) {
> + return SHELL_INVALID_PARAMETER;
> + }
> +
> + BlockIoHandle = 0;
> +
> + Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid,
> (EFI_DEVICE_PATH_PROTOCOL **)&DevPath, &BlockIoHandle);
> + if (EFI_ERROR (Status)) {
> + goto CleanUp;
> + }
> +
> + Status = gBS->OpenProtocol (BlockIoHandle, &gEfiBlockIoProtocolGuid,
> (VOID **)&BlockIo, gImageHandle, NULL,
> EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> + if (EFI_ERROR (Status)) {
> + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN
> (STR_GEN_MAP_PROTOCOL), gShellGptHiiHandle, gAppName, BlockName,
> L"BlockIo");
> + goto CleanUp;
> + }
> +
> + Status = gBS->HandleProtocol (
> + BlockIoHandle,
> + &gEfiDiskIoProtocolGuid,
> + (VOID **)&DiskIo
> + );
> + if (EFI_ERROR (Status)) {
> + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN
> (STR_GEN_MAP_PROTOCOL), gShellGptHiiHandle, gAppName, BlockName,
> L"DiskIo");
> + goto CleanUp;
> + }
> +
> + CheckFlag = Flag;
> + for (I = 0; CheckFlag; CheckFlag >>= 1) {
> + I += CheckFlag & 1;
> + if (I > 1) {
> + PrintErr (L"Too many flags", EFI_INVALID_PARAMETER);
> + Status = SHELL_INVALID_PARAMETER;
> + goto CleanUp;
> + }
> + }
> +
> + if (Flag & SYNC) {
> + // Let the Partition table driver know that
> + // we want to reread the tables
> + Status = gBS->ReinstallProtocolInterface (
> + BlockIoHandle,
> + &gEfiBlockIoProtocolGuid,
> + BlockIo,
> + BlockIo
> + );
> + Status = SHELL_SUCCESS;
> + goto CleanUp;
> + }
> +
> + if (!IsPartitionableDevicePath (DevicePathFromHandle (BlockIoHandle))) {
> + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
> gShellGptHiiHandle, gAppName, BlockName);
> + Print (L"%s is not a raw block device\n", BlockName);
> + Status = SHELL_INVALID_PARAMETER;
> + goto CleanUp;
> + }
> +
> + if (!BlockIo->Media->MediaPresent) {
> + PrintErr (L"Media is not present!\n", EFI_NO_MEDIA);
> + Status = EFI_NO_MEDIA;
> + goto CleanUp;
> + }
> +
> + // Preload GPT tables with validation
> + Status = PartitionGetGptTables (DiskIo, BlockIo);
> + if (EFI_ERROR (Status)) {
> + BOOLEAN CanContinue;
> +
> + CanContinue = (Flag & CREATE) || (Flag & CLEAR) || (Flag &
> FAT_FORMAT);
> + if (Status != EFI_NOT_FOUND) {
> + PrintErr (L"Unexpected error getting GPT tables", Status);
> + goto CleanUp;
> + } else {
> + if (!CanContinue) {
> + PrintErr (L"No GPT table found. Create first", Status);
> + goto CleanUp;
> + }
> + }
> + }
> +
> + // Do we have any partitions already?
> + TableNotEmpty = (PartitionFindPartitionByCriteria (NULL, 0, 0, SRC_ANY) !=
> NULL);
> +
> + Status = SHELL_INVALID_PARAMETER;
> +
> + if ((Flag < LIST) ||
> + (Flag & DELETE) ||
> + (Flag > READ_FILE)
> + ) {
> + if (BlockIo->Media->ReadOnly) {
> + Status = EFI_INVALID_PARAMETER;
> + PrintErr (L"Cannot write to a read-only device", Status);
> + goto CleanUp;
> + }
> + }
> +
> + if (BlockIo->Media->RemovableMedia) {
> + Print (L"%s is a removable device. Just a note\n", BlockName);
> + }
> +
> + switch (Flag) {
> + case INFO:
> + PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
> + OffsetFlag = FALSE;
> + LengthFlag = FALSE;
> + break;
> + case LIST:
> + {
> + UINTN NumEntries;
> +
> + NumEntries = PartitionListGptEntries ();
> + if (NumEntries == 0) {
> + Print (L"gpt: GPT is valid on %s, but no partition(s) defined yet. Use
> create\n", BlockName);
> + }
> + Status = SHELL_SUCCESS;
> + goto CleanUp;
> + break;
> + }
> + case CLEAR:
> + if (TableNotEmpty) {
> + // Tell the user what he/she is doing...
> + ShellPrintHiiEx (-1, -1,
> + NULL, STRING_TOKEN (STR_GPT_NOT_EMPTY),
> + gShellGptHiiHandle,
> + BlockName
> + );
> + }
> +
> + // Even if GPT tables do not exist, there might be something.
> + // Warn the user and double sure it is the intention,
> + // to prevent a user from bricking a device (JTAG would be needed to
> recover)
> + // by overwriting an ATF boot device. However with NoPrompt on, the
> user is
> + // responsible for operation because there is no confirmation (assuming
> yes on all queries).
> + if ((NoPrompt) || (!GptPromptYesNo (STRING_TOKEN
> (STR_GPT_CLEAR_SURE)) &&
> + (!GptPromptYesNo (STRING_TOKEN
> (STR_GPT_ABSOLUTELY_SURE))))
> + ) {
> + PartitionGptClearAll ();
> + }
> + Status = SHELL_SUCCESS;
> + goto CleanUp;
> + break;
> + case CREATE:
> + PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
> + OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 3);
> + LengthStr = ShellCommandLineGetRawValue (CheckPackage, 4);
> + AttrStr = ShellCommandLineGetRawValue (CheckPackage, 5);
> + GuidStr = ShellCommandLineGetValue (CheckPackage, L"-type");
> + GuidFlag = TRUE;
> + break;
> + case DELETE:
> + PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
> + LengthFlag = FALSE;
> + OffsetFlag = FALSE;
> + break;
> + case RENAME:
> + PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
> + NewPartName = ShellCommandLineGetRawValue (CheckPackage, 3);
> + NewPartNameFlag = TRUE;
> + LengthFlag = FALSE;
> + OffsetFlag = FALSE;
> + break;
> + case SETATTR:
> + PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
> + AttrStr = ShellCommandLineGetRawValue (CheckPackage, 3);
> + AttrFlag = TRUE;
> + LengthFlag = FALSE;
> + OffsetFlag = FALSE;
> + break;
> + case SETTYPE:
> + PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
> + GuidStr = ShellCommandLineGetValue (CheckPackage, L"-type");
> + GuidFlag = TRUE;
> + LengthFlag = FALSE;
> + OffsetFlag = FALSE;
> + break;
> + case FAT_FORMAT:
> + PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
> + VolumeName = ShellCommandLineGetRawValue (CheckPackage, 3);
> + LengthFlag = FALSE;
> + OffsetFlag = FALSE;
> + PartNameFlag = (PartName != NULL);
> + if (!PartNameFlag && TableNotEmpty) {
> + // Tell the user what he/she is doing...
> + ShellPrintHiiEx (-1, -1,
> + NULL, STRING_TOKEN (STR_GPT_NOT_EMPTY),
> + gShellGptHiiHandle,
> + BlockName
> + );
> + }
> + break;
> + // Fall through
> + case READ:
> + case WRITE:
> + AddressStr = ShellCommandLineGetRawValue (CheckPackage, 2);
> + PartName = ShellCommandLineGetRawValue (CheckPackage, 3);
> + OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 4);
> + LengthStr = ShellCommandLineGetRawValue (CheckPackage, 5);
> + AddrFlag = TRUE;
> + break;
> + case READ_FILE:
> + FileStr = ShellCommandLineGetRawValue (CheckPackage, 2);
> + PartName = ShellCommandLineGetRawValue (CheckPackage, 3);
> + OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 4);
> + LengthStr = ShellCommandLineGetRawValue (CheckPackage, 5);
> + FileFlag = TRUE;
> + break;
> + case WRITE_FILE:
> + FileStr = ShellCommandLineGetRawValue (CheckPackage, 2);
> + PartName = ShellCommandLineGetRawValue (CheckPackage, 3);
> + OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 4);
> + LengthFlag = FALSE;
> + FileFlag = TRUE;
> + break;
> + default:
> + Print (L"%s: Unsupported command. Try \"help %s\"", gAppName);
> + Status = SHELL_INVALID_PARAMETER;
> + goto CleanUp;
> + }
> +
> + // Read address parameter
> + if ((AddressStr == NULL) & AddrFlag) {
> + PrintErr (L"No address parameter", EFI_INVALID_PARAMETER);
> + goto CleanUp;
> + } else if (AddrFlag) {
> + Address = ShellHexStrToUintn (AddressStr);
> + if (Address == (UINTN)(-1)) {
> + PrintErr (L"Wrong address parameter", EFI_INVALID_PARAMETER);
> + goto CleanUp;
> + }
> + }
> +
> + if ((PartName == NULL) & PartNameFlag) {
> + PrintErr (L"Missing partition name", EFI_INVALID_PARAMETER);
> + goto CleanUp;
> + } else if (PartNameFlag) {
> + if (StrSize (PartName) > MAX_PARTITION_NAME_LENGTH) {
> + PrintErr (L"Partition name is too long (max 36 chars)",
> EFI_INVALID_PARAMETER);
> + goto CleanUp;
> + }
> + }
> +
> + // Read offset parameter
> + if ((OffsetStr == NULL) & OffsetFlag) {
> + PrintErr (L"No offset Parameter", EFI_INVALID_PARAMETER);
> + goto CleanUp;
> + } else if (OffsetFlag) {
> + Offset = ShellHexStrToUintn (OffsetStr);
> + if (Offset < 0) {
> + Print (L"%s: Wrong offset parameter: %s\n", gAppName, OffsetStr);
> + goto CleanUp;
> + }
> + }
> +
> + // Read length parameter
> + if ((LengthStr == NULL) & LengthFlag) {
> + PrintErr (L"No length parameter", EFI_INVALID_PARAMETER);
> + goto CleanUp;
> + } else if (LengthFlag) {
> + ByteCount = (UINT64)ShellStrToUintn (LengthStr);
> + if (ByteCount < 0) {
> + Print (L"%s: Wrong length parameter %s!\n", gAppName, LengthStr);
> + goto CleanUp;
> + }
> + }
> +
> + if ((NewPartName == NULL) & NewPartNameFlag) {
> + PrintErr (L"Missing name to be assigned to partition",
> EFI_INVALID_PARAMETER);
> + goto CleanUp;
> + } else if (NewPartNameFlag) {
> + if (StrSize (NewPartName) > MAX_PARTITION_NAME_LENGTH) {
> + PrintErr (L"Partition name is too long (max 36 chars)",
> EFI_INVALID_PARAMETER);
> + goto CleanUp;
> + }
> + }
> +
> + if ((AttrStr == NULL) & AttrFlag) {
> + PrintErr (L"Missing attributes parameter", EFI_INVALID_PARAMETER);
> + goto CleanUp;
> + } else if (AttrStr) {
> + PartAttributes = (UINT64)ShellStrToUintn (AttrStr);
> + }
> +
> + if ((GuidStr == NULL) & GuidFlag) {
> + PrintErr (L"Missing partition type GUID parameter",
> EFI_INVALID_PARAMETER);
> + goto CleanUp;
> + } else if (GuidFlag) {
> + Status = SHELL_INVALID_PARAMETER;
> + if (InternalShellIsHexOrDecimalNumber (GuidStr, FALSE, TRUE, FALSE)) {
> + UINTN Ordinal;
> +
> + Ordinal = ShellStrToUintn (GuidStr);
> + if (Ordinal < NumKnownPartTypesEntries) {
> + PartTypeGuid = PartitionGetKnownType (Ordinal, NULL)->TypeGuid;
> + Status = SHELL_SUCCESS;
> + } else {
> + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
> gShellGptHiiHandle, gAppName, GuidStr);
> + goto CleanUp;
> + }
> + } else {
> + Status = ConvertStringToGuid (GuidStr, &PartTypeGuid);
> + if ((EFI_ERROR (Status)) || (IsZeroGuid (&PartTypeGuid))) {
> + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
> gShellGptHiiHandle, gAppName, GuidStr);
> + Status = SHELL_INVALID_PARAMETER;
> + goto CleanUp;
> + }
> + }
> + }
> +
> + if (FileFlag) {
> + // Read FilePath parameter
> + if (FileStr == NULL) {
> + PrintErr (L"No FilePath parameter", EFI_INVALID_PARAMETER);
> + goto CleanUp;
> + } else {
> + FilePath = (CHAR16 *)FileStr;
> + Status = ShellIsFile (FilePath);
> + // When read file into flash, file doesn't have to exist
> + if (EFI_ERROR (Status && !(Flag & READ_FILE))) {
> + PrintErr (L"Wrong FilePath parameter", Status);
> + Status = SHELL_INVALID_PARAMETER;
> + goto CleanUp;
> + }
> + }
> +
> + Status = OpenAndPrepareFile (FilePath, &FileHandle, ((Flag &
> READ_FILE) != 0));
> + if (EFI_ERROR (Status)) {
> + Print (L"Error %r while preparing file %s", Status, FilePath);
> + Status = SHELL_ABORTED;
> + goto CleanUp;
> + }
> +
> + // Get file size in order to check correctness at the end of transfer
> + if (Flag & (WRITE_FILE)) {
> + Status = FileHandleGetSize (FileHandle, &FileSize);
> + if (EFI_ERROR (Status)) {
> + PrintErr (L"Cannot get file size", Status);
> + Status = SHELL_ABORTED;
> + goto CleanUp;
> + }
> + ByteCount = (UINT64)FileSize;
> + }
> +
> + FileBuffer = AllocateZeroPool ((UINTN)ByteCount);
> + if (FileBuffer == NULL) {
> + PrintErr (L"Cannot allocate memory", EFI_OUT_OF_RESOURCES);
> + Status = SHELL_OUT_OF_RESOURCES;
> + goto Error_Close_File;
> + }
> +
> + // Read file content and store it in FileBuffer
> + if (Flag & (WRITE_FILE)) {
> + if (!Quiet) {
> + Print (L"Reading %s...\r", FilePath);
> + }
> + Status = FileHandleRead (FileHandle, &ByteCount, FileBuffer);
> + if (EFI_ERROR (Status)) {
> + PrintErr (L"Read from file error", Status);
> + Status = SHELL_ABORTED;
> + goto Error_Free_Buffer;
> + } else if (ByteCount != (UINTN)FileSize) {
> + PrintErr (L"Not whole file read. Abort", EFI_DEVICE_ERROR);
> + Status = SHELL_DEVICE_ERROR;
> + goto Error_Free_Buffer;
> + }
> + if (!Quiet) {
> + Print (L"Writing %s into device %s, partition %s...\n", FilePath,
> BlockName, PartName);
> + }
> + }
> + }
> +
> + Buffer = (UINT8 *)Address;
> + if (FileFlag) {
> + Buffer = FileBuffer;
> + }
> +
> + if (Flag > TYPES_INFO) {
> + Entry = PartitionFindPartitionByCriteria (PartName, 0, 0, SRC_BY_NAME);
> + if (!Entry && PartName && (InternalShellIsHexOrDecimalNumber
> (PartName, FALSE, TRUE, FALSE))) {
> + Entry = PartitionFindPartitionByCriteria (PartName, 0, 0, SRC_BY_NUM);
> + }
> + if ((!Entry) && (PartNameFlag)) {
> + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
> gShellGptHiiHandle, gAppName, PartName);
> + Print (L"Could not find partition %s (case-sensitive). Make sure the name
> is spelled properly\n", PartName);
> + Status = SHELL_NOT_FOUND;
> + goto CleanUp;
> + }
> + }
> +
> + switch (Flag) {
> + case CREATE:
> + PartitionGptCreatePartition (
> + PartName,
> + Offset, // Lba. If 0, the next available is assumed
> + ByteCount, // in MegaBytes. If 0 the whole remaining space is assumed
> + PartAttributes,
> + PartTypeGuid);
> + break;
> + case DELETE:
> + ModParams.PartName = PartName;
> + ShellPrintHiiEx (-1, -1,
> + NULL, STRING_TOKEN (STR_GPT_DELETE_WARNING),
> + gShellGptHiiHandle,
> + Entry->PartitionName
> + );
> + if ((NoPrompt) || (!GptPromptYesNo (STRING_TOKEN
> (STR_GPT_ABSOLUTELY_SURE)))) {
> + Status = PartitionGptModifyPartition (
> + Entry, &ModParams, MOD_DELETE);
> + if (EFI_ERROR (Status)) {
> + PrintErr (L"Error deleting the partition", Status);
> + Status = SHELL_ABORTED;
> + goto CleanUp;
> + }
> + Status = SHELL_SUCCESS;
> + } else {
> + Status = SHELL_ABORTED;
> + }
> + break;
> + case FAT_FORMAT:
> + {
> + EFI_LBA StartingLBA, EndingLBA;
> + CHAR8 LabelName[12];
> +
> + if (VolumeName) {
> + if (StrLen (VolumeName) > 11) {
> + Status = EFI_INVALID_PARAMETER;
> + PrintErr (L"The volume label is too long", Status);
> + Status = SHELL_INVALID_PARAMETER;
> + goto CleanUp;
> + }
> + UnicodeStrToAsciiStr (VolumeName, (CHAR8 *)LabelName);
> + }
> + ShellPrintHiiEx (-1, -1,
> + NULL, STRING_TOKEN (STR_GPT_FORMAT_WARNING),
> + gShellGptHiiHandle,
> + Entry ? Entry->PartitionName : BlockName
> + );
> +
> + if ((NoPrompt) || (!GptPromptYesNo (STRING_TOKEN
> (STR_GPT_FORMAT_SURE)) &&
> + (!GptPromptYesNo (STRING_TOKEN
> (STR_GPT_ABSOLUTELY_SURE))))
> + ) {
> + StartingLBA = 0;
> + EndingLBA = BlockIo->Media->LastBlock;
> + if (Entry) {
> + StartingLBA = Entry->StartingLBA;
> + EndingLBA = Entry->EndingLBA;
> + }
> + if (!Quiet) {
> + Print (L"Formatting %s to FAT32...\r", PartNameFlag ? Entry-
> >PartitionName : BlockName);
> + }
> + Status = FatFormat (StartingLBA, EndingLBA, BlockIo, DiskIo,
> VolumeName ? LabelName : NULL, TRUE);
> + if (EFI_ERROR (Status)) {
> + PrintErr (L"Error formatting the partition to FAT ", Status);
> + Status = SHELL_ABORTED;
> + goto CleanUp;
> + } else if (!Quiet) {
> + Print (L"%s successfully formatted to FAT. Formatted size %llu MiB\n",
> + PartNameFlag ? Entry->PartitionName : BlockName,
> + MultU64x32 (EndingLBA - StartingLBA + 1, BlockIo->Media-
> >BlockSize) >> 20
> + );
> + }
> + } else {
> + Status = SHELL_ABORTED;
> + }
> + }
> + break;
> + case RENAME:
> + ModParams.PartName = PartName;
> + ModParams.NewName = NewPartName;
> + Status = PartitionGptModifyPartition (
> + Entry, &ModParams, MOD_RENAME);
> + break;
> + case SETATTR:
> + ModParams.Attributes = PartAttributes;
> + Status = PartitionGptModifyPartition (
> + Entry, &ModParams, MOD_ATTR);
> + break;
> + case SETTYPE:
> + ModParams.PartTypeGuid = PartTypeGuid;
> + Status = PartitionGptModifyPartition (
> + Entry, &ModParams, MOD_TYPE);
> + break;
> + case INFO:
> + PartitionPrintGptPartInfo (Entry);
> + Status = SHELL_SUCCESS;
> + break;
> + case READ:
> + case READ_FILE:
> + case WRITE:
> + case WRITE_FILE:
> + {
> + UINT64 MaxBytes;
> + BOOLEAN OpRead;
> +
> + OpRead = ((Flag & READ) || (Flag & READ_FILE));
> + MaxBytes = MultU64x32 (
> + Entry->EndingLBA - Entry->StartingLBA,
> + BlockIo->Media->BlockSize) +
> + BlockIo->Media->BlockSize -
> + MultU64x32 (Offset, BlockIo->Media->BlockSize);
> + if (ByteCount > MaxBytes) {
> + Status = EFI_INVALID_PARAMETER;
> + ShellPrintHiiEx (-1, -1,
> + NULL, (OpRead) ?
> + STRING_TOKEN (STR_GPT_READ_BOUNDARY) :
> + STRING_TOKEN (STR_GPT_WRITE_BOUNDARY),
> + gShellGptHiiHandle,
> + gAppName,
> + Entry->PartitionName,
> + MaxBytes,
> + ByteCount
> + );
> + Status = SHELL_INVALID_PARAMETER;
> + goto CleanUp;
> + }
> +
> + TimeStampB = GetPerformanceCounter ();
> + if (OpRead) {
> + Status = DiskIo->ReadDisk (DiskIo,
> + BlockIo->Media->MediaId,
> + MultU64x32 (Offset + Entry->StartingLBA, BlockIo-
> >Media->BlockSize), ByteCount, Buffer);
> + } else {
> + Status = DiskIo->WriteDisk (DiskIo, BlockIo->Media->MediaId,
> + MultU64x32 (Offset + Entry->StartingLBA, BlockIo-
> >Media->BlockSize), ByteCount, Buffer);
> + }
> + }
> + break;
> + default:
> + Status = SHELL_INVALID_PARAMETER;
> + PrintErr (L"Unknown command. Try \"help gpt\"",
> EFI_INVALID_PARAMETER);
> + goto CleanUp;
> + }
> +
> + if (EFI_ERROR (Status)) {
> + PrintErr (L"Error while performing transfer\n", Status);
> + Status = SHELL_ABORTED;
> + goto CleanUp;
> + }
> +
> + TimeStampE = ((GetPerformanceCounter () - TimeStampB) * 1000) / Freq;
> + SpeedKB = TimeStampE ? (ByteCount / (TimeStampE / 1000)) >> 10 : 0;
> +
> + switch (Flag) {
> + case WRITE:
> + case WRITE_FILE:
> + if (!Quiet) {
> + ShellPrintHiiEx (-1, -1,
> + NULL,
> + STRING_TOKEN (STR_GPT_WRITE_OK),
> + gShellGptHiiHandle,
> + ByteCount,
> + Offset,
> + Entry->PartitionName,
> + TimeStampE,
> + SpeedKB
> + );
> + }
> + break;
> + case READ:
> + if (!Quiet) {
> + ShellPrintHiiEx (-1, -1,
> + NULL,
> + STRING_TOKEN (STR_GPT_READ_OK),
> + gShellGptHiiHandle,
> + ByteCount,
> + Offset,
> + Entry->PartitionName,
> + TimeStampE,
> + SpeedKB
> + );
> + }
> + break;
> + case READ_FILE:
> + Status = FileHandleWrite (FileHandle, &ByteCount, FileBuffer);
> + if (EFI_ERROR (Status)) {
> + ShellPrintHiiEx (-1, -1,
> + NULL,
> + STRING_TOKEN (STR_GPT_FILE_WRITE_FAIL),
> + gShellGptHiiHandle,
> + gAppName,
> + FilePath,
> + Status
> + );
> + Status = SHELL_DEVICE_ERROR;
> + goto Error_Free_Buffer;
> + }
> +
> + if (!Quiet) {
> + ShellPrintHiiEx (-1, -1,
> + NULL,
> + STRING_TOKEN (STR_GPT_READFILE_OK),
> + gShellGptHiiHandle,
> + ByteCount,
> + Offset,
> + Entry->PartitionName,
> + FilePath,
> + TimeStampE,
> + SpeedKB
> + );
> + }
> + break;
> + }
> +
> + if (FileFlag) {
> + SHELL_FREE_NON_NULL (FileBuffer);
> + if (FileHandle != NULL) {
> + ShellCloseFile (&FileHandle);
> + FileHandle = NULL;
> + }
> + }
> +
> + Status = SHELL_SUCCESS;
> +
> + Error_Free_Buffer:
> + SHELL_FREE_NON_NULL (FileBuffer);
> + Error_Close_File:
> + if (FileHandle) {
> + ShellCloseFile (&FileHandle);
> + }
> + CleanUp:
> + if (BlockIoHandle) {
> + // By UEFI Spec blocks must be flushed
> + BlockIo->FlushBlocks (BlockIo);
> + gBS->CloseProtocol (BlockIoHandle, &gEfiBlockIoProtocolGuid,
> gImageHandle, NULL);
> + }
> +
> + GptCleanupGlobals ();
> +
> + ShellCommandLineFreeVarList (CheckPackage);
> +
> + if (EFI_ERROR (Status)) {
> + Status = SHELL_ABORTED;
> + }
> +
> + return Status;
> +}
> +
> +EFI_STATUS
> +EFIAPI
> +ShellGptLibConstructor (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE *SystemTable
> + )
> +{
> + gShellGptHiiHandle = NULL;
> +
> + gShellGptHiiHandle = HiiAddPackages (
> + &gShellGptHiiGuid, gImageHandle,
> + UefiShellGptCommandLibStrings, NULL
> + );
> + if (gShellGptHiiHandle == NULL) {
> + return EFI_DEVICE_ERROR;
> + }
> +
> + ShellCommandRegisterCommandName (
> + gAppName, ShellCommandRunGpt, ShellCommandGetManFileNameGpt,
> 0,
> + gAppName, TRUE, gShellGptHiiHandle, STRING_TOKEN
> (STR_GET_HELP_GPT)
> + );
> +
> + return EFI_SUCCESS;
> +}
> +
> +EFI_STATUS
> +EFIAPI
> +ShellGptLibDestructor (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE *SystemTable
> + )
> +{
> +
> + if (gShellGptHiiHandle != NULL) {
> + HiiRemovePackages (gShellGptHiiHandle);
> + }
> + return EFI_SUCCESS;
> +}
> diff --git
> a/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> new file mode 100644
> index 000000000000..1be4b1ab0f11
> --- /dev/null
> +++
> b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> @@ -0,0 +1,79 @@
> +#
> +# Marvell BSD License Option
> +#
> +# If you received this File from Marvell, you may opt to use, redistribute
> +# and/or modify this File under the following licensing terms.
> +# Redistribution and use in source and binary forms, with or without
> +# modification, are permitted provided that the following conditions are
> met:
> +#
> +# * Redistributions of source code must retain the above copyright notice,
> +# this list of conditions and the following disclaimer.
> +#
> +# * Redistributions in binary form must reproduce the above copyright
> +# notice, this list of conditions and the following disclaimer in the
> +# documentation and/or other materials provided with the distribution.
> +#
> +# * Neither the name of Marvell nor the names of its contributors may be
> +# used to endorse or promote products derived from this software without
> +# specific prior written permission.
> +#
> +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> CONTRIBUTORS "AS IS"
> +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> LIMITED TO, THE
> +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
> PARTICULAR PURPOSE ARE
> +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> CONTRIBUTORS BE LIABLE
> +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> CONSEQUENTIAL
> +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
> SUBSTITUTE GOODS OR
> +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
> HOWEVER
> +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
> STRICT LIABILITY,
> +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
> OUT OF THE USE
> +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> DAMAGE.
> +#
> +
> +#
> +# Portions Copyright (C) 2016 Broadcom
> +#
> +
> +[Defines]
> + INF_VERSION = 0x00010006
> + BASE_NAME = UefiShellGptCommandLib
> + FILE_GUID = F62ACF25-0D15-22F5-E642-FFB6515E00D7
> + MODULE_TYPE = UEFI_APPLICATION
> + VERSION_STRING = 0.1
> + LIBRARY_CLASS = NULL|UEFI_APPLICATION UEFI_DRIVER
> + CONSTRUCTOR = ShellGptLibConstructor
> + DESTRUCTOR = ShellGptLibDestructor
> +
> +[Sources]
> + FatFormat.c
> + GptWorker.c
> + UefiShellGptCommandLib.c
> + UefiShellGptCommandLib.uni
> +
> +[Packages]
> + MdeModulePkg/MdeModulePkg.dec
> + MdePkg/MdePkg.dec
> + ShellPkg/ShellPkg.dec
> +
> +[LibraryClasses]
> + BaseLib
> + BaseMemoryLib
> + DebugLib
> + DevicePathLib
> + FileHandleLib
> + HiiLib
> + MemoryAllocationLib
> + PcdLib
> + ShellCommandLib
> + ShellLib
> + UefiBootServicesTableLib
> + UefiRuntimeServicesTableLib
> + UefiLib
> +
> +[Protocols]
> + gEfiBlockIoProtocolGuid
> + gEfiDevicePathProtocolGuid
> + gEfiDiskIoProtocolGuid
> +
> +[Guids]
> + gShellGptHiiGuid
> + gEfiPartTypeUnusedGuid ## SOMETIMES_CONSUMES ## GUID
> diff --git
> a/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
> b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
> new file mode 100644
> index 000000000000..55bcb42cfeb3
> --- /dev/null
> +++
> b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
> @@ -0,0 +1,117 @@
> +/*********************************************************
> **********************
> +Copyright (C) 2016 Marvell International Ltd.
> +
> +Marvell BSD License Option
> +
> +If you received this File from Marvell, you may opt to use, redistribute
> and/or
> +modify this File under the following licensing terms.
> +Redistribution and use in source and binary forms, with or without
> modification,
> +are permitted provided that the following conditions are met:
> +
> + * Redistributions of source code must retain the above copyright notice,
> + this list of conditions and the following disclaimer.
> +
> + * Redistributions in binary form must reproduce the above copyright
> + notice, this list of conditions and the following disclaimer in the
> + documentation and/or other materials provided with the distribution.
> +
> + * Neither the name of Marvell nor the names of its contributors may be
> + used to endorse or promote products derived from this software
> without
> + specific prior written permission.
> +
> +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> CONTRIBUTORS "AS IS" AND
> +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
> THE IMPLIED
> +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> PURPOSE ARE
> +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> CONTRIBUTORS BE LIABLE FOR
> +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> CONSEQUENTIAL DAMAGES
> +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
> OR SERVICES;
> +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
> CAUSED AND ON
> +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> TORT
> +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
> THE USE OF THIS
> +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +
> +*********************************************************
> **********************/
> +
> +/* Portions Copyright (C) 2016 Broadcom */
> +/=#
> +
> +#langdef en-US "english"
> +
> +#string STR_GEN_PARAM_INV #language en-US "%H%s%N: Invalid
> argument - '%H%s%N'\r\n"
> +#string STR_GEN_MAP_PROTOCOL #language en-US "%H%s%N:
> Mapped device '%B%s%N' does not have protocol %B%s%N\r\n"
> +
> +#string STR_GPT_ERROR #language en-US "%H%s%N: %r - %s\r\n"
> +#string STR_GPT_NOT_EMPTY #language en-US "%H%s%N: WARNING!!!
> This device has valid GPT partition tables!\r\n"
> +#string STR_GPT_CLEAR_SURE #language en-US "Are you sure you want
> to clear the GPT tables on this device? %BY%Nes, %BN%No "
> +#string STR_GPT_ABSOLUTELY_SURE #language en-US "\r\nAre you ***
> ABSOLUTELY SURE *** you want to perform this
> operation ? %BY%Nes, %BN%No "
> +#string STR_GPT_FORMAT_WARNING #language en-US "%H%s%N:
> WARNING!!! Formatting of this partition will destroy all data on it!\r\n"
> +#string STR_GPT_FORMAT_SURE #language en-US "Are you sure you
> want to format this partition to FAT32 and destroy all data on
> it ? %BY%Nes, %BN%No "
> +#string STR_GPT_DELETE_WARNING #language en-US "%H%s%N: Deleting
> of this partition will make data on it unreachable!\r\n"
> +#string STR_GPT_READ_BOUNDARY #language en-US "%H%s%N: Attempt
> to read beyond %H%s%N partition boundary (can read upto %llu bytes from
> the given offset, requested %llu bytes)\r\n"
> +#string STR_GPT_WRITE_BOUNDARY #language en-US "%H%s%N:
> Attempt to write beyond %H%s%N partition boundary (can write upto %llu
> bytes from the given offset, requested %llu bytes)\r\n"
> +#string STR_GPT_FILE_WRITE_FAIL #language en-US "%H%s%N: Failed to
> write to the file %s, error %r\r\n"
> +
> +#string STR_GPT_WRITE_OK #language en-US "Written %llu bytes at
> offset 0x%x, partition %s. Elapsed time %llums (%llu KB/s)\r\n"
> +#string STR_GPT_READ_OK #language en-US "Read %llu bytes from
> offset 0x%x, partition %s. Elapsed time %llums (%llu KB/s)\r\n"
> +#string STR_GPT_READFILE_OK #language en-US "Read %llu bytes from
> offset 0x%x, partition %s into file %s. Elapsed time %llums (%llu KB/s)\r\n"
> +#string STR_GPT_LIST_DEVS #language en-US " %H%+6s%N %+8s "
> +
> +#string STR_GET_HELP_GPT #language en-US ""
> +".TH gpt 0 "GPT partition manager."\r\n"
> +".SH NAME\r\n"
> +"Manages GPT partitions on a block device.\r\n"
> +".SH SYNOPSIS\r\n"
> +" \r\n"
> +"gpt [read | readfile | write | writefile | list | info | clear |\r\n"
> +" create | delete | rename | setattrs | sync | fatformat | -typesinfo | -yes]
> \r\n"
> +"This is a complex utility. Please see examples for usage info\r\n"
> +".SH OPTIONS\r\n"
> +" \r\n"
> +" Device - Block device to be used for the operation\r\n"
> +" Length - Number of bytes to transfer (for read/write))\r\n"
> +" Address - Address in RAM to store/load data\r\n"
> +" Offset - Offset (in blocks) from beggining of the specifie partition to
> store/load data\r\n"
> +" FilePath - Path to file to read data into or write/update data from\r\n"
> +" -yes - Assume yes for all queries, do not prompt\r\n\r\n"
> +".SH EXAMPLES\r\n"
> +" \r\n"
> +"EXAMPLES:\r\n"
> +"Get the list of available partitionable block device(s)\r\n"
> +" gpt %Hlist%N\r\n"
> +"Get info on the particular partition with name PartitionName on the block
> device blk0:\r\n"
> +" gpt %Hinfo%N blk0: PartitionName\r\n"
> +"List all available GPT partitions on the block device blk0:\r\n"
> +" gpt list blk0:\r\n"
> +"Note: the ordinal number shown by this command can be used as a
> partition name in any command requiring partition name\r\n"
> +"Thus gpt info blk0: 1 is valid if there is a partition with ordinal 1 present in
> the output of gpt list command\r\n"
> +"Get information on all recognized partition types\r\n"
> +" gpt %Htypesinfo%N\r\n"
> +"Clear partitions information and install empty GPT tables for a block device
> blk0:\r\n"
> +" gpt %Hclear%N blk0:\r\n"
> +"Create a GPT partition with name PartitionName and type EFI SYSTEM in
> the GPT table, using the next available LBA, with size\r\n"
> +"64MiB, with system attribute, on block device blk0:\r\n"
> +" gpt %Hcreate%N blk0: PartitionName 0 64 1 -type 0\r\n"
> +"Same as above, but now the partition type is not known to the gpt utility,
> so use some GUID known to a 3rd party\r\n"
> +" gpt create blk0: PartitionName 0 64 1 -type 44581A4A-C834-D1A6-2602-
> 9D522A8F2307\r\n"
> +"Rename the GPT partition PartitionName on blk0: to
> NewPartitionName\r\n"
> +" gpt %Hrename%N blk0: PartitionName NewPartitionName\r\n"
> +"Have the PartitionDxe driver to re-read GPT tables on a block device
> blk0:(after they were updated with gpt utility)\r\n"
> +" gpt %Hsync%N blk0:\r\n"
> +"Read 4K from block offset 0x0e000 in Partition named PartitionName of
> the block device at blk0: into RAM at address 0x100000\r\n"
> +" gpt %Hread%N blk0: 0x100000 PartitionName 0xe000 4096\r\n"
> +"Write 512 bytes from 0x200000 at RAM into the block device at blk0:
> partition PartitionName at offset 0x1000\r\n"
> +" gpt %Hwrite%N blk0: 0x200000 PartitionName 0x1000 512\r\n"
> +"Read 0x3000 bytes from 0x0 offset of Partition PartitionName at the block
> device blk0: into file fs2:file.bin\r\n"
> +" gpt %Hreadfile%N blk0: fs2:file.bin PartitionName 0x0 0x3000\r\n"
> +"Write contents of file fs2:file.bin into partition named PartitionName with
> offset (in lba) 0x10 on a block device blk0:\r\n"
> +" gpt %Hwritefile%N blk0: fs2:file.bin PartitionName 0x10\r\n"
> +"FAT Format the partition PartitionName on block device blk0:\r\n"
> +" gpt %Hfatformat%N blk0: PartitionName\r\n"
> +"FAT Format the whole device blk0:\r\n"
> +" gpt fatformat blk0:\r\n"
> +
> +".SH RETURNVALUES\r\n"
> +" \r\n"
> +"RETURN VALUES:\r\n"
> +" SHELL_SUCCESS The action was completed as requested.\r\n"
> +" Specific Shell error Error while processing command\r\n"
> diff --git a/ShellPkg/ShellPkg.dec b/ShellPkg/ShellPkg.dec
> index 39f8012b98c1..5374a2a62d5f 100644
> --- a/ShellPkg/ShellPkg.dec
> +++ b/ShellPkg/ShellPkg.dec
> @@ -56,6 +56,7 @@ [Guids]
> gShellNetwork2HiiGuid = {0x174b2b5, 0xf505, 0x4b12, {0xaa, 0x60,
> 0x59, 0xdf, 0xf8, 0xd6, 0xea, 0x37}}
> gShellTftpHiiGuid = {0x738a9314, 0x82c1, 0x4592, {0x8f, 0xf7, 0xc1,
> 0xbd, 0xf1, 0xb2, 0x0e, 0xd4}}
> gShellBcfgHiiGuid = {0x5f5f605d, 0x1583, 0x4a2d, {0xa6, 0xb2, 0xeb,
> 0x12, 0xda, 0xb4, 0xa2, 0xb6}}
> + gShellGptHiiGuid = {0x5a1ed739, 0x5ef1, 0x429a, {0x8d, 0xf8, 0x28,
> 0xc9, 0x92, 0x64, 0xd7, 0xf8}}
>
> [Protocols]
> gEfiShellProtocolGuid = {0x6302d008, 0x7f9b, 0x4f30, {0x87, 0xac,
> 0x60, 0xc9, 0xfe, 0xf5, 0xda, 0x4e}}
> diff --git a/ShellPkg/ShellPkg.dsc b/ShellPkg/ShellPkg.dsc
> index 809bd4220af2..984c1d0ad48b 100644
> --- a/ShellPkg/ShellPkg.dsc
> +++ b/ShellPkg/ShellPkg.dsc
> @@ -89,6 +89,7 @@ [Components]
>
> ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib
> .inf
>
> ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib
> .inf
>
> ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsL
> ib.inf
> + ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
>
> ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLi
> b.inf
>
> ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1Commands
> Lib.inf
>
> ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1Comm
> andsLib.inf
> @@ -119,6 +120,9 @@ [Components]
> !ifdef $(INCLUDE_TFTP_COMMAND)
>
> NULL|ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib
> .inf
> !endif #$(INCLUDE_TFTP_COMMAND)
> +!ifdef $(INCLUDE_GPT_COMMAND)
> +
> NULL|ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.
> inf
> +!endif #$(INCLUDE_GPT_COMMAND)
> !endif #$(NO_SHELL_PROFILES)
> }
>
> --
> 1.9.1
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] GPT Shell Application/Library
2016-10-18 1:45 ` Ni, Ruiyu
@ 2016-10-18 1:48 ` Tim Lewis
2016-10-18 1:55 ` Ni, Ruiyu
0 siblings, 1 reply; 20+ messages in thread
From: Tim Lewis @ 2016-10-18 1:48 UTC (permalink / raw)
To: Ni, Ruiyu, Vladimir Olovyannikov, Carsey, Jaben,
edk2-devel@lists.01.org
We would prefer that this tool be external. Tim
-----Original Message-----
From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of Ni, Ruiyu
Sent: Monday, October 17, 2016 6:46 PM
To: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>; Carsey, Jaben <jaben.carsey@intel.com>; edk2-devel@lists.01.org
Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
Jaben,
Do you think that providing a standalone gpt.efi is better? So that Shell.efi only provides the internal commands listed in Shell spec.
Thanks/Ray
> -----Original Message-----
> From: Vladimir Olovyannikov [mailto:vladimir.olovyannikov@broadcom.com]
> Sent: Sunday, October 16, 2016 1:24 PM
> To: Carsey, Jaben <jaben.carsey@intel.com>; edk2-devel@lists.01.org; Ni,
> Ruiyu <ruiyu.ni@intel.com>
> Cc: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>
> Subject: [PATCH] GPT Shell Application/Library
>
> This allows managing (create, delete, modify, fat format) of GPT
> partitions from within UEFI Shell.
> Syntax:
> gpt <command> [device_mapped_name] [parameters...]
> See usage examples in the .uni file
> ---
> .../Library/UefiShellGptCommandLib/FatFormat.c | 611 +++++++
> .../Library/UefiShellGptCommandLib/FatFormat.h | 111 ++
> .../Library/UefiShellGptCommandLib/GptWorker.c | 1902
> ++++++++++++++++++++
> .../Library/UefiShellGptCommandLib/GptWorker.h | 186 ++
> .../UefiShellGptCommandLib.c | 1135 ++++++++++++
> .../UefiShellGptCommandLib.inf | 79 +
> .../UefiShellGptCommandLib.uni | 117 ++
> ShellPkg/ShellPkg.dec | 1 +
> ShellPkg/ShellPkg.dsc | 4 +
> 9 files changed, 4146 insertions(+)
> create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> create mode 100644
> ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> create mode 100644
> ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> create mode 100644
> ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> create mode 100644
> ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> create mode 100644
> ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> create mode 100644
> ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
>
> diff --git a/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> new file mode 100644
> index 000000000000..ba7904e6be28
> --- /dev/null
> +++ b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> @@ -0,0 +1,611 @@
> +/** @file
> +
> + Copyright (c) 2003 - 2012, Rob Riglar, Ultra-Embedded.com. All rights
> reserved<BR>
> +
> + This program and the accompanying materials
> + are licensed and made available under the terms and conditions of the BSD
> License
> + which accompanies this distribution. The full text of the license may be
> found at
> + http://opensource.org/licenses/bsd-license.php
> +
> + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +/* Portions Copyright (c) 2016, Broadcom. All rights reserved */
> +
> +#include "FatFormat.h"
> +
> +//-----------------------------------------------------------------------------
> +// Tables
> +//-----------------------------------------------------------------------------
> +typedef struct
> +{
> + UINT64 Sectors;
> + UINT8 SectorsPerCluster;
> +} SectorsPerClusterTable;
> +
> +STATIC SectorsPerClusterTable ClusterSizeTable16[] =
> +{
> + { 32680, 2 }, // 16MB - 1K
> + { 262144, 4 }, // 128MB - 2K
> + { 524288, 8 }, // 256MB - 4K
> + { 1048576, 16 }, // 512MB - 8K
> + { 2097152, 32 }, // 1GB - 16K
> + { 4194304, 64 }, // 2GB - 32K
> + { 8388608, 128 }, // 2GB - 64K [Warning only supported by Windows XP
> onwards]
> + { 0, 0 } // Invalid
> +};
> +
> +STATIC SectorsPerClusterTable ClusterSizeTable32[] =
> +{
> + { 532480, 1 }, // 260MB - 512b
> + { 16777216, 8 }, // 8GB - 4K
> + { 33554432, 16 }, // 16GB - 8K
> + { 67108864, 32 }, // 32GB - 16K
> + { 0xFFFFFFFF, 64 }, // >32GB - 32K
> + { 0, 0 } // Invalid
> +};
> +
> +STATIC
> +EFI_LBA LbaOfCluster (
> + IN FATFS *Fs,
> + IN UINT64 ClusterNumber
> + )
> +{
> + if (Fs->FatType == FAT_TYPE_16)
> + return (Fs->ClusterBeginLba +
> + (Fs->RootEntryCount * 32 / FAT_SECTOR_SIZE) +
> + ((ClusterNumber - 2) * Fs->SectorsPerCluster));
> + else
> + return ((Fs->ClusterBeginLba +
> + ((ClusterNumber - 2) * Fs->SectorsPerCluster)));
> +}
> +
> +//-----------------------------------------------------------------------------
> +// fatfs_calc_cluster_size: Calculate what cluster size should be used
> +//-----------------------------------------------------------------------------
> +STATIC
> +UINT8 CalcClusterSize (
> + IN UINTN Sectors,
> + IN BOOLEAN IsFat32)
> +{
> + UINTN Index;
> +
> + if (!IsFat32) {
> + for (Index = 0; ClusterSizeTable16[Index].SectorsPerCluster != 0; Index++)
> + if (Sectors <= ClusterSizeTable16[Index].Sectors)
> + return ClusterSizeTable16[Index].SectorsPerCluster;
> + } else {
> + for (Index = 0; ClusterSizeTable32[Index].SectorsPerCluster != 0; Index++)
> + if (Sectors <= ClusterSizeTable32[Index].Sectors)
> + return ClusterSizeTable32[Index].SectorsPerCluster;
> + }
> +
> + return 0;
> +}
> +//-----------------------------------------------------------------------------
> +// fatfs_erase_sectors: Erase a number of sectors
> +//-----------------------------------------------------------------------------
> +STATIC
> +EFI_STATUS
> +EraseSectors (
> + IN FATFS *Fs,
> + IN EFI_LBA Lba,
> + IN UINTN Count
> + )
> +{
> + UINTN Index;
> + EFI_STATUS Status;
> +
> + // Zero Sector first
> + ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE);
> +
> + for (Index = 0; Index < Count; Index++)
> + Status = Fs->DiskIo->WriteDisk (
> + Fs->DiskIo, Fs->BlockIo->Media->MediaId,
> + MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) +
> + MultU64x32 ((Lba + Index), FAT_SECTOR_SIZE),
> + FAT_SECTOR_SIZE, Fs->CurrentSector.Sector);
> +
> + return Status;
> +}
> +//-----------------------------------------------------------------------------
> +// fatfs_create_boot_sector: Create the boot Sector
> +//-----------------------------------------------------------------------------
> +STATIC
> +EFI_STATUS
> +CreateBootSector (
> + IN FATFS *Fs,
> + IN EFI_LBA BootSectorLba,
> + IN UINT64 VolSectors,
> + IN CONST CHAR8 *Name,
> + IN BOOLEAN IsFat32
> + )
> +{
> + UINTN TotalClusters;
> + UINTN Index;
> + EFI_STATUS Status;
> +
> + // Zero Sector initially
> + ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE);
> +
> + // OEM Name & Jump Code
> + Fs->CurrentSector.Sector[0] = 0xEB;
> + Fs->CurrentSector.Sector[1] = 0x3C;
> + Fs->CurrentSector.Sector[2] = 0x90;
> + Fs->CurrentSector.Sector[3] = 0x4D;
> + Fs->CurrentSector.Sector[4] = 0x53;
> + Fs->CurrentSector.Sector[5] = 0x44;
> + Fs->CurrentSector.Sector[6] = 0x4F;
> + Fs->CurrentSector.Sector[7] = 0x53;
> + Fs->CurrentSector.Sector[8] = 0x35;
> + Fs->CurrentSector.Sector[9] = 0x2E;
> + Fs->CurrentSector.Sector[10] = 0x30;
> +
> + // Bytes per Sector
> + Fs->CurrentSector.Sector[11] = (FAT_SECTOR_SIZE >> 0) & 0xFF;
> + Fs->CurrentSector.Sector[12] = (FAT_SECTOR_SIZE >> 8) & 0xFF;
> +
> + // Get sectors per cluster size for the disk
> + Fs->SectorsPerCluster = CalcClusterSize (VolSectors, IsFat32);
> + if (!Fs->SectorsPerCluster)
> + return 0; // Invalid disk size
> +
> + // Sectors per cluster
> + Fs->CurrentSector.Sector[13] = Fs->SectorsPerCluster;
> +
> + // Reserved Sectors
> + if (!IsFat32)
> + Fs->ReservedSectors = 8;
> + else
> + Fs->ReservedSectors = 32;
> + Fs->CurrentSector.Sector[14] = (Fs->ReservedSectors >> 0) & 0xFF;
> + Fs->CurrentSector.Sector[15] = (Fs->ReservedSectors >> 8) & 0xFF;
> +
> + // Number of FATS
> + Fs->NumOfFats = 2;
> + Fs->CurrentSector.Sector[16] = Fs->NumOfFats;
> +
> + // Max entries in root dir (FAT16 only)
> + if (!IsFat32) {
> + Fs->RootEntryCount = 512;
> + Fs->CurrentSector.Sector[17] = (Fs->RootEntryCount >> 0) & 0xFF;
> + Fs->CurrentSector.Sector[18] = (Fs->RootEntryCount >> 8) & 0xFF;
> + } else {
> + Fs->RootEntryCount = 0;
> + Fs->CurrentSector.Sector[17] = 0;
> + Fs->CurrentSector.Sector[18] = 0;
> + }
> +
> + // [FAT16] Total sectors (use FAT32 count instead)
> + Fs->CurrentSector.Sector[19] = 0x00;
> + Fs->CurrentSector.Sector[20] = 0x00;
> +
> + // Media type
> + Fs->CurrentSector.Sector[21] = 0xF8;
> +
> +
> + // FAT16 BS Details
> + if (!IsFat32) {
> + // Count of sectors used by the FAT table (FAT16 only)
> + TotalClusters = (VolSectors / Fs->SectorsPerCluster) + 1;
> + Fs->FatSectors = (TotalClusters / (FAT_SECTOR_SIZE / 2)) + 1;
> + Fs->CurrentSector.Sector[22] = (UINT8)((Fs->FatSectors >> 0) & 0xFF);
> + Fs->CurrentSector.Sector[23] = (UINT8)((Fs->FatSectors >> 8) & 0xFF);
> +
> + // Sectors per track
> + Fs->CurrentSector.Sector[24] = 0x00;
> + Fs->CurrentSector.Sector[25] = 0x00;
> +
> + // Heads
> + Fs->CurrentSector.Sector[26] = 0x00;
> + Fs->CurrentSector.Sector[27] = 0x00;
> +
> + // Hidden sectors
> + Fs->CurrentSector.Sector[28] = 0x20;
> + Fs->CurrentSector.Sector[29] = 0x00;
> + Fs->CurrentSector.Sector[30] = 0x00;
> + Fs->CurrentSector.Sector[31] = 0x00;
> +
> + // Total sectors for this volume
> + Fs->CurrentSector.Sector[32] = (UINT8)((VolSectors >> 0) & 0xFF);
> + Fs->CurrentSector.Sector[33] = (UINT8)((VolSectors >> 8) & 0xFF);
> + Fs->CurrentSector.Sector[34] = (UINT8)((VolSectors >> 16) & 0xFF);
> + Fs->CurrentSector.Sector[35] = (UINT8)((VolSectors >> 24) & 0xFF);
> +
> + // Drive number
> + Fs->CurrentSector.Sector[36] = 0x00;
> +
> + // Reserved
> + Fs->CurrentSector.Sector[37] = 0x00;
> +
> + // Boot signature
> + Fs->CurrentSector.Sector[38] = 0x29;
> +
> + // Volume ID
> + Fs->CurrentSector.Sector[39] = 0x12;
> + Fs->CurrentSector.Sector[40] = 0x34;
> + Fs->CurrentSector.Sector[41] = 0x56;
> + Fs->CurrentSector.Sector[42] = 0x78;
> +
> + // Volume name
> + for (Index = 0; Index < 11; Index++) {
> + if (Index < AsciiStrLen (Name))
> + Fs->CurrentSector.Sector[Index + 43] = Name[Index];
> + else
> + Fs->CurrentSector.Sector[Index + 43] = ' ';
> + }
> +
> + // File sys type
> + Fs->CurrentSector.Sector[54] = 'F';
> + Fs->CurrentSector.Sector[55] = 'A';
> + Fs->CurrentSector.Sector[56] = 'T';
> + Fs->CurrentSector.Sector[57] = '1';
> + Fs->CurrentSector.Sector[58] = '6';
> + Fs->CurrentSector.Sector[59] = ' ';
> + Fs->CurrentSector.Sector[60] = ' ';
> + Fs->CurrentSector.Sector[61] = ' ';
> +
> + // Signature
> + Fs->CurrentSector.Sector[510] = 0x55;
> + Fs->CurrentSector.Sector[511] = 0xAA;
> + }
> + // FAT32 BS Details
> + else {
> + // Count of sectors used by the FAT table (FAT16 only)
> + Fs->CurrentSector.Sector[22] = 0;
> + Fs->CurrentSector.Sector[23] = 0;
> +
> + // Sectors per track (default)
> + Fs->CurrentSector.Sector[24] = 0x3F;
> + Fs->CurrentSector.Sector[25] = 0x00;
> +
> + // Heads (default)
> + Fs->CurrentSector.Sector[26] = 0xFF;
> + Fs->CurrentSector.Sector[27] = 0x00;
> +
> + // Hidden sectors
> + Fs->CurrentSector.Sector[28] = 0x00;
> + Fs->CurrentSector.Sector[29] = 0x00;
> + Fs->CurrentSector.Sector[30] = 0x00;
> + Fs->CurrentSector.Sector[31] = 0x00;
> +
> + // Total sectors for this volume
> + Fs->CurrentSector.Sector[32] = (UINT8)((VolSectors >> 0) & 0xFF);
> + Fs->CurrentSector.Sector[33] = (UINT8)((VolSectors >> 8) & 0xFF);
> + Fs->CurrentSector.Sector[34] = (UINT8)((VolSectors >> 16) & 0xFF);
> + Fs->CurrentSector.Sector[35] = (UINT8)((VolSectors >> 24) & 0xFF);
> +
> + TotalClusters = (VolSectors / Fs->SectorsPerCluster) + 1;
> + Fs->FatSectors = (TotalClusters / (FAT_SECTOR_SIZE / 4)) + 1;
> +
> + // BPB_FATSz32
> + Fs->CurrentSector.Sector[36] = (UINT8)((Fs->FatSectors >> 0) & 0xFF);
> + Fs->CurrentSector.Sector[37] = (UINT8)((Fs->FatSectors >> 8) & 0xFF);
> + Fs->CurrentSector.Sector[38] = (UINT8)((Fs->FatSectors >> 16) & 0xFF);
> + Fs->CurrentSector.Sector[39] = (UINT8)((Fs->FatSectors >> 24) & 0xFF);
> +
> + // BPB_ExtFlags
> + Fs->CurrentSector.Sector[40] = 0;
> + Fs->CurrentSector.Sector[41] = 0;
> +
> + // BPB_FSVer
> + Fs->CurrentSector.Sector[42] = 0;
> + Fs->CurrentSector.Sector[43] = 0;
> +
> + // BPB_RootClus
> + Fs->CurrentSector.Sector[44] = (UINT8)((Fs->RootdirFirstCluster >> 0) &
> 0xFF);
> + Fs->CurrentSector.Sector[45] = (UINT8)((Fs->RootdirFirstCluster >> 8) &
> 0xFF);
> + Fs->CurrentSector.Sector[46] = (UINT8)((Fs->RootdirFirstCluster >> 16) &
> 0xFF);
> + Fs->CurrentSector.Sector[47] = (UINT8)((Fs->RootdirFirstCluster >> 24) &
> 0xFF);
> +
> + // BPB_FSInfo
> + Fs->CurrentSector.Sector[48] = (UINT8)((Fs->FsInfoSector >> 0) & 0xFF);
> + Fs->CurrentSector.Sector[49] = (UINT8)((Fs->FsInfoSector >> 8) & 0xFF);
> +
> + // BPB_BkBootSec
> + Fs->CurrentSector.Sector[50] = 6;
> + Fs->CurrentSector.Sector[51] = 0;
> +
> + // Drive number
> + Fs->CurrentSector.Sector[64] = 0x00;
> +
> + // Boot signature
> + Fs->CurrentSector.Sector[66] = 0x29;
> +
> + // Volume ID
> + Fs->CurrentSector.Sector[67] = 0x12;
> + Fs->CurrentSector.Sector[68] = 0x34;
> + Fs->CurrentSector.Sector[69] = 0x56;
> + Fs->CurrentSector.Sector[70] = 0x78;
> +
> + // Volume name
> + for (Index = 0; Index < 11; Index++) {
> + if (Index < (int)AsciiStrLen (Name))
> + Fs->CurrentSector.Sector[Index + 71] = Name[Index];
> + else
> + Fs->CurrentSector.Sector[Index + 71] = ' ';
> + }
> +
> + // File sys type
> + Fs->CurrentSector.Sector[82] = 'F';
> + Fs->CurrentSector.Sector[83] = 'A';
> + Fs->CurrentSector.Sector[84] = 'T';
> + Fs->CurrentSector.Sector[85] = '3';
> + Fs->CurrentSector.Sector[86] = '2';
> + Fs->CurrentSector.Sector[87] = ' ';
> + Fs->CurrentSector.Sector[88] = ' ';
> + Fs->CurrentSector.Sector[89] = ' ';
> +
> + // Signature
> + Fs->CurrentSector.Sector[510] = 0x55;
> + Fs->CurrentSector.Sector[511] = 0xAA;
> + }
> +
> + Status = Fs->DiskIo->WriteDisk (
> + Fs->DiskIo, Fs->BlockIo->Media->MediaId,
> + MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) +
> + MultU64x32 (Fs->FatBeginLba, FAT_SECTOR_SIZE),
> + FAT_SECTOR_SIZE,
> + Fs->CurrentSector.Sector);
> +
> + return Status;
> +}
> +//-----------------------------------------------------------------------------
> +// fatfs_create_fsinfo_sector: Create the FSInfo Sector (FAT32)
> +//-----------------------------------------------------------------------------
> +STATIC
> +EFI_STATUS
> +CreateFsinfoSector (
> + IN FATFS *Fs,
> + IN EFI_LBA SectorLba
> + )
> +{
> + EFI_STATUS Status;
> +
> + // Zero Sector initially
> + ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE);
> +
> + // FSI_LeadSig
> + Fs->CurrentSector.Sector[0] = 0x52;
> + Fs->CurrentSector.Sector[1] = 0x52;
> + Fs->CurrentSector.Sector[2] = 0x61;
> + Fs->CurrentSector.Sector[3] = 0x41;
> +
> + // FSI_StrucSig
> + Fs->CurrentSector.Sector[484] = 0x72;
> + Fs->CurrentSector.Sector[485] = 0x72;
> + Fs->CurrentSector.Sector[486] = 0x41;
> + Fs->CurrentSector.Sector[487] = 0x61;
> +
> + // FSI_Free_Count
> + Fs->CurrentSector.Sector[488] = 0xFF;
> + Fs->CurrentSector.Sector[489] = 0xFF;
> + Fs->CurrentSector.Sector[490] = 0xFF;
> + Fs->CurrentSector.Sector[491] = 0xFF;
> +
> + // FSI_Nxt_Free
> + Fs->CurrentSector.Sector[492] = 0xFF;
> + Fs->CurrentSector.Sector[493] = 0xFF;
> + Fs->CurrentSector.Sector[494] = 0xFF;
> + Fs->CurrentSector.Sector[495] = 0xFF;
> +
> + // Signature
> + Fs->CurrentSector.Sector[510] = 0x55;
> + Fs->CurrentSector.Sector[511] = 0xAA;
> +
> + Status = Fs->DiskIo->WriteDisk (
> + Fs->DiskIo, Fs->BlockIo->Media->MediaId,
> + MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) +
> + MultU64x32 (SectorLba, FAT_SECTOR_SIZE),
> + FAT_SECTOR_SIZE,
> + Fs->CurrentSector.Sector);
> +
> + return Status;
> +}
> +//-----------------------------------------------------------------------------
> +// fatfs_erase_fat: Erase FAT table using fs details in fs struct
> +//-----------------------------------------------------------------------------
> +STATIC
> +EFI_STATUS
> +EraseFat (
> + IN FATFS *Fs,
> + IN BOOLEAN IsFat32)
> +{
> + UINTN Index;
> + EFI_STATUS Status;
> +
> + // Zero Sector initially
> + ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE);
> +
> + // Initialise default allocate / reserved clusters
> + if (!IsFat32) {
> + SET_16BIT_WORD (Fs->CurrentSector.Sector, 0, 0xFFF8);
> + SET_16BIT_WORD (Fs->CurrentSector.Sector, 2, 0xFFFF);
> + } else {
> + SET_32BIT_WORD (Fs->CurrentSector.Sector, 0, 0x0FFFFFF8);
> + SET_32BIT_WORD (Fs->CurrentSector.Sector, 4, 0xFFFFFFFF);
> + SET_32BIT_WORD (Fs->CurrentSector.Sector, 8, 0x0FFFFFFF);
> + }
> +
> + Status = Fs->DiskIo->WriteDisk (
> + Fs->DiskIo, Fs->BlockIo->Media->MediaId,
> + MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) +
> + MultU64x32 (Fs->FatBeginLba, FAT_SECTOR_SIZE),
> + FAT_SECTOR_SIZE,
> + Fs->CurrentSector.Sector);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + // Zero remaining FAT sectors
> + ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE);
> + for (Index = 1; Index < Fs->FatSectors * Fs->NumOfFats; Index++) {
> + Status = Fs->DiskIo->WriteDisk (
> + Fs->DiskIo,
> + Fs->BlockIo->Media->MediaId,
> + MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) +
> + MultU64x32 ((Fs->FatBeginLba + Index), FAT_SECTOR_SIZE),
> + FAT_SECTOR_SIZE,
> + Fs->CurrentSector.Sector);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + }
> + return Status;
> +}
> +//-----------------------------------------------------------------------------
> +// fatfs_format_fat16: Format a FAT16 partition
> +//-----------------------------------------------------------------------------
> +STATIC
> +EFI_STATUS
> +FormatFat16 (
> + IN FATFS *Fs,
> + IN UINT64 VolumeSectors,
> + IN CONST CHAR8 *Name
> + )
> +{
> + EFI_STATUS Status;
> +
> + Fs->CurrentSector.Address = FAT32_INVALID_CLUSTER;
> + Fs->CurrentSector.Dirty = 0;
> +
> + Fs->NextFreeCluster = 0; // Invalid
> +
> + // Volume is FAT16
> + Fs->FatType = FAT_TYPE_16;
> +
> + // Not valid for FAT16
> + Fs->FsInfoSector = 0;
> + Fs->RootdirFirstCluster = 0;
> +
> + Fs->LbaBegin = 0;
> + Status = CreateBootSector (Fs, Fs->LbaBegin, VolumeSectors, Name, 0);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + // For FAT16 (which this may be), RootdirFirstCluster is actuall
> RootdirFirstSector
> + Fs->RootdirFirstSector = Fs->ReservedSectors + (Fs->NumOfFats * Fs-
> >FatSectors);
> + Fs->RootdirSectors = ((Fs->RootEntryCount * 32) +
> + (FAT_SECTOR_SIZE - 1)) / FAT_SECTOR_SIZE;
> +
> + // First FAT LBA Address
> + Fs->FatBeginLba = Fs->LbaBegin + Fs->ReservedSectors;
> +
> + // The Address of the first data cluster on this volume
> + Fs->ClusterBeginLba = Fs->FatBeginLba +
> + (Fs->NumOfFats * Fs->FatSectors);
> +
> + // Initialise FAT sectors
> + Status = EraseFat (Fs, 0);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + // Erase Root directory
> + Status = EraseSectors (
> + Fs,
> + Fs->LbaBegin + Fs->RootdirFirstSector,
> + Fs->RootdirSectors);
> +
> + return Status;
> +}
> +//-----------------------------------------------------------------------------
> +// fatfs_format_fat32: Format a FAT32 partition
> +//-----------------------------------------------------------------------------
> +STATIC
> +EFI_STATUS
> +FormatFat32 (
> + IN FATFS *Fs,
> + IN UINTN VolumeSectors,
> + IN CONST CHAR8 *Name
> + )
> +{
> + EFI_STATUS Status;
> +
> + Fs->CurrentSector.Address = FAT32_INVALID_CLUSTER;
> + Fs->CurrentSector.Dirty = 0;
> +
> + Fs->NextFreeCluster = 0; // Invalid
> +
> + // Volume is FAT32
> + Fs->FatType = FAT_TYPE_32;
> +
> + // Basic defaults for normal FAT32 partitions
> + Fs->FsInfoSector = 1;
> + Fs->RootdirFirstCluster = 2;
> +
> + // Sector 0: Boot Sector
> + // NOTE: We don't need an MBR, it is a waste of a good Sector!
> + Fs->LbaBegin = 0;
> + Status = CreateBootSector (Fs, Fs->LbaBegin, VolumeSectors, Name, 1);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + // First FAT LBA address
> + Fs->FatBeginLba = Fs->LbaBegin + Fs->ReservedSectors;
> +
> + // The address of the first data cluster on this volume
> + Fs->ClusterBeginLba = Fs->FatBeginLba + (Fs->NumOfFats * Fs-
> >FatSectors);
> +
> + // Initialise FSInfo sector
> + Status = CreateFsinfoSector (Fs, Fs->FsInfoSector);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + // Initialise FAT sectors
> + Status = EraseFat (Fs, 1);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + // Erase Root directory
> + Status = EraseSectors (
> + Fs,
> + LbaOfCluster (Fs, Fs->RootdirFirstCluster),
> + Fs->SectorsPerCluster);
> +
> + return Status;
> +}
> +//-----------------------------------------------------------------------------
> +// fatfs_format: Format a partition with either FAT16 or FAT32 based on size
> +//-----------------------------------------------------------------------------
> +EFI_STATUS
> +FatFormat (
> + IN EFI_LBA StartingLBA,
> + IN EFI_LBA EndingLBA,
> + IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
> + IN EFI_DISK_IO_PROTOCOL *DiskIo,
> + IN CHAR8 *VolumeName,
> + IN BOOLEAN ForceFat32
> + )
> +{
> + FATFS Fs;
> + UINT64 VolumeSectors;
> +
> + VolumeSectors = DivU64x32 (
> + MultU64x32 (
> + EndingLBA - StartingLBA + 1, BlockIo->Media->BlockSize),
> + FAT_SECTOR_SIZE);
> +
> + if (VolumeName == NULL) {
> + VolumeName = DEFAULT_FAT_LABEL_NAME;
> + }
> +
> + ZeroMem (&Fs, sizeof(Fs));
> +
> + Fs.StartingLBA = StartingLBA;
> + Fs.EndingLBA = EndingLBA;
> + Fs.BlockIo = BlockIo;
> + Fs.DiskIo = DiskIo;
> + // 2GB - 32K limit for safe behaviour for FAT16
> + if ((VolumeSectors <= 4194304) && (!ForceFat32)) {
> + return FormatFat16 (&Fs, VolumeSectors, VolumeName);
> + } else {
> + return FormatFat32 (&Fs, VolumeSectors, VolumeName);
> + }
> +}
> diff --git a/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> new file mode 100644
> index 000000000000..d1a325a57abe
> --- /dev/null
> +++ b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> @@ -0,0 +1,111 @@
> +/** @file
> +
> + Copyright (c) 2003 - 2012, Ultra-Embedded.com. All rights reserved<BR>
> +
> + This program and the accompanying materials
> + are licensed and made available under the terms and conditions of the BSD
> License
> + which accompanies this distribution. The full text of the license may be
> found at
> + http://opensource.org/licenses/bsd-license.php
> +
> + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +/* Portions Copyright (c) 2016, Broadcom. All rights reserved */
> +
> +#ifndef __FAT_FORMAT_H__
> +#define __FAT_FORMAT_H__
> +
> +#include "GptWorker.h"
> +
> +#define FAT_SECTOR_SIZE 512
> +#define FAT_BUFFER_SECTORS 1
> +#define FAT32_LAST_CLUSTER 0xFFFFFFFF
> +#define FAT32_INVALID_CLUSTER 0xFFFFFFFF
> +#define FAT_DIR_ENTRY_SIZE 32
> +#define FAT_BUFFERS 1
> +#define DEFAULT_FAT_LABEL_NAME "EFIVOL"
> +
> +#define GET_32BIT_WORD(Buffer, Location)
> ( ((UINT32)Buffer[Location + 3] << 24) + \
> + ((UINT32)Buffer[Location + 2] <<16 ) + \
> + ((UINT32)Buffer[Location + 1] << 8) + \
> + (UINT32)Buffer[Location+0] )
> +
> +#define GET_16BIT_WORD(Buffer, Location)
> ( ((UINT16)Buffer[Location + 1] << 8) + \
> + (UINT16)Buffer[Location+0])
> +
> +#define SET_32BIT_WORD(Buffer, Location, Value) { Buffer[Location + 0] =
> (UINT8)((Value) & 0xFF); \
> + Buffer[Location + 1] = (UINT8)((Value >> 8) & 0xFF);
> \
> + Buffer[Location + 2] = (UINT8)((Value >> 16) &
> 0xFF); \
> + Buffer[Location + 3] = (UINT8)((Value >> 24) &
> 0xFF); }
> +
> +#define SET_16BIT_WORD(Buffer, Location, Value) { Buffer[Location + 0] =
> (UINT8)((Value) & 0xFF); \
> + Buffer[Location + 1] = (UINT8)((Value >> 8) &
> 0xFF); }
> +
> +typedef enum eFatType
> +{
> + FAT_TYPE_16,
> + FAT_TYPE_32
> +} FAT_FS_TYPE;
> +
> +
> +// Forward declaration
> +typedef struct _FAT_BUFFER FAT_BUFFER;
> +
> +struct _FAT_BUFFER {
> + UINT8 Sector[FAT_SECTOR_SIZE * FAT_BUFFER_SECTORS];
> + UINTN Address;
> + BOOLEAN Dirty;
> + UINT8 *Ptr;
> +
> + // Next in chain of sector buffers
> + struct FAT_BUFFER *NextBuf;
> +};
> +
> +typedef struct
> +{
> + // Filesystem globals
> + UINT8 SectorsPerCluster;
> + EFI_LBA ClusterBeginLba;
> + UINTN RootdirFirstCluster;
> + UINTN RootdirFirstSector;
> + UINTN RootdirSectors;
> + EFI_LBA FatBeginLba;
> + UINT16 FsInfoSector;
> + EFI_LBA LbaBegin;
> + UINTN FatSectors;
> + UINTN NextFreeCluster;
> + UINT16 RootEntryCount;
> + UINT16 ReservedSectors;
> + UINT8 NumOfFats;
> + FAT_FS_TYPE FatType;
> +
> + // Working buffer
> + FAT_BUFFER CurrentSector;
> + // FAT Buffer
> + FAT_BUFFER *FatBufferHead;
> + FAT_BUFFER FatBuffers[FAT_BUFFERS];
> + EFI_LBA StartingLBA;
> + EFI_LBA EndingLBA;
> + EFI_BLOCK_IO_PROTOCOL *BlockIo;
> + EFI_DISK_IO_PROTOCOL *DiskIo;
> +
> +} FATFS;
> +
> +
> +
> +//-----------------------------------------------------------------------------
> +// Prototypes
> +//-----------------------------------------------------------------------------
> +EFI_STATUS
> +FatFormat (
> + IN EFI_LBA StartingLBA,
> + IN EFI_LBA EndingLBA,
> + IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
> + IN EFI_DISK_IO_PROTOCOL *DiskIo,
> + IN CHAR8 *VolumeName,
> + IN BOOLEAN ForceFat32
> + );
> +
> +#endif
> diff --git a/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> new file mode 100644
> index 000000000000..0546c94488b0
> --- /dev/null
> +++ b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> @@ -0,0 +1,1902 @@
> +/** @file
> +Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2016, Broadcom. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution. The full text of the license may be
> found at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#include "GptWorker.h"
> +
> +#define GPT_DEBUG_LEVEL 0
> +
> +STATIC EFI_PARTITION_TABLE_HEADER *PrimaryHeader = NULL;
> +STATIC EFI_PARTITION_TABLE_HEADER *BackupHeader = NULL;
> +STATIC EFI_PARTITION_ENTRY *PartEntry = NULL;
> +STATIC EFI_PARTITION_ENTRY_STATUS *PEntryStatus = NULL;
> +
> +STATIC EFI_BLOCK_IO_PROTOCOL *BlockIo;
> +STATIC EFI_DISK_IO_PROTOCOL *DiskIo;
> +
> +STATIC BOOLEAN MbrValid;
> +STATIC BOOLEAN GptValid;
> +
> +STATIC EFI_KNOWN_PARTITION_TYPE PartitionTypes[] =
> +{
> + // Known Partition type GUIDs
> + // Expand this table as needed.
> + // Starting with EFI System partition
> + { { 0xC12A7328L, 0xF81F, 0x11D2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9,
> 0x3B } }, L"EFI System" },
> + // Known Windows partition types
> + { { 0xE3C9E316L, 0x0B5C, 0x4DB8, { 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15,
> 0xAE } }, L"MS Windows Reserved (MSR)" },
> + { { 0xEBD0A0A2L, 0xB9E5, 0x4433, { 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99,
> 0xC7 } }, L"MS Windows Basic Data" },
> + { { 0x5808C8AAL, 0x7E8F, 0x42E0, { 0x85, 0xD2, 0xE1, 0xE9, 0x04, 0x34, 0xCF,
> 0xB3 } }, L"MS Windows LDM Metadata" },
> + { { 0xAF9B60A0L, 0x1431, 0x4F62, { 0xBC, 0x68, 0x33, 0x11, 0x71, 0x4A, 0x69,
> 0xAD } }, L"MS Windows LDM Data" },
> + { { 0xDE94BBA4L, 0x06D1, 0x4D40, { 0xA1, 0x6A, 0xBF, 0xD5, 0x01, 0x79,
> 0xD6, 0xAC } }, L"MS Windows Recovery Environment" },
> + { { 0xE75CAF8FL, 0xF680, 0x4CEE, { 0xAF, 0xA3, 0xB0, 0x01, 0xE5, 0x6E, 0xFC,
> 0x2D } }, L"MS Windows Storage Spaces" },
> + // Known Linux partition types
> + { { 0x0FC63DAFL, 0x8483, 0x4772, { 0x8E, 0x79, 0x3D, 0x69, 0xD8, 0x47, 0x7D,
> 0xE4 } }, L"Linux Filesystem Data" },
> + { { 0xA19D880FL, 0x05FC, 0x4D3B, { 0xA0, 0x06, 0x74, 0x3F, 0x0F, 0x84, 0x91,
> 0x1E } }, L"Linux RAID" },
> + { { 0x44479540L, 0xF297, 0x41B2, { 0x9A, 0xF7, 0xD1, 0x31, 0xD5, 0xF0, 0x45,
> 0x8A } }, L"Linux Root (x86)" },
> + { { 0x4F68BCE3L, 0xE8CD, 0x4DB1, { 0x96, 0xE7, 0xFB, 0xCA, 0xF9, 0x84, 0xB7,
> 0x09 } }, L"Linux Root (x86-64)" },
> + { { 0x69DAD710L, 0x2CE4, 0x4E3C, { 0xB1, 0x6C, 0x21, 0xA1, 0xD4, 0x9A,
> 0xBe, 0xD3 } }, L"Linux Root (ARM 32-bit)" },
> + { { 0xB921B045L, 0x1DF0, 0x41C3, { 0xAF, 0x44, 0x4C, 0x6F, 0x28, 0x0D, 0x3F,
> 0xAE } }, L"Linux Root (ARM 64-bit/AARCH64)" },
> + { { 0x0657FD6DL, 0xA4AB, 0x43C4, { 0x84, 0xE5, 0x09, 0x33, 0xC8, 0x4B, 0x4F,
> 0x4F } }, L"Linux Swap" },
> + { { 0xE6D6D379L, 0xF507, 0x44C2, { 0xA2, 0x3C, 0x23, 0x8F, 0x2A, 0x3D, 0xF9,
> 0x28 } }, L"Linux Logical Volume Manager (LVM)" },
> + { { 0x933AC7E1L, 0x2EB4, 0x4F13, { 0xB8, 0x44, 0x0E, 0x14, 0xE2, 0xAE, 0xF9,
> 0x15 } }, L"Linux /home" },
> + { { 0x3B8F8425L, 0x20E0, 0x4F3B, { 0x90, 0x7F, 0x1A, 0x25, 0xA7, 0x6F, 0x98,
> 0xE8 } }, L"Linux /srv (server data)" },
> + { { 0x7FFEC5C9L, 0x2D00, 0x49B7, { 0x89, 0x41, 0x3E, 0xA1, 0x0A, 0x55, 0x86,
> 0xB7 } }, L"Linux Plain dm-crypt" },
> + { { 0xCA7D7CCBL, 0x63ED, 0x4C53, { 0x86, 0x1C, 0x17, 0x42, 0x53, 0x60, 0x59,
> 0xCC } }, L"Linux LUKS" },
> + { { 0x8DA63339L, 0x0007, 0x60C0, { 0xC4, 0x36, 0x08, 0x3A, 0xC8, 0x23, 0x09,
> 0x08 } }, L"Linux Reserved" },
> +};
> +
> +MASTER_BOOT_RECORD ProtectiveMbrTemplate = {
> + { 0 }, // BoostStrapCode [440]
> + { 0 }, // UniqueMbrSignature[4] (unused)
> + { 0 }, // Unknown[2]
> +
> + // PARTITIONS
> + {
> + // MBR_PARTITION_RECORD
> + {
> + 0, // BootIndicator
> + 0, // StartHead
> + 0x1, // StartSector
> + 0x1, // StartTrack
> + PMBR_GPT_PARTITION, // OSIndicator
> + 0xff, // EndHead
> + 0xff, // EndSector
> + 0xff, // EndTrack
> + { 0x1, 0x0, 0x0, 0x0 }, // StartingLba[4]
> + { 0xff, 0xff, 0xff, 0xff }, // SizeInLba[4]
> + },
> + { 0 }, { 0 }, { 0 }, // Unused partitions
> + },
> +
> + MBR_SIGNATURE // Signature
> +};
> +
> +STATIC UINT32 CurRand = 1;
> +
> +/**
> + Get random seed based on the RTC
> +
> +**/
> +
> +STATIC
> +VOID
> +Srand (VOID)
> +{
> + EFI_TIME Time;
> + UINT32 Seed;
> + UINT64 MonotonicCount;
> +
> + gRT->GetTime (&Time, NULL);
> + Seed = (~Time.Hour << 24 | Time.Day << 16 | Time.Minute << 8 |
> Time.Second);
> + Seed ^= Time.Nanosecond;
> + Seed ^= Time.Year << 7;
> +
> + gBS->GetNextMonotonicCount (&MonotonicCount);
> + Seed += (UINT32)MonotonicCount;
> +
> + /* Store this seed */
> + CurRand = (UINT32)Seed;
> +}
> +
> +/**
> + Get a pseudo-random number
> +
> + @retval A pseudo-random number in the range 0 - 0x7fff
> +**/
> +
> +STATIC UINTN Rand (VOID)
> +{
> + /* return a pseudo-random in range 0 - 0x7fff */
> + return ((CurRand = CurRand * 214013L + 2531011L) >> 16) & 0x7fff;
> +}
> +
> +/**
> + Generate a GUID
> +
> + @param[in] Guid A pointer to a GUID receiving a generated value
> +**/
> +
> +STATIC VOID
> +GenerateGuid (OUT GUID *Guid)
> +{
> + UINTN Index;
> + UINT16 Buffer[sizeof(GUID)];
> +
> + /* Generates 128 random bits for new UUID */
> + for (Index = 0; Index < sizeof(GUID); Index++) {
> + UINTN V;
> +
> + V = Rand () >> 7;
> + Buffer[Index] = (UINT16)V;
> + }
> + /* set variant 10x and version 4 as required by RFC 4122 */
> + Buffer[8] = 0x80 | (Buffer[8] & 0x3f);
> + Buffer[6] = 0x40 | (Buffer[6] & 0xf);
> + CopyGuid (Guid, (CONST GUID *)Buffer);
> +}
> +
> +/**
> + Clean up globals
> +**/
> +VOID
> +GptCleanupGlobals (VOID)
> +{
> + SHELL_FREE_NON_NULL (PrimaryHeader);
> + SHELL_FREE_NON_NULL (BackupHeader);
> + SHELL_FREE_NON_NULL (PartEntry);
> + SHELL_FREE_NON_NULL (PEntryStatus);
> + GptValid = FALSE;
> + MbrValid = FALSE;
> +}
> +
> +/**
> + Caution: This function may receive untrusted input.
> + The GPT partition table header is external input, so this routine
> + will do basic validation for GPT partition table header before return.
> +
> + @param[in] Lba The starting Lba of the Partition Table
> + @param[out] PartHeader Stores the partition table that is read
> +
> + @retval EFI_SUCCESS The partition table is valid
> + @retval ERROR The partition table is not valid
> +
> +**/
> +STATIC
> +EFI_STATUS
> +PartitionValidGptTable (
> + IN EFI_LBA Lba,
> + OUT EFI_PARTITION_TABLE_HEADER *PartHeader
> + );
> +
> +/**
> + Check if the CRC field in the Partition table header is valid
> + for Partition entry array.
> +
> + @param[in] PartHeader Partition table header structure
> +
> + @retval TRUE the CRC is valid
> + @retval FALSE the CRC is invalid
> +
> +**/
> +STATIC
> +BOOLEAN
> +PartitionCheckGptEntryArrayCRC (
> + IN EFI_PARTITION_TABLE_HEADER *PartHeader
> + );
> +
> +
> +/**
> + Restore Partition Table to its alternate place
> + (Primary -> Backup or Backup -> Primary).
> +
> + @param[in] PartHeader Partition table header structure.
> +
> + @retval TRUE Restoring succeeds
> + @retval FALSE Restoring failed
> +
> +**/
> +STATIC
> +BOOLEAN
> +PartitionRestoreGptTable (
> + IN EFI_PARTITION_TABLE_HEADER *PartHeader
> + );
> +
> +
> +/**
> + This routine will check GPT partition entry and return entry status.
> +
> + Caution: This function may receive untrusted input.
> + The GPT partition entry is external input, so this routine
> + will do basic validation for GPT partition entry and report status.
> +
> + @param[in] PartHeader Partition table header structure
> + @param[in] PartEntry The partition entry array
> + @param[out] PEntryStatus the partition entry status array
> + recording the status of each partition
> +
> +**/
> +STATIC
> +VOID
> +PartitionCheckGptEntry (
> + IN EFI_PARTITION_TABLE_HEADER *PartHeader,
> + IN EFI_PARTITION_ENTRY *PartEntry,
> + OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus
> + );
> +
> +
> +/**
> + Checks the CRC32 value in the table header.
> +
> + @param MaxSize Max Size limit
> + @param Size The size of the table
> + @param Hdr Table to check
> +
> + @return TRUE CRC Valid
> + @return FALSE CRC Invalid
> +
> +**/
> +STATIC
> +BOOLEAN
> +PartitionCheckCrcAltSize (
> + IN UINTN MaxSize,
> + IN UINTN Size,
> + IN OUT EFI_TABLE_HEADER *Hdr
> + );
> +
> +
> +/**
> + Checks the CRC32 value in the table header.
> +
> + @param MaxSize Max Size limit
> + @param Hdr Table to check
> +
> + @return TRUE CRC Valid
> + @return FALSE CRC Invalid
> +
> +**/
> +STATIC
> +BOOLEAN
> +PartitionCheckCrc (
> + IN UINTN MaxSize,
> + IN OUT EFI_TABLE_HEADER *Hdr
> + );
> +
> +
> +/**
> + Updates the CRC32 value in the table header.
> +
> + @param Size The size of the table
> + @param Hdr Table to update
> +
> +**/
> +STATIC
> +VOID
> +PartitionSetCrcAltSize (
> + IN UINTN Size,
> + IN OUT EFI_TABLE_HEADER *Hdr
> + );
> +
> +
> +/**
> + Updates the CRC32 value in the table header.
> +
> + @param Hdr Table to update
> +
> +**/
> +STATIC
> +VOID
> +PartitionSetCrc (
> + IN OUT EFI_TABLE_HEADER *Hdr
> + );
> +
> +
> +/**
> + Get GPT tables.
> +
> + Caution: This function may receive untrusted input.
> + The GPT partition table is external input, so this routine
> + will do basic validation for GPT partition table before install
> + child handle for each GPT partition.
> +
> + @param[in] DiskIoProt DiskIo interface.
> + @param[in] BlockIoProt BlockIo interface.
> +
> + @retval EFI_SUCCESS Valid GPT disk.
> + @retval EFI_MEDIA_CHANGED Media changed Detected.
> + @retval other Not a valid GPT disk.
> +
> +**/
> +EFI_STATUS
> +PartitionGetGptTables (
> + IN EFI_DISK_IO_PROTOCOL *DiskIoProt,
> + IN EFI_BLOCK_IO_PROTOCOL *BlockIoProt
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 BlockSize;
> + EFI_LBA LastBlock;
> + UINTN Index;
> + EFI_STATUS GptValidStatus;
> + UINT32 MediaId;
> + MASTER_BOOT_RECORD *ProtectiveMbr;
> +
> + // Clear leftovers
> + GptCleanupGlobals ();
> +
> + MbrValid = FALSE;
> + GptValid = FALSE;
> +
> + ProtectiveMbr = NULL;
> +
> + BlockIo = BlockIoProt;
> + DiskIo = DiskIoProt;
> +
> + if (CurRand == 1) {
> + Srand ();
> + }
> +
> + BlockSize = BlockIo->Media->BlockSize;
> + LastBlock = BlockIo->Media->LastBlock;
> + MediaId = BlockIo->Media->MediaId;
> +
> + DEBUG ((EFI_D_VERBOSE, " BlockSize : %d \n", BlockSize));
> + DEBUG ((EFI_D_VERBOSE, " LastBlock : %lx \n", LastBlock));
> +
> + GptValidStatus = EFI_NOT_FOUND;
> + GptValid = FALSE;
> + MbrValid = FALSE;
> +
> + //
> + // Allocate a buffer for the Protective MBR
> + //
> + ProtectiveMbr = AllocatePool (BlockSize);
> + if (ProtectiveMbr == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + //
> + // Read the Protective MBR from LBA #0
> + //
> + Status = DiskIo->ReadDisk (
> + DiskIo,
> + MediaId,
> + 0,
> + BlockSize,
> + ProtectiveMbr
> + );
> + if (EFI_ERROR (Status)) {
> + GptValidStatus = Status;
> + goto Done;
> + }
> +
> + //
> + // Verify that the Protective MBR is valid
> + //
> + for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
> + if (ProtectiveMbr->Partition[Index].BootIndicator == 0x00 &&
> + ProtectiveMbr->Partition[Index].OSIndicator ==
> PMBR_GPT_PARTITION &&
> + UNPACK_UINT32 (ProtectiveMbr->Partition[Index].StartingLBA) == 1
> + ) {
> + break;
> + }
> + }
> + if (Index == MAX_MBR_PARTITIONS) {
> + goto Done;
> + }
> +
> + MbrValid = TRUE;
> +
> + //
> + // Allocate the GPT structures
> + //
> + PrimaryHeader = AllocateZeroPool
> (sizeof(EFI_PARTITION_TABLE_HEADER));
> + if (PrimaryHeader == NULL) {
> + goto Done;
> + }
> +
> + BackupHeader = AllocateZeroPool
> (sizeof(EFI_PARTITION_TABLE_HEADER));
> + if (BackupHeader == NULL) {
> + goto Done;
> + }
> +
> + //
> + // Check primary and backup partition tables
> + //
> + Status = PartitionValidGptTable (PRIMARY_PART_HEADER_LBA,
> PrimaryHeader);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((EFI_D_INFO, " Not Valid primary partition table\n"));
> +
> + Status = PartitionValidGptTable (LastBlock, BackupHeader);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((EFI_D_INFO, " Not Valid backup partition table\n"));
> + goto Done;
> + } else {
> + DEBUG ((EFI_D_INFO, " Valid backup partition table\n"));
> + DEBUG ((EFI_D_INFO, " Restore primary partition table by the
> backup\n"));
> + if (!PartitionRestoreGptTable (BackupHeader)) {
> + DEBUG ((EFI_D_INFO, " Restore primary partition table error\n"));
> + }
> +
> + Status = PartitionValidGptTable (BackupHeader->AlternateLBA,
> PrimaryHeader);
> + if (!EFI_ERROR (Status)) {
> + DEBUG ((EFI_D_INFO, " Restore backup partition table success\n"));
> + }
> + }
> + } else if (EFI_ERROR (PartitionValidGptTable (PrimaryHeader-
> >AlternateLBA, BackupHeader))) {
> + DEBUG ((EFI_D_INFO, " Valid primary and !Valid backup partition
> table\n"));
> + DEBUG ((EFI_D_INFO, " Restore backup partition table by the
> primary\n"));
> + if (!PartitionRestoreGptTable (PrimaryHeader)) {
> + DEBUG ((EFI_D_INFO, " Restore backup partition table error\n"));
> + }
> +
> + Status = PartitionValidGptTable (PrimaryHeader->AlternateLBA,
> BackupHeader);
> + if (!EFI_ERROR (Status)) {
> + DEBUG ((EFI_D_INFO, " Restore backup partition table success\n"));
> + }
> + }
> +
> + DEBUG ((EFI_D_VERBOSE, " Valid primary and Valid backup partition
> table\n"));
> +
> + //
> + // Read the EFI Partition Entries
> + //
> + PartEntry = AllocatePool (PrimaryHeader->NumberOfPartitionEntries *
> PrimaryHeader->SizeOfPartitionEntry);
> + if (PartEntry == NULL) {
> + DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
> + goto Done;
> + }
> +
> + Status = DiskIo->ReadDisk (
> + DiskIo,
> + MediaId,
> + MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockSize),
> + PrimaryHeader->NumberOfPartitionEntries * (PrimaryHeader-
> >SizeOfPartitionEntry),
> + PartEntry
> + );
> + if (EFI_ERROR (Status)) {
> + GptValidStatus = Status;
> + DEBUG ((EFI_D_ERROR, " Partition Entry ReadDisk error\n"));
> + goto Done;
> + }
> +
> + DEBUG ((EFI_D_VERBOSE, " Partition entries read block success\n"));
> +
> + DEBUG ((EFI_D_VERBOSE, " Number of partition entries: %d\n",
> PrimaryHeader->NumberOfPartitionEntries));
> +
> + PEntryStatus = AllocateZeroPool (PrimaryHeader-
> >NumberOfPartitionEntries * sizeof(EFI_PARTITION_ENTRY_STATUS));
> + if (PEntryStatus == NULL) {
> + DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
> + goto Done;
> + }
> +
> + //
> + // Check the integrity of partition entries
> + //
> + PartitionCheckGptEntry (PrimaryHeader, PartEntry, PEntryStatus);
> +
> + //
> + // If we got this far the GPT layout of the disk is valid and we should return
> true
> + //
> + GptValidStatus = EFI_SUCCESS;
> +
> + Done:
> + SHELL_FREE_NON_NULL (ProtectiveMbr);
> + if (EFI_ERROR (GptValidStatus)) {
> + SHELL_FREE_NON_NULL (PrimaryHeader);
> + SHELL_FREE_NON_NULL (BackupHeader);
> + SHELL_FREE_NON_NULL (PartEntry);
> + SHELL_FREE_NON_NULL (PEntryStatus);
> + } else {
> + GptValid = TRUE;
> + }
> +
> + return GptValidStatus;
> +}
> +
> +/**
> + This routine will read GPT partition table header and return it.
> +
> + Caution: This function may receive untrusted input.
> + The GPT partition table header is external input, so this routine
> + will do basic validation for GPT partition table header before return.
> +
> + @param[in] Lba The starting Lba of the Partition Table
> + @param[out] PartHeader Stores the partition table that is read
> +
> + @retval TRUE The partition table is valid
> + @retval FALSE The partition table is not valid
> +
> +**/
> +STATIC
> +EFI_STATUS
> +PartitionValidGptTable (
> + IN EFI_LBA Lba,
> + OUT EFI_PARTITION_TABLE_HEADER *PartHeader
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 BlockSize;
> + EFI_PARTITION_TABLE_HEADER *PartHdr;
> + UINT32 MediaId;
> +
> + BlockSize = BlockIo->Media->BlockSize;
> + MediaId = BlockIo->Media->MediaId;
> + PartHdr = AllocateZeroPool (BlockSize);
> +
> + if (PartHdr == NULL) {
> + DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
> + return EFI_OUT_OF_RESOURCES;
> + }
> + //
> + // Read the EFI Partition Table Header
> + //
> + Status = DiskIo->ReadDisk (
> + DiskIo,
> + MediaId,
> + MultU64x32 (Lba, BlockSize),
> + BlockSize,
> + PartHdr
> + );
> + if (EFI_ERROR (Status)) {
> + FreePool (PartHdr);
> + return Status;
> + }
> +
> + if ((PartHdr->Header.Signature != EFI_PTAB_HEADER_ID) ||
> + !PartitionCheckCrc (BlockSize, &PartHdr->Header) ||
> + PartHdr->MyLBA != Lba ||
> + (PartHdr->SizeOfPartitionEntry < sizeof(EFI_PARTITION_ENTRY))
> + ) {
> + DEBUG ((EFI_D_ERROR, "Invalid efi partition table header\n"));
> + FreePool (PartHdr);
> + return EFI_VOLUME_CORRUPTED;
> + }
> +
> + //
> + // Ensure the NumberOfPartitionEntries * SizeOfPartitionEntry doesn't
> overflow.
> + //
> + if (PartHdr->NumberOfPartitionEntries > DivU64x32 (MAX_UINTN,
> PartHdr->SizeOfPartitionEntry)) {
> + FreePool (PartHdr);
> + return EFI_VOLUME_CORRUPTED;
> + }
> +
> + CopyMem (PartHeader, PartHdr, sizeof(EFI_PARTITION_TABLE_HEADER));
> + if (!PartitionCheckGptEntryArrayCRC (PartHeader)) {
> + FreePool (PartHdr);
> + return EFI_VOLUME_CORRUPTED;
> + }
> +
> + DEBUG ((EFI_D_VERBOSE, " Valid efi partition table header\n"));
> + FreePool (PartHdr);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Check if the CRC field in the Partition table header is valid
> + for Partition entry array.
> +
> + @param[in] PartHeader Partition table header structure
> +
> + @retval TRUE the CRC is valid
> + @retval FALSE the CRC is invalid
> +
> +**/
> +STATIC
> +BOOLEAN
> +PartitionCheckGptEntryArrayCRC (
> + IN EFI_PARTITION_TABLE_HEADER *PartHeader
> + )
> +{
> + EFI_STATUS Status;
> + UINT8 *Ptr;
> + UINT32 Crc;
> + UINTN Size;
> +
> + //
> + // Read the EFI Partition Entries
> + //
> + Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader-
> >SizeOfPartitionEntry);
> + if (Ptr == NULL) {
> + DEBUG ((EFI_D_ERROR, " Allocate pool error\n"));
> + return FALSE;
> + }
> +
> + Status = DiskIo->ReadDisk (
> + DiskIo,
> + BlockIo->Media->MediaId,
> + MultU64x32 (PartHeader->PartitionEntryLBA, BlockIo->Media->BlockSize),
> + PartHeader->NumberOfPartitionEntries * PartHeader-
> >SizeOfPartitionEntry,
> + Ptr
> + );
> + if (EFI_ERROR (Status)) {
> + FreePool (Ptr);
> + return FALSE;
> + }
> +
> + Size = PartHeader->NumberOfPartitionEntries * PartHeader-
> >SizeOfPartitionEntry;
> +
> + Status = gBS->CalculateCrc32 (Ptr, Size, &Crc);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((EFI_D_ERROR, "CheckPEntryArrayCRC: Crc calculation failed\n"));
> + FreePool (Ptr);
> + return FALSE;
> + }
> +
> + FreePool (Ptr);
> +
> + return (BOOLEAN)(PartHeader->PartitionEntryArrayCRC32 == Crc);
> +}
> +
> +
> +/**
> + Restore Partition Table to its alternate place
> + (Primary -> Backup or Backup -> Primary).
> +
> + @param[in] PartHeader Partition table header structure.
> +
> + @retval TRUE Restoring succeeds
> + @retval FALSE Restoring failed
> +
> +**/
> +STATIC
> +BOOLEAN
> +PartitionRestoreGptTable (
> + IN EFI_PARTITION_TABLE_HEADER *PartHeader
> + )
> +{
> + EFI_STATUS Status;
> + UINTN BlockSize;
> + EFI_PARTITION_TABLE_HEADER *PartHdr;
> + EFI_LBA PEntryLBA;
> + UINT8 *Ptr;
> + UINT32 MediaId;
> +
> + PartHdr = NULL;
> + Ptr = NULL;
> +
> + BlockSize = BlockIo->Media->BlockSize;
> + MediaId = BlockIo->Media->MediaId;
> +
> + PartHdr = AllocateZeroPool (BlockSize);
> +
> + if (PartHdr == NULL) {
> + DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
> + return FALSE;
> + }
> +
> + PEntryLBA = (PartHeader->MyLBA == PRIMARY_PART_HEADER_LBA) ?\
> + (PartHeader->LastUsableLBA + 1) :\
> + (PRIMARY_PART_HEADER_LBA + 1);
> +
> + CopyMem (PartHdr, PartHeader, sizeof(EFI_PARTITION_TABLE_HEADER));
> +
> + PartHdr->MyLBA = PartHeader->AlternateLBA;
> + PartHdr->AlternateLBA = PartHeader->MyLBA;
> + PartHdr->PartitionEntryLBA = PEntryLBA;
> + PartitionSetCrc ((EFI_TABLE_HEADER *)PartHdr);
> +
> + Status = DiskIo->WriteDisk (
> + DiskIo,
> + MediaId,
> + MultU64x32 (PartHdr->MyLBA, (UINT32)BlockSize),
> + BlockSize,
> + PartHdr
> + );
> + if (EFI_ERROR (Status)) {
> + goto Done;
> + }
> +
> + Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader-
> >SizeOfPartitionEntry);
> + if (Ptr == NULL) {
> + DEBUG ((EFI_D_ERROR, " Allocate pool error\n"));
> + Status = EFI_OUT_OF_RESOURCES;
> + goto Done;
> + }
> +
> + Status = DiskIo->ReadDisk (
> + DiskIo,
> + MediaId,
> + MultU64x32 (PartHeader->PartitionEntryLBA, (UINT32)BlockSize),
> + PartHeader->NumberOfPartitionEntries * PartHeader-
> >SizeOfPartitionEntry,
> + Ptr
> + );
> + if (EFI_ERROR (Status)) {
> + goto Done;
> + }
> +
> + Status = DiskIo->WriteDisk (
> + DiskIo,
> + MediaId,
> + MultU64x32 (PEntryLBA, (UINT32)BlockSize),
> + PartHeader->NumberOfPartitionEntries * PartHeader-
> >SizeOfPartitionEntry,
> + Ptr
> + );
> +
> + Done:
> + FreePool (PartHdr);
> +
> + if (Ptr != NULL) {
> + FreePool (Ptr);
> + }
> +
> + if (EFI_ERROR (Status)) {
> + return FALSE;
> + }
> +
> + return TRUE;
> +}
> +
> +/**
> + This routine will check GPT partition entry and return entry status.
> +
> + Caution: This function may receive untrusted input.
> + The GPT partition entry is external input, so this routine
> + will do basic validation for GPT partition entry and report status.
> +
> + @param[in] PartHeader Partition table header structure
> + @param[in] PartEntry The partition entry array
> + @param[out] PEntryStatus the partition entry status array
> + recording the status of each partition
> +
> +**/
> +STATIC
> +VOID
> +PartitionCheckGptEntry (
> + IN EFI_PARTITION_TABLE_HEADER *PartHeader,
> + IN EFI_PARTITION_ENTRY *PartEntry,
> + OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus
> + )
> +{
> + EFI_LBA StartingLBA;
> + EFI_LBA EndingLBA;
> + EFI_PARTITION_ENTRY *Entry;
> + UINTN Index1;
> + UINTN Index2;
> +
> + DEBUG ((EFI_D_VERBOSE, " start check partition entries\n"));
> + for (Index1 = 0; Index1 < PartHeader->NumberOfPartitionEntries;
> Index1++) {
> + Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index1 *
> PartHeader->SizeOfPartitionEntry);
> + if (CompareGuid (&Entry->PartitionTypeGUID,
> &gEfiPartTypeUnusedGuid)) {
> + continue;
> + }
> +
> + StartingLBA = Entry->StartingLBA;
> + EndingLBA = Entry->EndingLBA;
> + if (StartingLBA > EndingLBA ||
> + StartingLBA < PartHeader->FirstUsableLBA ||
> + StartingLBA > PartHeader->LastUsableLBA ||
> + EndingLBA < PartHeader->FirstUsableLBA ||
> + EndingLBA > PartHeader->LastUsableLBA
> + ) {
> + PEntryStatus[Index1].OutOfRange = TRUE;
> + continue;
> + }
> +
> + if ((Entry->Attributes & BIT1) != 0) {
> + //
> + // If Bit 1 is set, this indicate that this is an OS specific GUID partition.
> + //
> + PEntryStatus[Index1].OsSpecific = TRUE;
> + }
> +
> + for (Index2 = Index1 + 1; Index2 < PartHeader-
> >NumberOfPartitionEntries; Index2++) {
> + Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index2 *
> PartHeader->SizeOfPartitionEntry);
> + if (CompareGuid (&Entry->PartitionTypeGUID,
> &gEfiPartTypeUnusedGuid)) {
> + continue;
> + }
> +
> + if (Entry->EndingLBA >= StartingLBA && Entry->StartingLBA <= EndingLBA)
> {
> + //
> + // This region overlaps with the Index1'th region
> + //
> + PEntryStatus[Index1].Overlap = TRUE;
> + PEntryStatus[Index2].Overlap = TRUE;
> + continue;
> + }
> + }
> + }
> +
> + DEBUG ((EFI_D_VERBOSE, " End check partition entries\n"));
> +}
> +
> +
> +/**
> + Updates the CRC32 value in the table header.
> +
> + @param Hdr Table to update
> +
> +**/
> +STATIC
> +VOID
> +PartitionSetCrc (
> + IN OUT EFI_TABLE_HEADER *Hdr
> + )
> +{
> + PartitionSetCrcAltSize (Hdr->HeaderSize, Hdr);
> +}
> +
> +
> +/**
> + Updates the CRC32 value in the table header.
> +
> + @param Size The size of the table
> + @param Hdr Table to update
> +
> +**/
> +STATIC
> +VOID
> +PartitionSetCrcAltSize (
> + IN UINTN Size,
> + IN OUT EFI_TABLE_HEADER *Hdr
> + )
> +{
> + UINT32 Crc;
> +
> + Hdr->CRC32 = 0;
> + gBS->CalculateCrc32 ((UINT8 *)Hdr, Size, &Crc);
> + Hdr->CRC32 = Crc;
> +}
> +
> +
> +/**
> + Checks the CRC32 value in the table header.
> +
> + @param MaxSize Max Size limit
> + @param Hdr Table to check
> +
> + @return TRUE CRC Valid
> + @return FALSE CRC Invalid
> +
> +**/
> +STATIC
> +BOOLEAN
> +PartitionCheckCrc (
> + IN UINTN MaxSize,
> + IN OUT EFI_TABLE_HEADER *Hdr
> + )
> +{
> + return PartitionCheckCrcAltSize (MaxSize, Hdr->HeaderSize, Hdr);
> +}
> +
> +
> +/**
> + Checks the CRC32 value in the table header.
> +
> + @param MaxSize Max Size limit
> + @param Size The size of the table
> + @param Hdr Table to check
> +
> + @return TRUE CRC Valid
> + @return FALSE CRC Invalid
> +
> +**/
> +STATIC
> +BOOLEAN
> +PartitionCheckCrcAltSize (
> + IN UINTN MaxSize,
> + IN UINTN Size,
> + IN OUT EFI_TABLE_HEADER *Hdr
> + )
> +{
> + UINT32 Crc;
> + UINT32 OrgCrc;
> + EFI_STATUS Status;
> +
> + Crc = 0;
> +
> + if (Size == 0) {
> + //
> + // If header size is 0 CRC will pass so return FALSE here
> + //
> + return FALSE;
> + }
> +
> + if ((MaxSize != 0) && (Size > MaxSize)) {
> + DEBUG ((EFI_D_ERROR, "CheckCrc32: Size > MaxSize\n"));
> + return FALSE;
> + }
> + //
> + // clear old crc from header
> + //
> + OrgCrc = Hdr->CRC32;
> + Hdr->CRC32 = 0;
> +
> + Status = gBS->CalculateCrc32 ((UINT8 *)Hdr, Size, &Crc);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc calculation failed\n"));
> + return FALSE;
> + }
> + //
> + // set results
> + //
> + Hdr->CRC32 = Crc;
> +
> + //
> + // return status
> + //
> + DEBUG_CODE_BEGIN ();
> + if (OrgCrc != Crc) {
> + DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc check failed\n"));
> + }
> + DEBUG_CODE_END ();
> +
> + return (BOOLEAN)(OrgCrc == Crc);
> +}
> +
> +/**
> + Converts a GUID into a unicode string.
> +
> + @param [in] Guid A GUID to be converted
> + @param [out] Buffer A pointer to a buffer receiving the string
> + @param [in] BufferSize Size of the buffer
> +
> + @return EFI_SUCCESS Successful conversion
> + @return EFI_INVALID_PARAMETER Conversion failed
> +
> +**/
> +
> +STATIC
> +EFI_STATUS
> +GuidToString (
> + IN EFI_GUID *Guid,
> + OUT CHAR16 *Buffer,
> + IN UINTN BufferSize
> + )
> +{
> + UINTN Size;
> + EFI_STATUS Status;
> +
> + Status = EFI_SUCCESS;
> +
> + Size = UnicodeSPrint (
> + Buffer,
> + BufferSize,
> + L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
> + (UINTN)Guid->Data1,
> + (UINTN)Guid->Data2,
> + (UINTN)Guid->Data3,
> + (UINTN)Guid->Data4[0],
> + (UINTN)Guid->Data4[1],
> + (UINTN)Guid->Data4[2],
> + (UINTN)Guid->Data4[3],
> + (UINTN)Guid->Data4[4],
> + (UINTN)Guid->Data4[5],
> + (UINTN)Guid->Data4[6],
> + (UINTN)Guid->Data4[7]
> + );
> + if (!Size) {
> + Status = EFI_INVALID_PARAMETER;
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Get a string representation of a known
> + partition type GUID. If partition GUID is not
> + known, gets a string representation of the GUID
> +
> + @param GUID Guid to be searched for
> + @param PartTypeStr Buffer receiving the string
> + @param NoGuidStr Do not convert GUID to string
> + for an unknown partition type
> +
> + @return EFI_SUCCESS GUID type is known
> + @return EFI_NOT_FOUND Unknown GUID partition type
> +
> +**/
> +EFI_STATUS
> +GetPartitionTypeStr (
> + IN EFI_GUID Guid,
> + OUT CHAR16 *PartTypeStr,
> + IN BOOLEAN NoGuidStr)
> +{
> + UINTN Index;
> + EFI_STATUS Status;
> +
> + Status = EFI_SUCCESS;
> + for (Index = 0; Index < ARRAY_SIZE (PartitionTypes); Index++) {
> + if (CompareGuid (&Guid, &PartitionTypes[Index].TypeGuid)) {
> + StrnCpy (PartTypeStr, PartitionTypes[Index].TypeName,
> MAX_PARTITION_NAME_LENGTH);
> + return Status;
> + }
> + }
> + if (!NoGuidStr) {
> + GuidToString (&Guid, PartTypeStr, (MAX_PARTITION_NAME_LENGTH + 1)
> * sizeof(CHAR16));
> + }
> + return EFI_NOT_FOUND;
> +}
> +
> +/**
> + Lists partitions on a block device.
> +
> + @return Number of partitions used
> +**/
> +
> +UINTN
> +PartitionListGptEntries (VOID)
> +{
> + UINTN Index;
> + EFI_PARTITION_ENTRY *Entry;
> + EFI_LBA Length;
> + UINTN NumEntries; // Used entries
> + UINTN BlockSize;
> + BOOLEAN FirstTime;
> + UINT64 BlocksOccupied;
> +
> + NumEntries = 0;
> + BlockSize = BlockIo->Media->BlockSize;
> + FirstTime = TRUE;
> +
> + if (!GptValid) {
> + return 0;
> + }
> +
> + BlocksOccupied = 0;
> +
> + for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries;
> Index++) {
> +
> + BOOLEAN Specific;
> + CHAR16 PartTypeStr[MAX_PARTITION_NAME_LENGTH + 1];
> +
> + Specific = FALSE;
> +
> + Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index *
> PrimaryHeader->SizeOfPartitionEntry);
> +
> + Length = Entry->EndingLBA - Entry->StartingLBA + 1;
> +
> + if (CompareGuid (&Entry->PartitionTypeGUID,
> &gEfiPartTypeUnusedGuid)) {
> + continue;
> + }
> +
> + if (FirstTime) {
> + Print (L" No \t%-36s\tStart (LBA)\tEnd (LBA)\tSize (MiB)\t Partition
> Type\r\n", L"Name");
> + Print (L" ---- -------------------------------------- ----------- ----------- -----
> ----- -------------------------------\r\n");
> + FirstTime = FALSE;
> + }
> + NumEntries++;
> + if (PEntryStatus[Index].OutOfRange ||
> + PEntryStatus[Index].Overlap ||
> + PEntryStatus[Index].OsSpecific) {
> + Specific = TRUE;
> + }
> +
> + BlocksOccupied += Length;
> +
> + GetPartitionTypeStr (Entry->PartitionTypeGUID, (CHAR16 *)&PartTypeStr,
> FALSE);
> +
> + Print (L"%1s %-3d\t%-36s\t0x%09llx\t0x%09llx\t%06llu\t %s\r\n",
> + Specific ? L"S" : L"",
> + Index + 1,
> + Entry->PartitionName,
> + (UINT64)Entry->StartingLBA,
> + (UINT64)Entry->EndingLBA,
> + (MultU64x32 (Length, BlockSize)) >> 20,
> + PartTypeStr);
> + }
> +
> + // This code block is to provide additional info
> + {
> + UINT64 DiskSizeMiB, SizeOccupiedMiB;
> +
> + DiskSizeMiB = MultU64x32 (PrimaryHeader->LastUsableLBA -
> PrimaryHeader->FirstUsableLBA + 1, BlockIo->Media->BlockSize) >> 20;
> + SizeOccupiedMiB = MultU64x32 (BlocksOccupied, BlockIo->Media-
> >BlockSize) >> 20;
> + Print (L"\r\n%d partition(s) used out of %d\r\n", NumEntries,
> PrimaryHeader->NumberOfPartitionEntries);
> + Print (L"Total device capacity (minus GPT service blocks): %llu
> MiB\r\nPartitioned space: %llu MiB\r\n",
> + DiskSizeMiB,
> + SizeOccupiedMiB);
> + Print (L"Unpartitioned space available: %llu MiB (%d%%)\n",
> + DiskSizeMiB - SizeOccupiedMiB,
> + (100 * (DiskSizeMiB - SizeOccupiedMiB)) / DiskSizeMiB);
> + }
> +
> + return NumEntries;
> +}
> +
> +/**
> + Locate a partition by criteria
> +
> + @param Name Partition name (or ordinal represented a string)
> + @param StartLba StartLba of the partition to search for
> + @param EndingLba EndingLba of the partition to search for
> + @param SearchType A combination (OR) of search options.
> + Options are:
> + SRC_BY_NAME = search by partition name
> + SRC_BY_LBA = search by Start/Ending lba
> + SRC_ANY = returns a first used partition
> + SRC_BY_NUM = search by ordinal
> +
> +
> + @return Non-NULL Pointer to th partition found
> + @return NULL No partition found
> +
> +**/
> +EFI_PARTITION_ENTRY *
> +PartitionFindPartitionByCriteria (
> + IN OPTIONAL CONST CHAR16 *Name,
> + IN OPTIONAL EFI_LBA StartLba,
> + IN OPTIONAL EFI_LBA EndingLba,
> + IN SEARCH_TYPE SearchType
> + )
> +{
> + UINTN Index;
> + EFI_PARTITION_ENTRY *Entry;
> +
> + if (!GptValid) {
> + return NULL;
> + }
> +
> + if (!Name && (SearchType & SRC_BY_NAME)) {
> + return NULL;
> + }
> +
> + for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries;
> Index++) {
> + Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index *
> PrimaryHeader->SizeOfPartitionEntry);
> +
> + if (CompareGuid (&Entry->PartitionTypeGUID,
> &gEfiPartTypeUnusedGuid)) {
> + continue;
> + }
> +
> + if (SearchType & SRC_ANY) {
> + return Entry;
> + }
> +
> + if (SearchType & SRC_BY_NAME) {
> + if (!StrCmp (Name, Entry->PartitionName)) {
> + return Entry;
> + }
> + }
> + if (SearchType & SRC_BY_NUM) {
> + UINTN Ordinal;
> +
> + Ordinal = ShellStrToUintn (Name);
> + if (Index == (Ordinal - 1)) {
> + return Entry;
> + }
> + }
> + if (SearchType & SRC_BY_LBA) {
> + if (
> + ((StartLba >= Entry->StartingLBA) &&
> + (StartLba <= Entry->EndingLBA)
> + ) ||
> + ((EndingLba >= Entry->StartingLBA) &&
> + (EndingLba <= Entry->EndingLBA)
> + )
> + ) {
> + return Entry;
> + }
> + }
> + }
> + return NULL;
> +}
> +
> +/**
> + Prints information on a given partition.
> +
> + @param Entry Pointer to the Partition of interest
> +**/
> +
> +VOID
> +PartitionPrintGptPartInfo (
> + IN EFI_PARTITION_ENTRY *Entry
> + )
> +{
> + CONST CHAR16 PartStr[MAX_PARTITION_NAME_LENGTH + 1] = { L'\0' };
> + CONST CHAR16 *StrUnknown = L"Unknown";
> + EFI_STATUS Status;
> + EFI_LBA Length;
> +
> + ASSERT (Entry);
> +
> + Status = GetPartitionTypeStr (Entry->PartitionTypeGUID, (CHAR16
> *)&PartStr, TRUE);
> + if (EFI_ERROR (Status)) {
> + StrCpy ((CHAR16 *)&PartStr, StrUnknown);
> + }
> +
> + Length = Entry->EndingLBA - Entry->StartingLBA + 1;
> +
> + Print (L"Partition name: %s\r\n", Entry->PartitionName);
> + Print (L"Starting LBA : 0x%09llx\r\nEnding LBA : 0x%09llx\r\n",
> + (UINT64)Entry->StartingLBA, (UINT64)Entry->EndingLBA);
> + Print (L"Partition Size: %llu MiB (0x%llx blocks)\n",
> + (MultU64x32 (Length, BlockIo->Media->BlockSize)) >> 20, Length);
> + Print (L"Attributes : 0x%09llx\r\n", Entry->Attributes);
> + Print (L"Type/GUID : %s/%g\r\n", PartStr, &Entry->PartitionTypeGUID);
> + Print (L"Unique GUID : %g\n", &Entry->UniquePartitionGUID);
> +}
> +
> +
> +/**
> + Writes protective MBR to a block device.
> +
> + @return EFI_SUCCESS MBR written successfully
> + @return other Failed to write an MBR
> +
> +**/
> +
> +STATIC
> +EFI_STATUS
> +WriteProtectiveMbr (
> + VOID
> + )
> +{
> + UINT32 BlockSize;
> + UINT64 DiskSize;
> + EFI_STATUS Status;
> + MBR_PARTITION_RECORD *Partition;
> + MASTER_BOOT_RECORD *ProtectiveMbr;
> +
> + BlockSize = BlockIo->Media->BlockSize;
> +
> + ProtectiveMbr = NULL;
> + ProtectiveMbr = AllocateZeroPool (BlockSize);
> + if (ProtectiveMbr == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + DiskSize = BlockIo->Media->LastBlock + 1;
> + if (DiskSize > 0xffffffff) {
> + DiskSize = 0xffffffff;
> + }
> +
> + CopyMem (ProtectiveMbr, &ProtectiveMbrTemplate,
> sizeof(MASTER_BOOT_RECORD));
> +
> + Partition = &ProtectiveMbr->Partition[0];
> +
> + Partition->BootIndicator = 0;
> + Partition->StartSector = 1;
> +
> + //
> + // We don't actually know this data, so we'll make up
> + // something that seems likely.
> + //
> +
> + //
> + // Old software is expecting the Partition to start on
> + // a Track boundary, so we'll set track to 1 to avoid "overlay"
> + // with the MBR
> + //
> +
> + Partition->StartTrack = 1;
> +
> + Status = DiskIo->WriteDisk (
> + DiskIo,
> + BlockIo->Media->MediaId,
> + 0,
> + BlockSize,
> + ProtectiveMbr
> + );
> +
> + MbrValid = !EFI_ERROR (Status);
> +
> + SHELL_FREE_NON_NULL (ProtectiveMbr);
> +
> + return Status;
> +}
> +
> +/**
> + Write GPT tables to the block device.
> +
> + @return EFI_SUCCESS GPT tables were successfully written/updated
> + @return other Failed to write/update GPT tables
> +
> +**/
> +
> +STATIC
> +EFI_STATUS
> +WriteGPT (
> + VOID
> + )
> +/*
> + CALLER is expected to fill in:
> + FirstUseableLBA
> + LastUseableLBA
> + EntryCount
> + DiskGUID
> +
> + We fill in the rest, and blast it out.
> +
> + Returns a status.
> +
> +*/
> +{
> + UINT32 BlockSize;
> + UINT32 TableSize;
> + EFI_STATUS Status = EFI_SUCCESS;
> +
> + BlockSize = BlockIo->Media->BlockSize;
> + TableSize = PrimaryHeader->NumberOfPartitionEntries *
> sizeof(EFI_PARTITION_ENTRY);
> +
> + if (!MbrValid) {
> + WriteProtectiveMbr ();
> + }
> + //
> + // Write out the primary header...
> + //
> + PrimaryHeader->Header.Signature = EFI_PTAB_HEADER_ID;
> + PrimaryHeader->Header.Revision = GPT_REVISION_1_0;
> + PrimaryHeader->Header.HeaderSize =
> sizeof(EFI_PARTITION_TABLE_HEADER);
> +
> + PrimaryHeader->AlternateLBA = BackupHeader->MyLBA;
> +
> + PrimaryHeader->SizeOfPartitionEntry = sizeof(EFI_PARTITION_ENTRY);
> +
> + Status = gBS->CalculateCrc32 ((UINT8 *)PartEntry, TableSize,
> &PrimaryHeader->PartitionEntryArrayCRC32);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + // Write primary header
> + PartitionSetCrc (&PrimaryHeader->Header);
> +
> + Status = DiskIo->WriteDisk (
> + DiskIo,
> + BlockIo->Media->MediaId,
> + MultU64x32 (PrimaryHeader->MyLBA, (UINT32)BlockSize),
> + BlockSize,
> + PrimaryHeader
> + );
> +
> +
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + //
> + // Write out the primary table ...
> + //
> + Status = DiskIo->WriteDisk (
> + DiskIo,
> + BlockIo->Media->MediaId,
> + MultU64x32 (PrimaryHeader->PartitionEntryLBA, (UINT32)BlockSize),
> + TableSize,
> + PartEntry
> + );
> +
> +
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + //
> + // Write out the secondary header and table by calling restore
> + //
> +
> + if (!PartitionRestoreGptTable (PrimaryHeader)) {
> + return EFI_VOLUME_CORRUPTED;
> + }
> + BlockIo->FlushBlocks (BlockIo);
> + GptValid = !EFI_ERROR (Status);
> +
> + return Status;
> +}
> +
> +/**
> + (Re)initialize GPT tables on the block device
> +
> + @return EFI_SUCCESS Successfully (re)initialized GPT Tables
> + @return other Failed to (re)initialize GPT tables
> +
> +**/
> +STATIC
> +EFI_STATUS
> +TableCreateEmptyGpt (VOID)
> +{
> + UINTN EntryCount;
> + UINTN BlockFit;
> + UINTN BlockSize;
> + UINTN EntryBlocks;
> + UINT64 DiskSize;
> + UINTN TableSize;
> + EFI_LBA Header1_LBA;
> + EFI_LBA Table1_LBA;
> + EFI_LBA Header2_LBA;
> + EFI_LBA Table2_LBA;
> + EFI_LBA FirstUsableLBA;
> + EFI_LBA LastUsableLBA;
> + EFI_STATUS Status;
> +
> + EntryCount = ENTRY_DEFAULT;
> + BlockSize = BlockIo->Media->BlockSize;
> + BlockFit = BlockSize / sizeof(EFI_PARTITION_ENTRY);
> +
> + if (BlockFit > ENTRY_DEFAULT) {
> + EntryCount = BlockFit;
> + }
> + EntryBlocks = EntryCount / BlockFit;
> +
> + if ((EntryBlocks * BlockFit) != EntryCount) {
> + Status = EFI_VOLUME_CORRUPTED;
> + PrintErr (L"Invalid Entry blocks and Entry count combination\n", Status);
> + return Status;
> + }
> +
> + DiskSize = BlockIo->Media->LastBlock + 1;
> +
> + SHELL_FREE_NON_NULL (PrimaryHeader);
> + SHELL_FREE_NON_NULL (BackupHeader);
> + SHELL_FREE_NON_NULL (PartEntry);
> +
> + PrimaryHeader = AllocateZeroPool (BlockSize);
> + if (PrimaryHeader == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + BackupHeader = AllocateZeroPool (BlockSize);
> + if (BackupHeader == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + Header1_LBA = 1;
> + Table1_LBA = 2;
> + FirstUsableLBA = Table1_LBA + EntryBlocks;
> +
> + Header2_LBA = DiskSize - 1;
> + Table2_LBA = Header2_LBA - EntryBlocks;
> + LastUsableLBA = Table2_LBA - 1;
> +
> + TableSize = EntryBlocks * BlockSize;
> +
> + if (TableSize != (EntryCount * sizeof(EFI_PARTITION_ENTRY))) {
> + Status = EFI_VOLUME_CORRUPTED;
> + PrintErr (L"Invalid Table size and Entry count combination\n", Status);
> + return Status;
> + }
> +
> + if (GPT_DEBUG_LEVEL) {
> + Print (L"DiskSize = %lx\n", DiskSize);
> + Print (L"BlockSize = %x\n", BlockSize);
> + Print (L"Header1_LBA = %lx\n", Header1_LBA);
> + Print (L"Table1_LBA = %lx\n", Table1_LBA);
> + Print (L"FirstUsableLBA = %lx\n", FirstUsableLBA);
> + Print (L"Header2_LBA = %lx\n", Header2_LBA);
> + Print (L"Table2_LBA = %lx\n", Table2_LBA);
> + Print (L"LastUsableLBA = %lx\n", LastUsableLBA);
> + Print (L"EntryCount = %x\n", EntryCount);
> + Print (L"EntryBlocks = %x\n", EntryBlocks);
> + }
> +
> + //
> + // Since we're making empty tables, we just write zeros...
> + //
> +
> + PartEntry = AllocateZeroPool (TableSize);
> + if (PartEntry == NULL) {
> + SHELL_FREE_NON_NULL (PrimaryHeader);
> + SHELL_FREE_NON_NULL (BackupHeader);
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + PEntryStatus = AllocateZeroPool (TableSize);
> +
> + PrimaryHeader->FirstUsableLBA = FirstUsableLBA;
> + PrimaryHeader->LastUsableLBA = LastUsableLBA;
> + PrimaryHeader->NumberOfPartitionEntries = (UINT32)EntryCount;
> + GenerateGuid (&PrimaryHeader->DiskGUID);
> +
> + PrimaryHeader->MyLBA = Header1_LBA;
> + BackupHeader->MyLBA = Header2_LBA;
> + PrimaryHeader->PartitionEntryLBA = Table1_LBA;
> + BackupHeader->PartitionEntryLBA = Table2_LBA;
> +
> + Status = WriteGPT ();
> +
> + return Status;
> +}
> +
> +/**
> + Clear GPT partitions.
> +
> + @return EFI_SUCCESS Cleared successfully
> + @return FALSE Failed to clear
> +
> +**/
> +
> +EFI_STATUS
> +PartitionGptClearAll (VOID)
> +{
> + GptCleanupGlobals ();
> + GptValid = FALSE;
> + MbrValid = FALSE;
> + return TableCreateEmptyGpt ();
> +}
> +
> +/**
> + Create a GPT partition.
> +
> + @param PartName Partition Name
> + @param StartLba Starting LBA of the partition.
> + if zero, will be calculated
> + @param SizeInMegaBytes Size of the partition in MB
> + @param Attributes Partition attributes
> + @param PartTypeGuid a Type GUID to be assigned to the partition
> (not a partition unique GUID)
> +
> +
> + @return EFI_SUCCESS Partition successfully created
> + @return EFI_INVALID_PARAMETER Either partition exists, or wrong
> parameters specified
> + @return other Failed to create a partition
> +**/
> +EFI_STATUS
> +PartitionGptCreatePartition (
> + IN CONST CHAR16 *PartName,
> + IN EFI_LBA StartLba,
> + IN UINT64 SizeInMegabytes,
> + IN UINT64 Attributes,
> + IN EFI_GUID PartTypeGuid)
> +{
> + EFI_GUID Guid, PartitionIdGuid;
> + EFI_STATUS Status;
> + UINT64 StartBlock;
> + UINT64 EndBlock;
> + UINT64 SizeInBytes = 0;
> + UINT32 BlockSize;
> + UINT64 DiskSizeBlocks;
> + UINT8 *p;
> + BOOLEAN OffsetSpecified = FALSE;
> + BOOLEAN AllZeros;
> + INTN AllZeroEntry;
> + INTN OldFreeEntry;
> + UINT64 AvailBlocks;
> + UINT64 BlocksToAllocate;
> + UINT64 HighSeen;
> + UINTN Slot;
> + UINT64 LowestAlignedLba;
> + UINT32 OptimalTransferBlocks;
> + UINTN i, j;
> + CHAR16 PartNameUsed[MAX_PARTITION_NAME_LENGTH + 1] = { L'\0' };
> + EFI_PARTITION_ENTRY *Entry;
> +
> + LowestAlignedLba = 0;
> + OptimalTransferBlocks = 1;
> +
> + AllZeroEntry = -1;
> + OldFreeEntry = -1;
> +
> + BlockSize = BlockIo->Media->BlockSize;
> + OffsetSpecified = (StartLba != 0);
> + CopyMem (&PartNameUsed, PartName, sizeof(CHAR16) * StrSize
> (PartName));
> +
> + GenerateGuid (&Guid);
> +
> + // Creating a new partition
> + if (!GptValid) {
> + // Creating a GPT for the first time
> + Status = TableCreateEmptyGpt ();
> + if (!EFI_ERROR (Status)) {
> + // Fill in the structures
> + Status = PartitionGetGptTables (DiskIo, BlockIo);
> + }
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + }
> +
> + Entry = PartitionFindPartitionByCriteria (PartName, 0, 0, SRC_BY_NAME);
> + if (Entry) {
> + Status = EFI_INVALID_PARAMETER;
> + PrintErr (L"Partition with this name already exists", Status);
> + return Status;
> + }
> + HighSeen = PrimaryHeader->FirstUsableLBA - 1;
> +
> + if (StartLba) {
> + //
> + // if offset is specified, compute the start and end blocks
> + //
> + StartBlock = StartLba;
> + //
> + // StartBlock should be aligned to OptimalTransferBlocks, the least
> common multiple of:
> + // a). the physical block boundary, if any
> + // b). the optimal transfer length granularity, if any
> + //
> + if (StartBlock < LowestAlignedLba) {
> + StartBlock = LowestAlignedLba;
> + } else {
> + while (((StartBlock - LowestAlignedLba) % OptimalTransferBlocks) != 0) {
> + StartBlock++;
> + }
> + }
> +
> + if (StartBlock < PrimaryHeader->FirstUsableLBA ||
> + StartBlock > PrimaryHeader->LastUsableLBA) {
> + //
> + // Offset specified is too large
> + //
> + Status = EFI_INVALID_PARAMETER;
> + PrintErr (L"Specified offset is too large", EFI_INVALID_PARAMETER);
> + goto Exit;
> + }
> +
> + SizeInBytes = MultU64x32 (SizeInMegabytes, (1024 * 1024));
> + if (SizeInBytes < SizeInMegabytes || SizeInBytes == 0) {
> + //
> + // If size is not specified or too large,
> + // try to make the partition as big as it can be
> + //
> + BlocksToAllocate = EndBlock = SizeInBytes = 0xffffffffffffffff;
> + } else {
> + BlocksToAllocate = DivU64x32 (SizeInBytes, BlockSize);
> + EndBlock = StartBlock + BlocksToAllocate - 1;
> + if (EndBlock > PrimaryHeader->LastUsableLBA) {
> + EndBlock = PrimaryHeader->LastUsableLBA;
> + BlocksToAllocate = EndBlock - StartBlock + 1;
> + }
> + }
> + }
> +
> + for (i = 0; i < PrimaryHeader->NumberOfPartitionEntries; i++) {
> + Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + i *
> PrimaryHeader->SizeOfPartitionEntry);
> + if (!CompareGuid (&Entry->PartitionTypeGUID,
> &gEfiPartTypeUnusedGuid)) {
> +
> + //
> + // Type not null, so it's allocated
> + //
> + if (Entry->EndingLBA > HighSeen) {
> + HighSeen = Entry->EndingLBA;
> + }
> + if (OffsetSpecified) {
> + //
> + // make sure new partition does not overlap with existing partitions
> + //
> + if (Entry->StartingLBA <= StartBlock &&
> + StartBlock <= Entry->EndingLBA) {
> + //
> + // starting block is inside an existing partition
> + //
> + Status = EFI_INVALID_PARAMETER;
> + PrintErr (L"Starting block is inside an existing partition", Status);
> + goto Exit;
> + }
> + if ((Entry->StartingLBA <= EndBlock &&
> + EndBlock <= Entry->EndingLBA) ||
> + (StartBlock <= Entry->StartingLBA &&
> + Entry->StartingLBA <= EndBlock) ||
> + (StartBlock <= Entry->EndingLBA &&
> + Entry->EndingLBA <= EndBlock)) {
> + //
> + // new partition overlaps with an existing partition
> + // readjust new partition size to avoid overlapping
> + //
> + EndBlock = Entry->StartingLBA - 1;
> + if (EndBlock < StartBlock) {
> + Status = EFI_INVALID_PARAMETER;
> + PrintErr (L"Cannot readjust new partition size - overlapping", Status);
> + goto Exit;
> + } else {
> + BlocksToAllocate = EndBlock - StartBlock + 1;
> + }
> + }
> + }
> + } else {
> + p = (UINT8 *)(Entry);
> + AllZeros = TRUE;
> + for (j = 0; j < sizeof(EFI_PARTITION_ENTRY); j++) {
> + if (p[j] != 0) {
> + AllZeros = FALSE;
> + }
> + }
> + if (AllZeros) {
> + if (AllZeroEntry == -1) {
> + AllZeroEntry = i;
> + }
> + } else if (OldFreeEntry == -1) {
> + OldFreeEntry = i;
> + }
> + }
> + }
> +
> + //
> + // AllZeroEntry - if not -1, is pointer to a never before used entry (free)
> + // OldFreeEntry - if not -1, is pointer to some pre-used free entry
> + //
> + if ((AllZeroEntry == -1) && (OldFreeEntry == -1)) {
> + //
> + // TABLE IS FULL!!
> + //
> + Status = EFI_OUT_OF_RESOURCES;
> + PrintErr (L"Table is full", Status);
> + goto Exit;
> + }
> +
> + if (OffsetSpecified) {
> + //
> + // the user haven't specified the new partition size and we haven't
> + // run into any partition that will limit the size of this new partition.
> + // So, use the max it can
> + //
> + if (BlocksToAllocate == -1) {
> + EndBlock = PrimaryHeader->LastUsableLBA;
> + BlocksToAllocate = EndBlock - StartBlock + 1;
> + }
> + } else {
> + //
> + // Because HighSeen is the last LBA of the used blocks, let HighSeen align
> to the least common multiple of:
> + // a). the physical block boundary, if any
> + // b). the optimal transfer length granularity, if any
> + //
> + if (HighSeen + 1 < LowestAlignedLba) {
> + HighSeen = LowestAlignedLba - 1;
> + } else {
> + while (((HighSeen + 1 - LowestAlignedLba) % OptimalTransferBlocks) != 0)
> {
> + HighSeen++;
> + }
> + }
> +
> + if (PrimaryHeader->LastUsableLBA <= HighSeen) {
> + Status = EFI_OUT_OF_RESOURCES;
> + PrintErr (L"Disk has no free blocks (FULL) cannot create", Status);
> + goto Exit;
> + }
> + //
> + // [HighSeen+1 ... LastUsableLBA] is available...
> + // avail = (LastUsableLBA - (HighSeen+1)) + 1 => LastUsabbleLBA -
> HighSeen
> + //
> + AvailBlocks = PrimaryHeader->LastUsableLBA - HighSeen;
> +
> + SizeInBytes = MultU64x32 (SizeInMegabytes, (1024 * 1024));
> + if (SizeInBytes < SizeInMegabytes) {
> + //
> + // overflow, force a very big answer
> + //
> + SizeInBytes = 0xffffffffffffffff;
> + }
> +
> + if ((SizeInBytes == 0) ||
> + (SizeInBytes > (MultU64x32 (AvailBlocks, BlockSize)))) {
> + //
> + // User asked for zero, or for more than we've got,
> + // so give them all that is left
> + //
> + BlocksToAllocate = AvailBlocks;
> +
> + } else {
> +
> + //
> + // We would have to have a BlockSize > 1mb for Remainder to
> + // not be 0. Since we cannot actually test this case, we
> + // ingore it...
> + //
> + BlocksToAllocate = DivU64x32 (SizeInBytes, BlockSize);
> +
> + }
> + }
> +
> + //
> + // We have a name
> + // We have a type guid
> + // We have a size in blocks
> + // We have an attribute mask
> + //
> +
> + if (BlocksToAllocate < ((1024 * 1024) / BlockSize)) {
> + Status = EFI_OUT_OF_RESOURCES;
> + PrintErr (L"Partition is too small to be created", Status);
> + goto Exit;
> + }
> +
> + if (GPT_DEBUG_LEVEL) {
> + Print (L"Requested SizeInMegaBytes = %ld\n", SizeInMegabytes);
> + Print (L"Resulting size in Blocks = %ld\n", BlocksToAllocate);
> + Print (L"Results size in Bytes = %ld\n", MultU64x32 (BlocksToAllocate,
> BlockSize));
> + }
> +
> + if (AllZeroEntry != -1) {
> + Slot = AllZeroEntry;
> + } else {
> + Slot = OldFreeEntry;
> + }
> +
> + GenerateGuid (&PartitionIdGuid);
> + Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Slot *
> PrimaryHeader->SizeOfPartitionEntry);
> +
> + CopyMem (&Entry->PartitionTypeGUID, &PartTypeGuid,
> sizeof(EFI_GUID));
> + CopyMem (&Entry->UniquePartitionGUID, &PartitionIdGuid,
> sizeof(EFI_GUID));
> + if (OffsetSpecified) {
> + PartEntry[Slot].StartingLBA = StartBlock;
> + PartEntry[Slot].EndingLBA = EndBlock;
> + } else {
> + PartEntry[Slot].StartingLBA = HighSeen + 1;
> + PartEntry[Slot].EndingLBA = HighSeen + BlocksToAllocate;
> + }
> +
> + if (!(((Entry->EndingLBA - Entry->StartingLBA) + 1) == BlocksToAllocate)) {
> + PrintErr (L"Wrong Size for new partiton", EFI_INVALID_PARAMETER);
> + goto Exit;
> + }
> +
> + if ((Entry->StartingLBA < PrimaryHeader->FirstUsableLBA) ||
> + (Entry->EndingLBA > PrimaryHeader->LastUsableLBA)) {
> + PrintErr (L"New Partition out of bounds", EFI_INVALID_PARAMETER);
> + goto Exit;
> + }
> +
> + Entry->Attributes = Attributes;
> + CopyMem (&(Entry->PartitionName[0]), PartName,
> MAX_PARTITION_NAME_LENGTH * sizeof(CHAR16));
> +
> + DiskSizeBlocks = BlockIo->Media->LastBlock + 1;
> + if (DiskSizeBlocks > 0xffffffff) {
> + DiskSizeBlocks = 0xffffffff;
> + }
> +
> + Status = WriteGPT ();
> +
> + if (EFI_ERROR (Status)) {
> + PrintErr (L"Attempt to Write out partition table failed", Status);
> + }
> +
> + Exit:
> + return Status;
> +}
> +
> +/**
> + Modifiy a partition based on parameters.
> +
> + @param Entry Pointer to an existing partition
> + @param Params Parameters to be modified
> + @param Flags Which parameter is to be modified
> +
> + @return EFI_SUCCESS Successfully modified the partition
> + @return other Failed to modify a partition
> +
> +**/
> +
> +EFI_STATUS
> +PartitionGptModifyPartition (
> + IN EFI_PARTITION_ENTRY *Entry,
> + IN MOD_PARAMS *Params,
> + IN MOD_FLAGS Flags
> + )
> +{
> + EFI_STATUS Status;
> +
> + ASSERT (Entry);
> +
> + Status = EFI_INVALID_PARAMETER;
> +
> + switch (Flags) {
> + case MOD_DELETE:
> + ZeroMem (Entry, sizeof(EFI_PARTITION_ENTRY));
> + break;
> + case MOD_ATTR:
> + Entry->Attributes = Params->Attributes;
> + break;
> + case MOD_TYPE:
> + Entry->PartitionTypeGUID = Params->PartTypeGuid;
> + break;
> + case MOD_RENAME:
> + StrCpy (Entry->PartitionName, Params->NewName);
> + break;
> + default:
> + PrintErr (L"Unknown modification flag(s)", Status);
> + return Status;
> + }
> +
> + return WriteGPT ();
> +}
> +
> +EFI_KNOWN_PARTITION_TYPE *PartitionGetKnownType (
> + IN UINTN Index,
> + IN OUT OPTIONAL UINTN *NumEntries
> + )
> +{
> + if (NumEntries) {
> + *NumEntries = ARRAY_SIZE(PartitionTypes);
> + }
> + if (Index > ARRAY_SIZE(PartitionTypes)) {
> + return NULL;
> + }
> +
> + return &PartitionTypes[Index];
> +}
> +
> diff --git a/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> new file mode 100644
> index 000000000000..9efec5cefe94
> --- /dev/null
> +++ b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> @@ -0,0 +1,186 @@
> +/*
> + * BSD LICENSE
> + *
> + * Copyright(c) 2016 Broadcom. All rights reserved.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + *
> + * * Redistributions of source code must retain the above copyright
> + * notice, this list of conditions and the following disclaimer.
> + * * Redistributions in binary form must reproduce the above copyright
> + * notice, this list of conditions and the following disclaimer in
> + * the documentation and/or other materials provided with the
> + * distribution.
> + * * Neither the name of Broadcom nor the names of its
> + * contributors may be used to endorse or promote products derived
> + * from this software without specific prior written permission.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> CONTRIBUTORS
> + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
> NOT
> + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
> FITNESS FOR
> + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
> COPYRIGHT
> + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> NOT
> + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
> OF USE,
> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
> AND ON ANY
> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
> THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> DAMAGE.
> + */
> +
> +/* GPT partitioner header file */
> +
> +#ifndef _GPTWORKER_H_
> +#define _GPTWORKER_H_
> +
> +#include <Uefi.h>
> +#include <ShellBase.h>
> +
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/ShellCommandLib.h>
> +#include <Library/ShellLib.h>
> +#include <Library/UefiLib.h>
> +#include <Library/UefiShellLib/UefiShellLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiRuntimeServicesTableLib.h>
> +#include <Library/PrintLib.h>
> +#include <Library/ShellCEntryLib.h>
> +#include <Library/HiiLib.h>
> +#include <Library/FileHandleLib.h>
> +#include <Protocol/DevicePath.h>
> +#include <Library/DevicePathLib.h>
> +#include <Protocol/BlockIo.h>
> +#include <Protocol/DiskIo.h>
> +#include <IndustryStandard/Mbr.h>
> +
> +typedef enum {
> + MOD_NAME = BIT0,
> + MOD_ATTR = BIT1,
> + MOD_TYPE = BIT2,
> + MOD_DELETE = BIT3,
> + MOD_RENAME = BIT4
> +} MOD_FLAGS;
> +
> +typedef struct {
> + UINTN Attributes;
> + EFI_GUID PartTypeGuid;
> + CONST CHAR16 *PartName;
> + CONST CHAR16 *NewName;
> +} MOD_PARAMS;
> +
> +typedef enum {
> + SRC_BY_NAME = BIT0,
> + SRC_BY_LBA = BIT1,
> + SRC_BY_NUM = BIT2,
> + SRC_ANY = BIT3
> +} SEARCH_TYPE;
> +
> +#define MAX_PARTITION_NAME_LENGTH 36
> +#define ENTRY_DEFAULT 128
> +#define GPT_REVISION_1_0 0x00010000
> +
> +#define ARRAY_SIZE(x) \
> + (sizeof(x) / sizeof((x)[0]))
> +
> +//
> +// Extract INT32 from char array
> +//
> +#define UNPACK_INT32(a) (INT32)( (((UINT8 *) a)[0] << 0) | \
> + (((UINT8 *) a)[1] << 8) | \
> + (((UINT8 *) a)[2] << 16) | \
> + (((UINT8 *) a)[3] << 24) )
> +
> +//
> +// Extract UINT32 from char array
> +//
> +#define UNPACK_UINT32(a) (UINT32)( (((UINT8 *) a)[0] << 0) | \
> + (((UINT8 *) a)[1] << 8) | \
> + (((UINT8 *) a)[2] << 16) | \
> + (((UINT8 *) a)[3] << 24) )
> +
> +
> +//
> +// GPT Partition Entry Status
> +//
> +typedef struct {
> + BOOLEAN OutOfRange;
> + BOOLEAN Overlap;
> + BOOLEAN OsSpecific;
> +} EFI_PARTITION_ENTRY_STATUS;
> +
> +typedef struct {
> + CONST EFI_GUID TypeGuid;
> + CONST CHAR16 *TypeName;
> +
> +} EFI_KNOWN_PARTITION_TYPE;
> +
> +EFI_KNOWN_PARTITION_TYPE *PartitionGetKnownType (
> + IN UINTN Index,
> + IN OUT OPTIONAL UINTN *NumEntries
> + );
> +
> +EFI_STATUS
> +PartitionGetGptTables (
> + IN EFI_DISK_IO_PROTOCOL *DiskIoProt,
> + IN EFI_BLOCK_IO_PROTOCOL *BlockIoProt
> + );
> +
> +UINTN
> +PartitionListGptEntries (
> + VOID
> + );
> +
> +VOID
> +PartitionPrintGptPartInfo (
> + IN EFI_PARTITION_ENTRY *Entry
> + );
> +
> +EFI_STATUS
> +GetPartitionTypeStr (
> + EFI_GUID Guid,
> + CHAR16 *PartTypeStr,
> + BOOLEAN NoGuidStr
> + );
> +
> +
> +EFI_STATUS
> +PartitionGptClearAll (
> + VOID
> + );
> +
> +EFI_STATUS
> +PartitionGptCreatePartition (
> + CONST CHAR16 *PartName,
> + EFI_LBA StartLba,
> + EFI_LBA PartitionSize,
> + UINT64 Attributes,
> + EFI_GUID PartTypeGuid);
> +
> +EFI_STATUS
> +PartitionGptModifyPartition (
> + EFI_PARTITION_ENTRY *Entry,
> + MOD_PARAMS *Params,
> + MOD_FLAGS Flags
> + );
> +
> +VOID
> +GptCleanupGlobals (
> + VOID
> + );
> +
> +EFI_PARTITION_ENTRY *
> +PartitionFindPartitionByCriteria (
> + CONST CHAR16 *Name,
> + EFI_LBA StartLba,
> + EFI_LBA EndingLba,
> + SEARCH_TYPE SearchType);
> +
> +VOID
> +PrintErr (IN CONST CHAR16 *Message, IN EFI_STATUS Status);
> +
> +#endif //_GPTWORKER_H_
> diff --git
> a/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> new file mode 100644
> index 000000000000..a9d74a780911
> --- /dev/null
> +++
> b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> @@ -0,0 +1,1135 @@
> +/*********************************************************
> **********************
> +Copyright (C) 2016 Marvell International Ltd.
> +
> +Marvell BSD License Option
> +
> +If you received this File from Marvell, you may opt to use, redistribute
> and/or
> +modify this File under the following licensing terms.
> +Redistribution and use in source and binary forms, with or without
> modification,
> +are permitted provided that the following conditions are met:
> +
> +* Redistributions of source code must retain the above copyright notice,
> + this list of conditions and the following disclaimer.
> +
> +* Redistributions in binary form must reproduce the above copyright
> + notice, this list of conditions and the following disclaimer in the
> + documentation and/or other materials provided with the distribution.
> +
> +* Neither the name of Marvell nor the names of its contributors may be
> + used to endorse or promote products derived from this software without
> + specific prior written permission.
> +
> +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> CONTRIBUTORS "AS IS" AND
> +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
> THE IMPLIED
> +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> PURPOSE ARE
> +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> CONTRIBUTORS BE LIABLE FOR
> +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> CONSEQUENTIAL DAMAGES
> +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
> OR SERVICES;
> +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
> CAUSED AND ON
> +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> TORT
> +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
> THE USE OF THIS
> +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +
> +*********************************************************
> **********************/
> +
> +/* Portions Copyright (C) 2016 Broadcom */
> +
> +#include "FatFormat.h"
> +#include
> <Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.h>
> +#include <Library/TimerLib.h>
> +
> +CONST CHAR16 gShellGptFileName[] = L"ShellCommand";
> +STATIC CONST CHAR16 gAppName[] = L"gpt";
> +EFI_HANDLE gShellGptHiiHandle = NULL;
> +
> +STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
> + // Partition-related operations
> + { L"clear", TypeFlag }, // Clears all partitions
> + { L"create", TypeFlag }, // Creates a partition
> + { L"delete", TypeFlag }, // Deletes a partition
> + { L"list", TypeFlag }, // Lists all partitions
> + { L"rename", TypeFlag }, // Renames a partition
> + { L"setattr", TypeFlag }, // Set attributes for a partition in partition
> table
> + { L"settype", TypeFlag },
> + { L"sync", TypeFlag }, // Synchronizes either master or alternative
> partition table
> + { L"typesinfo", TypeFlag }, // Verifies correctness of master and
> alternative partition tables
> + // BlockIo-related operations
> + { L"read", TypeFlag }, // Reads n bytes into memory address from
> a partition starting from a certain lba
> + { L"readfile", TypeFlag }, // Same as above, but instead of store it in
> memory saves into a file system
> + { L"write", TypeFlag }, // Writes n bytes from memory into a
> partition starting from a certain lba
> + { L"writefile", TypeFlag }, // Same as above, but instead of getting
> data from memory reads a file
> + { L"info", TypeFlag }, // Get information on a certain partition
> (startLba, lastLba, attributes)
> + { L"fatformat", TypeFlag }, // FAT format of a partition
> + { L"-type", TypeValue },
> + { L"-yes", TypeFlag },
> + { L"-verbose", TypeFlag },
> + { NULL, TypeMax }
> +};
> +
> +typedef enum {
> + // Not requires presence
> + CLEAR = BIT0,
> + CREATE = BIT1,
> + LIST = BIT2,
> + SYNC = BIT3,
> + TYPES_INFO = BIT4,
> +
> + // Requires presence
> + DELETE = BIT5,
> + INFO = BIT6,
> + READ = BIT7,
> + READ_FILE = BIT8,
> + RENAME = BIT9,
> + SETATTR = BIT10,
> + SETTYPE = BIT11,
> + WRITE = BIT12,
> + WRITE_FILE = BIT13,
> + FAT_FORMAT = BIT14,
> +} Flags;
> +
> +/**
> + Return the file name of the help text file if not using HII.
> +
> + @return The string pointer to the file name.
> +**/
> +CONST CHAR16 *
> +EFIAPI
> +ShellCommandGetManFileNameGpt (
> + VOID
> + )
> +{
> +
> + return gShellGptFileName;
> +}
> +
> +STATIC
> +EFI_STATUS
> +OpenAndPrepareFile (
> + IN CHAR16 *FilePath,
> + OUT SHELL_FILE_HANDLE *FileHandle,
> + IN BOOLEAN WriteNeeded
> + )
> +{
> + EFI_STATUS Status;
> + UINT64 OpenMode;
> +
> + OpenMode = EFI_FILE_MODE_READ;
> +
> + if (WriteNeeded) {
> + OpenMode |= EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE;
> + }
> +
> + Status = ShellOpenFileByName (FilePath, FileHandle, OpenMode, 0);
> + if (EFI_ERROR (Status)) {
> + ShellPrintHiiEx (-1, -1,
> + NULL, STRING_TOKEN (STR_GPT_ERROR),
> + gShellGptHiiHandle,
> + gAppName,
> + Status,
> + L"Cannot open file"
> + );
> + return Status;
> + }
> +
> + Status = FileHandleSetPosition (*FileHandle, 0);
> +
> + if (EFI_ERROR (Status)) {
> + ShellPrintHiiEx (-1, -1,
> + NULL, STRING_TOKEN (STR_GPT_ERROR),
> + gShellGptHiiHandle,
> + gAppName,
> + Status,
> + "Cannot set file position to the first byte"
> + );
> +
> + ShellCloseFile (FileHandle);
> + return Status;
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +VOID
> +PrintErr (
> + IN CONST CHAR16 *Message,
> + IN EFI_STATUS Status
> + )
> +{
> + ShellPrintHiiEx (-1, -1,
> + NULL, STRING_TOKEN (STR_GPT_ERROR),
> + gShellGptHiiHandle,
> + gAppName,
> + Status,
> + Message
> + );
> +}
> +
> +STATIC
> +BOOLEAN
> +IsPartitionableDevicePath (
> + IN EFI_DEVICE_PATH *DevicePath
> + )
> +{
> + UINTN PathSize;
> + EFI_DEVICE_PATH *PathInstance;
> + BOOLEAN Partitionable;
> +
> + Partitionable = TRUE;
> + while (DevicePath != NULL) {
> + PathInstance = GetNextDevicePathInstance (&DevicePath, &PathSize);
> +
> + while (!IsDevicePathEnd (PathInstance)) {
> + if ((DevicePathType (PathInstance) == MEDIA_DEVICE_PATH)) {
> + Partitionable = FALSE;
> + }
> +
> + PathInstance = NextDevicePathNode (PathInstance);
> + }
> + }
> + return Partitionable;
> +}
> +
> +STATIC
> +EFI_STATUS
> +GptPromptYesNo (
> + IN CONST EFI_STRING_ID HiiFormatStringId
> + )
> +{
> + EFI_STATUS Status;
> + VOID *Response;
> +
> + Status = ShellPromptForResponseHii (ShellPromptResponseTypeYesNo,
> HiiFormatStringId, gShellGptHiiHandle, &Response);
> + if ((EFI_ERROR (Status)) || (*(SHELL_PROMPT_RESPONSE *)Response) !=
> ShellPromptResponseYes) {
> + return EFI_ABORTED;
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +STATIC
> +VOID FormatSize(
> + UINT64 Size, CHAR16 *Buffer)
> +{
> +#define MAX_SIZE_BUF_SIZE 32
> + UINT64 Base, Frac;
> + CHAR16 Metric;
> +
> + Metric = L'B';
> + Frac = 0;
> + if (Size < SIZE_1KB) {
> + Base = Size;
> + } else if (Size < SIZE_1MB) {
> + Base = Size / SIZE_1KB;
> + Frac = ((Size % SIZE_1KB) * 10) >> 10;
> + Metric = L'K';
> + } else if (Size < SIZE_1GB) {
> + Base = Size / SIZE_1MB;
> + Frac = ((Size % SIZE_1MB) * 10) >> 20;
> + Metric = L'M';
> + } else if (Size < SIZE_1TB) {
> + Base = Size / SIZE_1GB;
> + Frac = ((Size % SIZE_1GB) * 10) >> 30;
> + Metric = L'G';
> + } else {
> + Base = Size / SIZE_1TB;
> + Frac = ((Size % SIZE_1TB) * 10) >> 40;
> + Metric = L'T';
> + }
> + if (Frac) {
> + UnicodeSPrint (Buffer, MAX_SIZE_BUF_SIZE, L"%d.%d%c", Base, Frac,
> Metric);
> + } else {
> + UnicodeSPrint (Buffer, MAX_SIZE_BUF_SIZE, L"%d%c", Base, Metric);
> + }
> +}
> +
> +STATIC
> +EFI_STATUS
> +FindAndPrintPartitionableDevices (VOID)
> +{
> + UINTN Index;
> + EFI_HANDLE *HandlePointer;
> + UINTN HandleCount;
> + UINTN DevCount;
> + EFI_STATUS Status;
> + BOOLEAN FirstTime;
> +
> + Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid,
> NULL, &HandleCount, &HandlePointer);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + DevCount = 0;
> + FirstTime = TRUE;
> +
> + for (Index = 0; Index < HandleCount; Index++) {
> + EFI_DEVICE_PATH *DevicePath;
> + CONST CHAR16 *MapPath;
> + CHAR16 *Match;
> + EFI_BLOCK_IO *BlkIo;
> + EFI_DISK_IO *DiskIo;
> + CHAR16 *BufferForSize;
> +
> + Status = gBS->HandleProtocol (HandlePointer[Index],
> &gEfiBlockIoProtocolGuid, (VOID **)&BlkIo);
> + if (EFI_ERROR (Status)) {
> + continue;
> + }
> +
> + DevicePath = DevicePathFromHandle (HandlePointer[Index]);
> + if (!IsPartitionableDevicePath (DevicePath)) {
> + continue;
> + }
> + MapPath = gEfiShellProtocol->GetMapFromDevicePath (&DevicePath);
> + if (MapPath == NULL) {
> + continue;
> + }
> +
> + Status = gBS->HandleProtocol (HandlePointer[Index],
> &gEfiDiskIoProtocolGuid, (VOID **)&DiskIo);
> + if (EFI_ERROR (Status)) {
> + continue;
> + }
> +
> + Match = StrStr (MapPath, L";BLK");
> + if (Match) {
> + MapPath = Match;
> + MapPath++;
> + }
> +
> + if (FirstTime) {
> + BufferForSize = AllocateZeroPool (MAX_SIZE_BUF_SIZE * sizeof
> (CHAR16));
> + ASSERT (BufferForSize);
> + Print (L" Device\t Size Comments\n");
> + Print (L" ------ ------- ------------------------------------------------------------
> \n");
> + FirstTime = FALSE;
> + }
> + GptCleanupGlobals ();
> + FormatSize (MultU64x32 (BlkIo->Media->LastBlock + 1, BlkIo->Media-
> >BlockSize), BufferForSize);
> + ShellPrintHiiEx (-1, -1,
> + NULL, STRING_TOKEN (STR_GPT_LIST_DEVS),
> + gShellGptHiiHandle,
> + MapPath,
> + BufferForSize);
> + if (BlkIo->Media->ReadOnly) {
> + Print (L"Read-Only! ");
> + }
> + if (!BlkIo->Media->MediaPresent) {
> + Print (L"No Media! ");
> + }
> + if (!EFI_ERROR (PartitionGetGptTables (DiskIo, BlkIo))) {
> + Print (L"Valid GPT. ");
> + }
> + if (BlkIo->Media->RemovableMedia) {
> + Print (L"Removable device.");
> + }
> + Print (L"\n");
> + DevCount++;
> + }
> + Print (L"\r\n");
> + if (DevCount) {
> + Print (L"%d potentially partitionable device(s) found\n", DevCount);
> + } else {
> + Print (L"No potentially partitionable device(s) found\n");
> + }
> +
> + GptCleanupGlobals ();
> + return EFI_SUCCESS;
> +}
> +
> +SHELL_STATUS
> +EFIAPI
> +ShellCommandRunGpt (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE *SystemTable
> + )
> +{
> + EFI_STATUS Status;
> + LIST_ENTRY *CheckPackage;
> + EFI_PHYSICAL_ADDRESS Address = 0, Offset = 0;
> + UINT64 PartAttributes = 0;
> + EFI_GUID PartTypeGuid = { 0 };
> + SHELL_FILE_HANDLE FileHandle = NULL;
> + UINT64 ByteCount, FileSize;
> + UINTN I;
> + UINT8 *Buffer = NULL, *FileBuffer = NULL;
> +
> + CHAR16 * ProblemParam,*FilePath;
> + CONST CHAR16 *AddressStr = NULL, *OffsetStr = NULL;
> + CONST CHAR16 *PartName = NULL, *NewPartName = NULL,
> *AttrStr = NULL,
> + *GuidStr = NULL, *VolumeName = NULL;
> + CONST CHAR16 *LengthStr = NULL, *FileStr = NULL;
> + BOOLEAN AddrFlag = FALSE, LengthFlag = TRUE, FileFlag = FALSE,
> GuidFlag = FALSE, OffsetFlag = TRUE;
> + BOOLEAN PartNameFlag = TRUE, NewPartNameFlag = FALSE,
> AttrFlag = FALSE;
> + UINTN Flag = 0, CheckFlag = 0;
> + CONST CHAR16 *BlockName;
> + EFI_DEVICE_PATH_PROTOCOL *DevPath;
> + EFI_BLOCK_IO_PROTOCOL *BlockIo;
> + EFI_DISK_IO_PROTOCOL *DiskIo;
> + EFI_HANDLE BlockIoHandle;
> + MOD_PARAMS ModParams;
> + EFI_PARTITION_ENTRY *Entry;
> + UINTN NumKnownPartTypesEntries;
> + BOOLEAN TableNotEmpty, NoPrompt = FALSE, Quiet = TRUE;
> + UINT64 TimeStampB, TimeStampE, SpeedKB, Freq;
> +
> + // Parse Shell command line
> + Status = ShellInitialize ();
> + if (EFI_ERROR (Status)) {
> + PrintErr (L"Cannot initialize Shell", Status);
> + ASSERT_EFI_ERROR (Status);
> + return SHELL_ABORTED;
> + }
> +
> + Status = ShellCommandLineParse (ParamList, &CheckPackage,
> &ProblemParam, TRUE);
> + if (EFI_ERROR (Status)) {
> + PrintErr (L"Error while parsing command line", Status);
> + return SHELL_ABORTED;
> + }
> +
> + TimeStampB = 0;
> + TimeStampE = 0;
> +
> + NoPrompt = ShellCommandLineGetFlag (CheckPackage, L"-yes");
> + Quiet = !ShellCommandLineGetFlag (CheckPackage, L"-verbose");
> +
> + Freq = GetPerformanceCounterProperties (NULL, NULL);
> +
> + // Check flags provided by user
> + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"clear") << 0);
> + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"create") << 1);
> + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"list") << 2);
> + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"sync") << 3);
> + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"typesinfo") << 4);
> + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"delete") << 5);
> + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"info") << 6);
> + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"read") << 7);
> + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"readfile") << 8);
> + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"rename") << 9);
> + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"setattr") << 10);
> + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"settype") << 11);
> + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"write") << 12);
> + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"writefile") << 13);
> + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"fatformat") << 14);
> +
> + PartitionGetKnownType ((UINTN)(-1), &NumKnownPartTypesEntries);
> +
> + if (Flag & TYPES_INFO) {
> + UINTN Index;
> +
> + Print (L" No\t%-36s\tGUID\r\n", L"Type name");
> + Print (L" ---- ---------------------------------- ------------------------------------
> \n");
> + for (Index = 0; Index < NumKnownPartTypesEntries; Index++) {
> + EFI_KNOWN_PARTITION_TYPE *PartType;
> +
> + PartType = PartitionGetKnownType (Index, NULL);
> + if (PartType == NULL) {
> + break;
> + }
> + Print (L" %3d\t%-36s\t%g\n", Index, PartType->TypeName, &PartType-
> >TypeGuid);
> + }
> + if (Flag == TYPES_INFO) {
> + return SHELL_SUCCESS;
> + }
> + }
> + // Start parsing the command.
> + // Generally command is:
> + // block_name:bootpart_no addr or filename offset
> +
> + BlockName = ShellCommandLineGetRawValue (CheckPackage, 1);
> + if (BlockName == NULL) {
> + if (Flag & LIST) {
> + Status = FindAndPrintPartitionableDevices ();
> + if (EFI_ERROR (Status)) {
> + PrintErr (L"Error getting list of partitionable devices", Status);
> + Status = SHELL_ABORTED;
> + }
> + return Status;
> + }
> + PrintErr (L"Missing block device name", EFI_INVALID_PARAMETER);
> + return SHELL_INVALID_PARAMETER;
> + }
> +
> + // Find device handle by mapped name
> + if (gEfiShellProtocol->GetDevicePathFromMap (BlockName) == NULL) {
> + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
> gShellGptHiiHandle, gAppName, BlockName);
> + Status = SHELL_INVALID_PARAMETER;
> + } else {
> + DevPath = (EFI_DEVICE_PATH_PROTOCOL *)gEfiShellProtocol-
> >GetDevicePathFromMap (BlockName);
> + if (gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &DevPath, NULL)
> == EFI_NOT_FOUND) {
> + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN
> (STR_GEN_MAP_PROTOCOL), gShellGptHiiHandle, gAppName, BlockName,
> L"BlockIo");
> + Status = SHELL_INVALID_PARAMETER;
> + }
> + }
> +
> + if (Status) {
> + return SHELL_INVALID_PARAMETER;
> + }
> +
> + BlockIoHandle = 0;
> +
> + Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid,
> (EFI_DEVICE_PATH_PROTOCOL **)&DevPath, &BlockIoHandle);
> + if (EFI_ERROR (Status)) {
> + goto CleanUp;
> + }
> +
> + Status = gBS->OpenProtocol (BlockIoHandle, &gEfiBlockIoProtocolGuid,
> (VOID **)&BlockIo, gImageHandle, NULL,
> EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> + if (EFI_ERROR (Status)) {
> + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN
> (STR_GEN_MAP_PROTOCOL), gShellGptHiiHandle, gAppName, BlockName,
> L"BlockIo");
> + goto CleanUp;
> + }
> +
> + Status = gBS->HandleProtocol (
> + BlockIoHandle,
> + &gEfiDiskIoProtocolGuid,
> + (VOID **)&DiskIo
> + );
> + if (EFI_ERROR (Status)) {
> + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN
> (STR_GEN_MAP_PROTOCOL), gShellGptHiiHandle, gAppName, BlockName,
> L"DiskIo");
> + goto CleanUp;
> + }
> +
> + CheckFlag = Flag;
> + for (I = 0; CheckFlag; CheckFlag >>= 1) {
> + I += CheckFlag & 1;
> + if (I > 1) {
> + PrintErr (L"Too many flags", EFI_INVALID_PARAMETER);
> + Status = SHELL_INVALID_PARAMETER;
> + goto CleanUp;
> + }
> + }
> +
> + if (Flag & SYNC) {
> + // Let the Partition table driver know that
> + // we want to reread the tables
> + Status = gBS->ReinstallProtocolInterface (
> + BlockIoHandle,
> + &gEfiBlockIoProtocolGuid,
> + BlockIo,
> + BlockIo
> + );
> + Status = SHELL_SUCCESS;
> + goto CleanUp;
> + }
> +
> + if (!IsPartitionableDevicePath (DevicePathFromHandle (BlockIoHandle))) {
> + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
> gShellGptHiiHandle, gAppName, BlockName);
> + Print (L"%s is not a raw block device\n", BlockName);
> + Status = SHELL_INVALID_PARAMETER;
> + goto CleanUp;
> + }
> +
> + if (!BlockIo->Media->MediaPresent) {
> + PrintErr (L"Media is not present!\n", EFI_NO_MEDIA);
> + Status = EFI_NO_MEDIA;
> + goto CleanUp;
> + }
> +
> + // Preload GPT tables with validation
> + Status = PartitionGetGptTables (DiskIo, BlockIo);
> + if (EFI_ERROR (Status)) {
> + BOOLEAN CanContinue;
> +
> + CanContinue = (Flag & CREATE) || (Flag & CLEAR) || (Flag &
> FAT_FORMAT);
> + if (Status != EFI_NOT_FOUND) {
> + PrintErr (L"Unexpected error getting GPT tables", Status);
> + goto CleanUp;
> + } else {
> + if (!CanContinue) {
> + PrintErr (L"No GPT table found. Create first", Status);
> + goto CleanUp;
> + }
> + }
> + }
> +
> + // Do we have any partitions already?
> + TableNotEmpty = (PartitionFindPartitionByCriteria (NULL, 0, 0, SRC_ANY) !=
> NULL);
> +
> + Status = SHELL_INVALID_PARAMETER;
> +
> + if ((Flag < LIST) ||
> + (Flag & DELETE) ||
> + (Flag > READ_FILE)
> + ) {
> + if (BlockIo->Media->ReadOnly) {
> + Status = EFI_INVALID_PARAMETER;
> + PrintErr (L"Cannot write to a read-only device", Status);
> + goto CleanUp;
> + }
> + }
> +
> + if (BlockIo->Media->RemovableMedia) {
> + Print (L"%s is a removable device. Just a note\n", BlockName);
> + }
> +
> + switch (Flag) {
> + case INFO:
> + PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
> + OffsetFlag = FALSE;
> + LengthFlag = FALSE;
> + break;
> + case LIST:
> + {
> + UINTN NumEntries;
> +
> + NumEntries = PartitionListGptEntries ();
> + if (NumEntries == 0) {
> + Print (L"gpt: GPT is valid on %s, but no partition(s) defined yet. Use
> create\n", BlockName);
> + }
> + Status = SHELL_SUCCESS;
> + goto CleanUp;
> + break;
> + }
> + case CLEAR:
> + if (TableNotEmpty) {
> + // Tell the user what he/she is doing...
> + ShellPrintHiiEx (-1, -1,
> + NULL, STRING_TOKEN (STR_GPT_NOT_EMPTY),
> + gShellGptHiiHandle,
> + BlockName
> + );
> + }
> +
> + // Even if GPT tables do not exist, there might be something.
> + // Warn the user and double sure it is the intention,
> + // to prevent a user from bricking a device (JTAG would be needed to
> recover)
> + // by overwriting an ATF boot device. However with NoPrompt on, the
> user is
> + // responsible for operation because there is no confirmation (assuming
> yes on all queries).
> + if ((NoPrompt) || (!GptPromptYesNo (STRING_TOKEN
> (STR_GPT_CLEAR_SURE)) &&
> + (!GptPromptYesNo (STRING_TOKEN
> (STR_GPT_ABSOLUTELY_SURE))))
> + ) {
> + PartitionGptClearAll ();
> + }
> + Status = SHELL_SUCCESS;
> + goto CleanUp;
> + break;
> + case CREATE:
> + PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
> + OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 3);
> + LengthStr = ShellCommandLineGetRawValue (CheckPackage, 4);
> + AttrStr = ShellCommandLineGetRawValue (CheckPackage, 5);
> + GuidStr = ShellCommandLineGetValue (CheckPackage, L"-type");
> + GuidFlag = TRUE;
> + break;
> + case DELETE:
> + PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
> + LengthFlag = FALSE;
> + OffsetFlag = FALSE;
> + break;
> + case RENAME:
> + PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
> + NewPartName = ShellCommandLineGetRawValue (CheckPackage, 3);
> + NewPartNameFlag = TRUE;
> + LengthFlag = FALSE;
> + OffsetFlag = FALSE;
> + break;
> + case SETATTR:
> + PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
> + AttrStr = ShellCommandLineGetRawValue (CheckPackage, 3);
> + AttrFlag = TRUE;
> + LengthFlag = FALSE;
> + OffsetFlag = FALSE;
> + break;
> + case SETTYPE:
> + PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
> + GuidStr = ShellCommandLineGetValue (CheckPackage, L"-type");
> + GuidFlag = TRUE;
> + LengthFlag = FALSE;
> + OffsetFlag = FALSE;
> + break;
> + case FAT_FORMAT:
> + PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
> + VolumeName = ShellCommandLineGetRawValue (CheckPackage, 3);
> + LengthFlag = FALSE;
> + OffsetFlag = FALSE;
> + PartNameFlag = (PartName != NULL);
> + if (!PartNameFlag && TableNotEmpty) {
> + // Tell the user what he/she is doing...
> + ShellPrintHiiEx (-1, -1,
> + NULL, STRING_TOKEN (STR_GPT_NOT_EMPTY),
> + gShellGptHiiHandle,
> + BlockName
> + );
> + }
> + break;
> + // Fall through
> + case READ:
> + case WRITE:
> + AddressStr = ShellCommandLineGetRawValue (CheckPackage, 2);
> + PartName = ShellCommandLineGetRawValue (CheckPackage, 3);
> + OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 4);
> + LengthStr = ShellCommandLineGetRawValue (CheckPackage, 5);
> + AddrFlag = TRUE;
> + break;
> + case READ_FILE:
> + FileStr = ShellCommandLineGetRawValue (CheckPackage, 2);
> + PartName = ShellCommandLineGetRawValue (CheckPackage, 3);
> + OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 4);
> + LengthStr = ShellCommandLineGetRawValue (CheckPackage, 5);
> + FileFlag = TRUE;
> + break;
> + case WRITE_FILE:
> + FileStr = ShellCommandLineGetRawValue (CheckPackage, 2);
> + PartName = ShellCommandLineGetRawValue (CheckPackage, 3);
> + OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 4);
> + LengthFlag = FALSE;
> + FileFlag = TRUE;
> + break;
> + default:
> + Print (L"%s: Unsupported command. Try \"help %s\"", gAppName);
> + Status = SHELL_INVALID_PARAMETER;
> + goto CleanUp;
> + }
> +
> + // Read address parameter
> + if ((AddressStr == NULL) & AddrFlag) {
> + PrintErr (L"No address parameter", EFI_INVALID_PARAMETER);
> + goto CleanUp;
> + } else if (AddrFlag) {
> + Address = ShellHexStrToUintn (AddressStr);
> + if (Address == (UINTN)(-1)) {
> + PrintErr (L"Wrong address parameter", EFI_INVALID_PARAMETER);
> + goto CleanUp;
> + }
> + }
> +
> + if ((PartName == NULL) & PartNameFlag) {
> + PrintErr (L"Missing partition name", EFI_INVALID_PARAMETER);
> + goto CleanUp;
> + } else if (PartNameFlag) {
> + if (StrSize (PartName) > MAX_PARTITION_NAME_LENGTH) {
> + PrintErr (L"Partition name is too long (max 36 chars)",
> EFI_INVALID_PARAMETER);
> + goto CleanUp;
> + }
> + }
> +
> + // Read offset parameter
> + if ((OffsetStr == NULL) & OffsetFlag) {
> + PrintErr (L"No offset Parameter", EFI_INVALID_PARAMETER);
> + goto CleanUp;
> + } else if (OffsetFlag) {
> + Offset = ShellHexStrToUintn (OffsetStr);
> + if (Offset < 0) {
> + Print (L"%s: Wrong offset parameter: %s\n", gAppName, OffsetStr);
> + goto CleanUp;
> + }
> + }
> +
> + // Read length parameter
> + if ((LengthStr == NULL) & LengthFlag) {
> + PrintErr (L"No length parameter", EFI_INVALID_PARAMETER);
> + goto CleanUp;
> + } else if (LengthFlag) {
> + ByteCount = (UINT64)ShellStrToUintn (LengthStr);
> + if (ByteCount < 0) {
> + Print (L"%s: Wrong length parameter %s!\n", gAppName, LengthStr);
> + goto CleanUp;
> + }
> + }
> +
> + if ((NewPartName == NULL) & NewPartNameFlag) {
> + PrintErr (L"Missing name to be assigned to partition",
> EFI_INVALID_PARAMETER);
> + goto CleanUp;
> + } else if (NewPartNameFlag) {
> + if (StrSize (NewPartName) > MAX_PARTITION_NAME_LENGTH) {
> + PrintErr (L"Partition name is too long (max 36 chars)",
> EFI_INVALID_PARAMETER);
> + goto CleanUp;
> + }
> + }
> +
> + if ((AttrStr == NULL) & AttrFlag) {
> + PrintErr (L"Missing attributes parameter", EFI_INVALID_PARAMETER);
> + goto CleanUp;
> + } else if (AttrStr) {
> + PartAttributes = (UINT64)ShellStrToUintn (AttrStr);
> + }
> +
> + if ((GuidStr == NULL) & GuidFlag) {
> + PrintErr (L"Missing partition type GUID parameter",
> EFI_INVALID_PARAMETER);
> + goto CleanUp;
> + } else if (GuidFlag) {
> + Status = SHELL_INVALID_PARAMETER;
> + if (InternalShellIsHexOrDecimalNumber (GuidStr, FALSE, TRUE, FALSE)) {
> + UINTN Ordinal;
> +
> + Ordinal = ShellStrToUintn (GuidStr);
> + if (Ordinal < NumKnownPartTypesEntries) {
> + PartTypeGuid = PartitionGetKnownType (Ordinal, NULL)->TypeGuid;
> + Status = SHELL_SUCCESS;
> + } else {
> + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
> gShellGptHiiHandle, gAppName, GuidStr);
> + goto CleanUp;
> + }
> + } else {
> + Status = ConvertStringToGuid (GuidStr, &PartTypeGuid);
> + if ((EFI_ERROR (Status)) || (IsZeroGuid (&PartTypeGuid))) {
> + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
> gShellGptHiiHandle, gAppName, GuidStr);
> + Status = SHELL_INVALID_PARAMETER;
> + goto CleanUp;
> + }
> + }
> + }
> +
> + if (FileFlag) {
> + // Read FilePath parameter
> + if (FileStr == NULL) {
> + PrintErr (L"No FilePath parameter", EFI_INVALID_PARAMETER);
> + goto CleanUp;
> + } else {
> + FilePath = (CHAR16 *)FileStr;
> + Status = ShellIsFile (FilePath);
> + // When read file into flash, file doesn't have to exist
> + if (EFI_ERROR (Status && !(Flag & READ_FILE))) {
> + PrintErr (L"Wrong FilePath parameter", Status);
> + Status = SHELL_INVALID_PARAMETER;
> + goto CleanUp;
> + }
> + }
> +
> + Status = OpenAndPrepareFile (FilePath, &FileHandle, ((Flag &
> READ_FILE) != 0));
> + if (EFI_ERROR (Status)) {
> + Print (L"Error %r while preparing file %s", Status, FilePath);
> + Status = SHELL_ABORTED;
> + goto CleanUp;
> + }
> +
> + // Get file size in order to check correctness at the end of transfer
> + if (Flag & (WRITE_FILE)) {
> + Status = FileHandleGetSize (FileHandle, &FileSize);
> + if (EFI_ERROR (Status)) {
> + PrintErr (L"Cannot get file size", Status);
> + Status = SHELL_ABORTED;
> + goto CleanUp;
> + }
> + ByteCount = (UINT64)FileSize;
> + }
> +
> + FileBuffer = AllocateZeroPool ((UINTN)ByteCount);
> + if (FileBuffer == NULL) {
> + PrintErr (L"Cannot allocate memory", EFI_OUT_OF_RESOURCES);
> + Status = SHELL_OUT_OF_RESOURCES;
> + goto Error_Close_File;
> + }
> +
> + // Read file content and store it in FileBuffer
> + if (Flag & (WRITE_FILE)) {
> + if (!Quiet) {
> + Print (L"Reading %s...\r", FilePath);
> + }
> + Status = FileHandleRead (FileHandle, &ByteCount, FileBuffer);
> + if (EFI_ERROR (Status)) {
> + PrintErr (L"Read from file error", Status);
> + Status = SHELL_ABORTED;
> + goto Error_Free_Buffer;
> + } else if (ByteCount != (UINTN)FileSize) {
> + PrintErr (L"Not whole file read. Abort", EFI_DEVICE_ERROR);
> + Status = SHELL_DEVICE_ERROR;
> + goto Error_Free_Buffer;
> + }
> + if (!Quiet) {
> + Print (L"Writing %s into device %s, partition %s...\n", FilePath,
> BlockName, PartName);
> + }
> + }
> + }
> +
> + Buffer = (UINT8 *)Address;
> + if (FileFlag) {
> + Buffer = FileBuffer;
> + }
> +
> + if (Flag > TYPES_INFO) {
> + Entry = PartitionFindPartitionByCriteria (PartName, 0, 0, SRC_BY_NAME);
> + if (!Entry && PartName && (InternalShellIsHexOrDecimalNumber
> (PartName, FALSE, TRUE, FALSE))) {
> + Entry = PartitionFindPartitionByCriteria (PartName, 0, 0, SRC_BY_NUM);
> + }
> + if ((!Entry) && (PartNameFlag)) {
> + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
> gShellGptHiiHandle, gAppName, PartName);
> + Print (L"Could not find partition %s (case-sensitive). Make sure the name
> is spelled properly\n", PartName);
> + Status = SHELL_NOT_FOUND;
> + goto CleanUp;
> + }
> + }
> +
> + switch (Flag) {
> + case CREATE:
> + PartitionGptCreatePartition (
> + PartName,
> + Offset, // Lba. If 0, the next available is assumed
> + ByteCount, // in MegaBytes. If 0 the whole remaining space is assumed
> + PartAttributes,
> + PartTypeGuid);
> + break;
> + case DELETE:
> + ModParams.PartName = PartName;
> + ShellPrintHiiEx (-1, -1,
> + NULL, STRING_TOKEN (STR_GPT_DELETE_WARNING),
> + gShellGptHiiHandle,
> + Entry->PartitionName
> + );
> + if ((NoPrompt) || (!GptPromptYesNo (STRING_TOKEN
> (STR_GPT_ABSOLUTELY_SURE)))) {
> + Status = PartitionGptModifyPartition (
> + Entry, &ModParams, MOD_DELETE);
> + if (EFI_ERROR (Status)) {
> + PrintErr (L"Error deleting the partition", Status);
> + Status = SHELL_ABORTED;
> + goto CleanUp;
> + }
> + Status = SHELL_SUCCESS;
> + } else {
> + Status = SHELL_ABORTED;
> + }
> + break;
> + case FAT_FORMAT:
> + {
> + EFI_LBA StartingLBA, EndingLBA;
> + CHAR8 LabelName[12];
> +
> + if (VolumeName) {
> + if (StrLen (VolumeName) > 11) {
> + Status = EFI_INVALID_PARAMETER;
> + PrintErr (L"The volume label is too long", Status);
> + Status = SHELL_INVALID_PARAMETER;
> + goto CleanUp;
> + }
> + UnicodeStrToAsciiStr (VolumeName, (CHAR8 *)LabelName);
> + }
> + ShellPrintHiiEx (-1, -1,
> + NULL, STRING_TOKEN (STR_GPT_FORMAT_WARNING),
> + gShellGptHiiHandle,
> + Entry ? Entry->PartitionName : BlockName
> + );
> +
> + if ((NoPrompt) || (!GptPromptYesNo (STRING_TOKEN
> (STR_GPT_FORMAT_SURE)) &&
> + (!GptPromptYesNo (STRING_TOKEN
> (STR_GPT_ABSOLUTELY_SURE))))
> + ) {
> + StartingLBA = 0;
> + EndingLBA = BlockIo->Media->LastBlock;
> + if (Entry) {
> + StartingLBA = Entry->StartingLBA;
> + EndingLBA = Entry->EndingLBA;
> + }
> + if (!Quiet) {
> + Print (L"Formatting %s to FAT32...\r", PartNameFlag ? Entry-
> >PartitionName : BlockName);
> + }
> + Status = FatFormat (StartingLBA, EndingLBA, BlockIo, DiskIo,
> VolumeName ? LabelName : NULL, TRUE);
> + if (EFI_ERROR (Status)) {
> + PrintErr (L"Error formatting the partition to FAT ", Status);
> + Status = SHELL_ABORTED;
> + goto CleanUp;
> + } else if (!Quiet) {
> + Print (L"%s successfully formatted to FAT. Formatted size %llu MiB\n",
> + PartNameFlag ? Entry->PartitionName : BlockName,
> + MultU64x32 (EndingLBA - StartingLBA + 1, BlockIo->Media-
> >BlockSize) >> 20
> + );
> + }
> + } else {
> + Status = SHELL_ABORTED;
> + }
> + }
> + break;
> + case RENAME:
> + ModParams.PartName = PartName;
> + ModParams.NewName = NewPartName;
> + Status = PartitionGptModifyPartition (
> + Entry, &ModParams, MOD_RENAME);
> + break;
> + case SETATTR:
> + ModParams.Attributes = PartAttributes;
> + Status = PartitionGptModifyPartition (
> + Entry, &ModParams, MOD_ATTR);
> + break;
> + case SETTYPE:
> + ModParams.PartTypeGuid = PartTypeGuid;
> + Status = PartitionGptModifyPartition (
> + Entry, &ModParams, MOD_TYPE);
> + break;
> + case INFO:
> + PartitionPrintGptPartInfo (Entry);
> + Status = SHELL_SUCCESS;
> + break;
> + case READ:
> + case READ_FILE:
> + case WRITE:
> + case WRITE_FILE:
> + {
> + UINT64 MaxBytes;
> + BOOLEAN OpRead;
> +
> + OpRead = ((Flag & READ) || (Flag & READ_FILE));
> + MaxBytes = MultU64x32 (
> + Entry->EndingLBA - Entry->StartingLBA,
> + BlockIo->Media->BlockSize) +
> + BlockIo->Media->BlockSize -
> + MultU64x32 (Offset, BlockIo->Media->BlockSize);
> + if (ByteCount > MaxBytes) {
> + Status = EFI_INVALID_PARAMETER;
> + ShellPrintHiiEx (-1, -1,
> + NULL, (OpRead) ?
> + STRING_TOKEN (STR_GPT_READ_BOUNDARY) :
> + STRING_TOKEN (STR_GPT_WRITE_BOUNDARY),
> + gShellGptHiiHandle,
> + gAppName,
> + Entry->PartitionName,
> + MaxBytes,
> + ByteCount
> + );
> + Status = SHELL_INVALID_PARAMETER;
> + goto CleanUp;
> + }
> +
> + TimeStampB = GetPerformanceCounter ();
> + if (OpRead) {
> + Status = DiskIo->ReadDisk (DiskIo,
> + BlockIo->Media->MediaId,
> + MultU64x32 (Offset + Entry->StartingLBA, BlockIo-
> >Media->BlockSize), ByteCount, Buffer);
> + } else {
> + Status = DiskIo->WriteDisk (DiskIo, BlockIo->Media->MediaId,
> + MultU64x32 (Offset + Entry->StartingLBA, BlockIo-
> >Media->BlockSize), ByteCount, Buffer);
> + }
> + }
> + break;
> + default:
> + Status = SHELL_INVALID_PARAMETER;
> + PrintErr (L"Unknown command. Try \"help gpt\"",
> EFI_INVALID_PARAMETER);
> + goto CleanUp;
> + }
> +
> + if (EFI_ERROR (Status)) {
> + PrintErr (L"Error while performing transfer\n", Status);
> + Status = SHELL_ABORTED;
> + goto CleanUp;
> + }
> +
> + TimeStampE = ((GetPerformanceCounter () - TimeStampB) * 1000) / Freq;
> + SpeedKB = TimeStampE ? (ByteCount / (TimeStampE / 1000)) >> 10 : 0;
> +
> + switch (Flag) {
> + case WRITE:
> + case WRITE_FILE:
> + if (!Quiet) {
> + ShellPrintHiiEx (-1, -1,
> + NULL,
> + STRING_TOKEN (STR_GPT_WRITE_OK),
> + gShellGptHiiHandle,
> + ByteCount,
> + Offset,
> + Entry->PartitionName,
> + TimeStampE,
> + SpeedKB
> + );
> + }
> + break;
> + case READ:
> + if (!Quiet) {
> + ShellPrintHiiEx (-1, -1,
> + NULL,
> + STRING_TOKEN (STR_GPT_READ_OK),
> + gShellGptHiiHandle,
> + ByteCount,
> + Offset,
> + Entry->PartitionName,
> + TimeStampE,
> + SpeedKB
> + );
> + }
> + break;
> + case READ_FILE:
> + Status = FileHandleWrite (FileHandle, &ByteCount, FileBuffer);
> + if (EFI_ERROR (Status)) {
> + ShellPrintHiiEx (-1, -1,
> + NULL,
> + STRING_TOKEN (STR_GPT_FILE_WRITE_FAIL),
> + gShellGptHiiHandle,
> + gAppName,
> + FilePath,
> + Status
> + );
> + Status = SHELL_DEVICE_ERROR;
> + goto Error_Free_Buffer;
> + }
> +
> + if (!Quiet) {
> + ShellPrintHiiEx (-1, -1,
> + NULL,
> + STRING_TOKEN (STR_GPT_READFILE_OK),
> + gShellGptHiiHandle,
> + ByteCount,
> + Offset,
> + Entry->PartitionName,
> + FilePath,
> + TimeStampE,
> + SpeedKB
> + );
> + }
> + break;
> + }
> +
> + if (FileFlag) {
> + SHELL_FREE_NON_NULL (FileBuffer);
> + if (FileHandle != NULL) {
> + ShellCloseFile (&FileHandle);
> + FileHandle = NULL;
> + }
> + }
> +
> + Status = SHELL_SUCCESS;
> +
> + Error_Free_Buffer:
> + SHELL_FREE_NON_NULL (FileBuffer);
> + Error_Close_File:
> + if (FileHandle) {
> + ShellCloseFile (&FileHandle);
> + }
> + CleanUp:
> + if (BlockIoHandle) {
> + // By UEFI Spec blocks must be flushed
> + BlockIo->FlushBlocks (BlockIo);
> + gBS->CloseProtocol (BlockIoHandle, &gEfiBlockIoProtocolGuid,
> gImageHandle, NULL);
> + }
> +
> + GptCleanupGlobals ();
> +
> + ShellCommandLineFreeVarList (CheckPackage);
> +
> + if (EFI_ERROR (Status)) {
> + Status = SHELL_ABORTED;
> + }
> +
> + return Status;
> +}
> +
> +EFI_STATUS
> +EFIAPI
> +ShellGptLibConstructor (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE *SystemTable
> + )
> +{
> + gShellGptHiiHandle = NULL;
> +
> + gShellGptHiiHandle = HiiAddPackages (
> + &gShellGptHiiGuid, gImageHandle,
> + UefiShellGptCommandLibStrings, NULL
> + );
> + if (gShellGptHiiHandle == NULL) {
> + return EFI_DEVICE_ERROR;
> + }
> +
> + ShellCommandRegisterCommandName (
> + gAppName, ShellCommandRunGpt, ShellCommandGetManFileNameGpt,
> 0,
> + gAppName, TRUE, gShellGptHiiHandle, STRING_TOKEN
> (STR_GET_HELP_GPT)
> + );
> +
> + return EFI_SUCCESS;
> +}
> +
> +EFI_STATUS
> +EFIAPI
> +ShellGptLibDestructor (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE *SystemTable
> + )
> +{
> +
> + if (gShellGptHiiHandle != NULL) {
> + HiiRemovePackages (gShellGptHiiHandle);
> + }
> + return EFI_SUCCESS;
> +}
> diff --git
> a/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> new file mode 100644
> index 000000000000..1be4b1ab0f11
> --- /dev/null
> +++
> b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> @@ -0,0 +1,79 @@
> +#
> +# Marvell BSD License Option
> +#
> +# If you received this File from Marvell, you may opt to use, redistribute
> +# and/or modify this File under the following licensing terms.
> +# Redistribution and use in source and binary forms, with or without
> +# modification, are permitted provided that the following conditions are
> met:
> +#
> +# * Redistributions of source code must retain the above copyright notice,
> +# this list of conditions and the following disclaimer.
> +#
> +# * Redistributions in binary form must reproduce the above copyright
> +# notice, this list of conditions and the following disclaimer in the
> +# documentation and/or other materials provided with the distribution.
> +#
> +# * Neither the name of Marvell nor the names of its contributors may be
> +# used to endorse or promote products derived from this software without
> +# specific prior written permission.
> +#
> +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> CONTRIBUTORS "AS IS"
> +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> LIMITED TO, THE
> +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
> PARTICULAR PURPOSE ARE
> +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> CONTRIBUTORS BE LIABLE
> +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> CONSEQUENTIAL
> +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
> SUBSTITUTE GOODS OR
> +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
> HOWEVER
> +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
> STRICT LIABILITY,
> +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
> OUT OF THE USE
> +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> DAMAGE.
> +#
> +
> +#
> +# Portions Copyright (C) 2016 Broadcom
> +#
> +
> +[Defines]
> + INF_VERSION = 0x00010006
> + BASE_NAME = UefiShellGptCommandLib
> + FILE_GUID = F62ACF25-0D15-22F5-E642-FFB6515E00D7
> + MODULE_TYPE = UEFI_APPLICATION
> + VERSION_STRING = 0.1
> + LIBRARY_CLASS = NULL|UEFI_APPLICATION UEFI_DRIVER
> + CONSTRUCTOR = ShellGptLibConstructor
> + DESTRUCTOR = ShellGptLibDestructor
> +
> +[Sources]
> + FatFormat.c
> + GptWorker.c
> + UefiShellGptCommandLib.c
> + UefiShellGptCommandLib.uni
> +
> +[Packages]
> + MdeModulePkg/MdeModulePkg.dec
> + MdePkg/MdePkg.dec
> + ShellPkg/ShellPkg.dec
> +
> +[LibraryClasses]
> + BaseLib
> + BaseMemoryLib
> + DebugLib
> + DevicePathLib
> + FileHandleLib
> + HiiLib
> + MemoryAllocationLib
> + PcdLib
> + ShellCommandLib
> + ShellLib
> + UefiBootServicesTableLib
> + UefiRuntimeServicesTableLib
> + UefiLib
> +
> +[Protocols]
> + gEfiBlockIoProtocolGuid
> + gEfiDevicePathProtocolGuid
> + gEfiDiskIoProtocolGuid
> +
> +[Guids]
> + gShellGptHiiGuid
> + gEfiPartTypeUnusedGuid ## SOMETIMES_CONSUMES ## GUID
> diff --git
> a/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
> b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
> new file mode 100644
> index 000000000000..55bcb42cfeb3
> --- /dev/null
> +++
> b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
> @@ -0,0 +1,117 @@
> +/*********************************************************
> **********************
> +Copyright (C) 2016 Marvell International Ltd.
> +
> +Marvell BSD License Option
> +
> +If you received this File from Marvell, you may opt to use, redistribute
> and/or
> +modify this File under the following licensing terms.
> +Redistribution and use in source and binary forms, with or without
> modification,
> +are permitted provided that the following conditions are met:
> +
> + * Redistributions of source code must retain the above copyright notice,
> + this list of conditions and the following disclaimer.
> +
> + * Redistributions in binary form must reproduce the above copyright
> + notice, this list of conditions and the following disclaimer in the
> + documentation and/or other materials provided with the distribution.
> +
> + * Neither the name of Marvell nor the names of its contributors may be
> + used to endorse or promote products derived from this software
> without
> + specific prior written permission.
> +
> +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> CONTRIBUTORS "AS IS" AND
> +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
> THE IMPLIED
> +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> PURPOSE ARE
> +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> CONTRIBUTORS BE LIABLE FOR
> +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> CONSEQUENTIAL DAMAGES
> +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
> OR SERVICES;
> +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
> CAUSED AND ON
> +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> TORT
> +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
> THE USE OF THIS
> +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +
> +*********************************************************
> **********************/
> +
> +/* Portions Copyright (C) 2016 Broadcom */
> +/=#
> +
> +#langdef en-US "english"
> +
> +#string STR_GEN_PARAM_INV #language en-US "%H%s%N: Invalid
> argument - '%H%s%N'\r\n"
> +#string STR_GEN_MAP_PROTOCOL #language en-US "%H%s%N:
> Mapped device '%B%s%N' does not have protocol %B%s%N\r\n"
> +
> +#string STR_GPT_ERROR #language en-US "%H%s%N: %r - %s\r\n"
> +#string STR_GPT_NOT_EMPTY #language en-US "%H%s%N: WARNING!!!
> This device has valid GPT partition tables!\r\n"
> +#string STR_GPT_CLEAR_SURE #language en-US "Are you sure you want
> to clear the GPT tables on this device? %BY%Nes, %BN%No "
> +#string STR_GPT_ABSOLUTELY_SURE #language en-US "\r\nAre you ***
> ABSOLUTELY SURE *** you want to perform this
> operation ? %BY%Nes, %BN%No "
> +#string STR_GPT_FORMAT_WARNING #language en-US "%H%s%N:
> WARNING!!! Formatting of this partition will destroy all data on it!\r\n"
> +#string STR_GPT_FORMAT_SURE #language en-US "Are you sure you
> want to format this partition to FAT32 and destroy all data on
> it ? %BY%Nes, %BN%No "
> +#string STR_GPT_DELETE_WARNING #language en-US "%H%s%N: Deleting
> of this partition will make data on it unreachable!\r\n"
> +#string STR_GPT_READ_BOUNDARY #language en-US "%H%s%N: Attempt
> to read beyond %H%s%N partition boundary (can read upto %llu bytes from
> the given offset, requested %llu bytes)\r\n"
> +#string STR_GPT_WRITE_BOUNDARY #language en-US "%H%s%N:
> Attempt to write beyond %H%s%N partition boundary (can write upto %llu
> bytes from the given offset, requested %llu bytes)\r\n"
> +#string STR_GPT_FILE_WRITE_FAIL #language en-US "%H%s%N: Failed to
> write to the file %s, error %r\r\n"
> +
> +#string STR_GPT_WRITE_OK #language en-US "Written %llu bytes at
> offset 0x%x, partition %s. Elapsed time %llums (%llu KB/s)\r\n"
> +#string STR_GPT_READ_OK #language en-US "Read %llu bytes from
> offset 0x%x, partition %s. Elapsed time %llums (%llu KB/s)\r\n"
> +#string STR_GPT_READFILE_OK #language en-US "Read %llu bytes from
> offset 0x%x, partition %s into file %s. Elapsed time %llums (%llu KB/s)\r\n"
> +#string STR_GPT_LIST_DEVS #language en-US " %H%+6s%N %+8s "
> +
> +#string STR_GET_HELP_GPT #language en-US ""
> +".TH gpt 0 "GPT partition manager."\r\n"
> +".SH NAME\r\n"
> +"Manages GPT partitions on a block device.\r\n"
> +".SH SYNOPSIS\r\n"
> +" \r\n"
> +"gpt [read | readfile | write | writefile | list | info | clear |\r\n"
> +" create | delete | rename | setattrs | sync | fatformat | -typesinfo | -yes]
> \r\n"
> +"This is a complex utility. Please see examples for usage info\r\n"
> +".SH OPTIONS\r\n"
> +" \r\n"
> +" Device - Block device to be used for the operation\r\n"
> +" Length - Number of bytes to transfer (for read/write))\r\n"
> +" Address - Address in RAM to store/load data\r\n"
> +" Offset - Offset (in blocks) from beggining of the specifie partition to
> store/load data\r\n"
> +" FilePath - Path to file to read data into or write/update data from\r\n"
> +" -yes - Assume yes for all queries, do not prompt\r\n\r\n"
> +".SH EXAMPLES\r\n"
> +" \r\n"
> +"EXAMPLES:\r\n"
> +"Get the list of available partitionable block device(s)\r\n"
> +" gpt %Hlist%N\r\n"
> +"Get info on the particular partition with name PartitionName on the block
> device blk0:\r\n"
> +" gpt %Hinfo%N blk0: PartitionName\r\n"
> +"List all available GPT partitions on the block device blk0:\r\n"
> +" gpt list blk0:\r\n"
> +"Note: the ordinal number shown by this command can be used as a
> partition name in any command requiring partition name\r\n"
> +"Thus gpt info blk0: 1 is valid if there is a partition with ordinal 1 present in
> the output of gpt list command\r\n"
> +"Get information on all recognized partition types\r\n"
> +" gpt %Htypesinfo%N\r\n"
> +"Clear partitions information and install empty GPT tables for a block device
> blk0:\r\n"
> +" gpt %Hclear%N blk0:\r\n"
> +"Create a GPT partition with name PartitionName and type EFI SYSTEM in
> the GPT table, using the next available LBA, with size\r\n"
> +"64MiB, with system attribute, on block device blk0:\r\n"
> +" gpt %Hcreate%N blk0: PartitionName 0 64 1 -type 0\r\n"
> +"Same as above, but now the partition type is not known to the gpt utility,
> so use some GUID known to a 3rd party\r\n"
> +" gpt create blk0: PartitionName 0 64 1 -type 44581A4A-C834-D1A6-2602-
> 9D522A8F2307\r\n"
> +"Rename the GPT partition PartitionName on blk0: to
> NewPartitionName\r\n"
> +" gpt %Hrename%N blk0: PartitionName NewPartitionName\r\n"
> +"Have the PartitionDxe driver to re-read GPT tables on a block device
> blk0:(after they were updated with gpt utility)\r\n"
> +" gpt %Hsync%N blk0:\r\n"
> +"Read 4K from block offset 0x0e000 in Partition named PartitionName of
> the block device at blk0: into RAM at address 0x100000\r\n"
> +" gpt %Hread%N blk0: 0x100000 PartitionName 0xe000 4096\r\n"
> +"Write 512 bytes from 0x200000 at RAM into the block device at blk0:
> partition PartitionName at offset 0x1000\r\n"
> +" gpt %Hwrite%N blk0: 0x200000 PartitionName 0x1000 512\r\n"
> +"Read 0x3000 bytes from 0x0 offset of Partition PartitionName at the block
> device blk0: into file fs2:file.bin\r\n"
> +" gpt %Hreadfile%N blk0: fs2:file.bin PartitionName 0x0 0x3000\r\n"
> +"Write contents of file fs2:file.bin into partition named PartitionName with
> offset (in lba) 0x10 on a block device blk0:\r\n"
> +" gpt %Hwritefile%N blk0: fs2:file.bin PartitionName 0x10\r\n"
> +"FAT Format the partition PartitionName on block device blk0:\r\n"
> +" gpt %Hfatformat%N blk0: PartitionName\r\n"
> +"FAT Format the whole device blk0:\r\n"
> +" gpt fatformat blk0:\r\n"
> +
> +".SH RETURNVALUES\r\n"
> +" \r\n"
> +"RETURN VALUES:\r\n"
> +" SHELL_SUCCESS The action was completed as requested.\r\n"
> +" Specific Shell error Error while processing command\r\n"
> diff --git a/ShellPkg/ShellPkg.dec b/ShellPkg/ShellPkg.dec
> index 39f8012b98c1..5374a2a62d5f 100644
> --- a/ShellPkg/ShellPkg.dec
> +++ b/ShellPkg/ShellPkg.dec
> @@ -56,6 +56,7 @@ [Guids]
> gShellNetwork2HiiGuid = {0x174b2b5, 0xf505, 0x4b12, {0xaa, 0x60,
> 0x59, 0xdf, 0xf8, 0xd6, 0xea, 0x37}}
> gShellTftpHiiGuid = {0x738a9314, 0x82c1, 0x4592, {0x8f, 0xf7, 0xc1,
> 0xbd, 0xf1, 0xb2, 0x0e, 0xd4}}
> gShellBcfgHiiGuid = {0x5f5f605d, 0x1583, 0x4a2d, {0xa6, 0xb2, 0xeb,
> 0x12, 0xda, 0xb4, 0xa2, 0xb6}}
> + gShellGptHiiGuid = {0x5a1ed739, 0x5ef1, 0x429a, {0x8d, 0xf8, 0x28,
> 0xc9, 0x92, 0x64, 0xd7, 0xf8}}
>
> [Protocols]
> gEfiShellProtocolGuid = {0x6302d008, 0x7f9b, 0x4f30, {0x87, 0xac,
> 0x60, 0xc9, 0xfe, 0xf5, 0xda, 0x4e}}
> diff --git a/ShellPkg/ShellPkg.dsc b/ShellPkg/ShellPkg.dsc
> index 809bd4220af2..984c1d0ad48b 100644
> --- a/ShellPkg/ShellPkg.dsc
> +++ b/ShellPkg/ShellPkg.dsc
> @@ -89,6 +89,7 @@ [Components]
>
> ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib
> .inf
>
> ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib
> .inf
>
> ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsL
> ib.inf
> + ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
>
> ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLi
> b.inf
>
> ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1Commands
> Lib.inf
>
> ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1Comm
> andsLib.inf
> @@ -119,6 +120,9 @@ [Components]
> !ifdef $(INCLUDE_TFTP_COMMAND)
>
> NULL|ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib
> .inf
> !endif #$(INCLUDE_TFTP_COMMAND)
> +!ifdef $(INCLUDE_GPT_COMMAND)
> +
> NULL|ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.
> inf
> +!endif #$(INCLUDE_GPT_COMMAND)
> !endif #$(NO_SHELL_PROFILES)
> }
>
> --
> 1.9.1
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] GPT Shell Application/Library
2016-10-18 1:48 ` Tim Lewis
@ 2016-10-18 1:55 ` Ni, Ruiyu
2016-10-18 2:59 ` Carsey, Jaben
0 siblings, 1 reply; 20+ messages in thread
From: Ni, Ruiyu @ 2016-10-18 1:55 UTC (permalink / raw)
To: Tim Lewis, Vladimir Olovyannikov, Carsey, Jaben,
edk2-devel@lists.01.org
Or we could have a common wrapper module, that links to different library to provide different <command>.efi.
This will require the name of the wrapper module is customizable. Haven't tried on that, seems doable.
Thanks/Ray
> -----Original Message-----
> From: Tim Lewis [mailto:tim.lewis@insyde.com]
> Sent: Tuesday, October 18, 2016 9:48 AM
> To: Ni, Ruiyu <ruiyu.ni@intel.com>; Vladimir Olovyannikov
> <vladimir.olovyannikov@broadcom.com>; Carsey, Jaben
> <jaben.carsey@intel.com>; edk2-devel@lists.01.org
> Subject: RE: [PATCH] GPT Shell Application/Library
>
> We would prefer that this tool be external. Tim
>
> -----Original Message-----
> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of Ni,
> Ruiyu
> Sent: Monday, October 17, 2016 6:46 PM
> To: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>; Carsey,
> Jaben <jaben.carsey@intel.com>; edk2-devel@lists.01.org
> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
>
> Jaben,
> Do you think that providing a standalone gpt.efi is better? So that Shell.efi
> only provides the internal commands listed in Shell spec.
>
> Thanks/Ray
>
> > -----Original Message-----
> > From: Vladimir Olovyannikov
> [mailto:vladimir.olovyannikov@broadcom.com]
> > Sent: Sunday, October 16, 2016 1:24 PM
> > To: Carsey, Jaben <jaben.carsey@intel.com>; edk2-devel@lists.01.org; Ni,
> > Ruiyu <ruiyu.ni@intel.com>
> > Cc: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>
> > Subject: [PATCH] GPT Shell Application/Library
> >
> > This allows managing (create, delete, modify, fat format) of GPT
> > partitions from within UEFI Shell.
> > Syntax:
> > gpt <command> [device_mapped_name] [parameters...]
> > See usage examples in the .uni file
> > ---
> > .../Library/UefiShellGptCommandLib/FatFormat.c | 611 +++++++
> > .../Library/UefiShellGptCommandLib/FatFormat.h | 111 ++
> > .../Library/UefiShellGptCommandLib/GptWorker.c | 1902
> > ++++++++++++++++++++
> > .../Library/UefiShellGptCommandLib/GptWorker.h | 186 ++
> > .../UefiShellGptCommandLib.c | 1135 ++++++++++++
> > .../UefiShellGptCommandLib.inf | 79 +
> > .../UefiShellGptCommandLib.uni | 117 ++
> > ShellPkg/ShellPkg.dec | 1 +
> > ShellPkg/ShellPkg.dsc | 4 +
> > 9 files changed, 4146 insertions(+)
> > create mode 100644
> ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> > create mode 100644
> > ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> > create mode 100644
> > ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> > create mode 100644
> > ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> > create mode 100644
> > ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> > create mode 100644
> > ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> > create mode 100644
> > ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
> >
> > diff --git a/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> > b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> > new file mode 100644
> > index 000000000000..ba7904e6be28
> > --- /dev/null
> > +++ b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> > @@ -0,0 +1,611 @@
> > +/** @file
> > +
> > + Copyright (c) 2003 - 2012, Rob Riglar, Ultra-Embedded.com. All rights
> > reserved<BR>
> > +
> > + This program and the accompanying materials
> > + are licensed and made available under the terms and conditions of the
> BSD
> > License
> > + which accompanies this distribution. The full text of the license may be
> > found at
> > + http://opensource.org/licenses/bsd-license.php
> > +
> > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> > BASIS,
> > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> > EXPRESS OR IMPLIED.
> > +
> > +**/
> > +
> > +/* Portions Copyright (c) 2016, Broadcom. All rights reserved */
> > +
> > +#include "FatFormat.h"
> > +
> > +//-----------------------------------------------------------------------------
> > +// Tables
> > +//-----------------------------------------------------------------------------
> > +typedef struct
> > +{
> > + UINT64 Sectors;
> > + UINT8 SectorsPerCluster;
> > +} SectorsPerClusterTable;
> > +
> > +STATIC SectorsPerClusterTable ClusterSizeTable16[] =
> > +{
> > + { 32680, 2 }, // 16MB - 1K
> > + { 262144, 4 }, // 128MB - 2K
> > + { 524288, 8 }, // 256MB - 4K
> > + { 1048576, 16 }, // 512MB - 8K
> > + { 2097152, 32 }, // 1GB - 16K
> > + { 4194304, 64 }, // 2GB - 32K
> > + { 8388608, 128 }, // 2GB - 64K [Warning only supported by Windows XP
> > onwards]
> > + { 0, 0 } // Invalid
> > +};
> > +
> > +STATIC SectorsPerClusterTable ClusterSizeTable32[] =
> > +{
> > + { 532480, 1 }, // 260MB - 512b
> > + { 16777216, 8 }, // 8GB - 4K
> > + { 33554432, 16 }, // 16GB - 8K
> > + { 67108864, 32 }, // 32GB - 16K
> > + { 0xFFFFFFFF, 64 }, // >32GB - 32K
> > + { 0, 0 } // Invalid
> > +};
> > +
> > +STATIC
> > +EFI_LBA LbaOfCluster (
> > + IN FATFS *Fs,
> > + IN UINT64 ClusterNumber
> > + )
> > +{
> > + if (Fs->FatType == FAT_TYPE_16)
> > + return (Fs->ClusterBeginLba +
> > + (Fs->RootEntryCount * 32 / FAT_SECTOR_SIZE) +
> > + ((ClusterNumber - 2) * Fs->SectorsPerCluster));
> > + else
> > + return ((Fs->ClusterBeginLba +
> > + ((ClusterNumber - 2) * Fs->SectorsPerCluster)));
> > +}
> > +
> > +//-----------------------------------------------------------------------------
> > +// fatfs_calc_cluster_size: Calculate what cluster size should be used
> > +//-----------------------------------------------------------------------------
> > +STATIC
> > +UINT8 CalcClusterSize (
> > + IN UINTN Sectors,
> > + IN BOOLEAN IsFat32)
> > +{
> > + UINTN Index;
> > +
> > + if (!IsFat32) {
> > + for (Index = 0; ClusterSizeTable16[Index].SectorsPerCluster != 0;
> Index++)
> > + if (Sectors <= ClusterSizeTable16[Index].Sectors)
> > + return ClusterSizeTable16[Index].SectorsPerCluster;
> > + } else {
> > + for (Index = 0; ClusterSizeTable32[Index].SectorsPerCluster != 0;
> Index++)
> > + if (Sectors <= ClusterSizeTable32[Index].Sectors)
> > + return ClusterSizeTable32[Index].SectorsPerCluster;
> > + }
> > +
> > + return 0;
> > +}
> > +//-----------------------------------------------------------------------------
> > +// fatfs_erase_sectors: Erase a number of sectors
> > +//-----------------------------------------------------------------------------
> > +STATIC
> > +EFI_STATUS
> > +EraseSectors (
> > + IN FATFS *Fs,
> > + IN EFI_LBA Lba,
> > + IN UINTN Count
> > + )
> > +{
> > + UINTN Index;
> > + EFI_STATUS Status;
> > +
> > + // Zero Sector first
> > + ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE);
> > +
> > + for (Index = 0; Index < Count; Index++)
> > + Status = Fs->DiskIo->WriteDisk (
> > + Fs->DiskIo, Fs->BlockIo->Media->MediaId,
> > + MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) +
> > + MultU64x32 ((Lba + Index), FAT_SECTOR_SIZE),
> > + FAT_SECTOR_SIZE, Fs->CurrentSector.Sector);
> > +
> > + return Status;
> > +}
> > +//-----------------------------------------------------------------------------
> > +// fatfs_create_boot_sector: Create the boot Sector
> > +//-----------------------------------------------------------------------------
> > +STATIC
> > +EFI_STATUS
> > +CreateBootSector (
> > + IN FATFS *Fs,
> > + IN EFI_LBA BootSectorLba,
> > + IN UINT64 VolSectors,
> > + IN CONST CHAR8 *Name,
> > + IN BOOLEAN IsFat32
> > + )
> > +{
> > + UINTN TotalClusters;
> > + UINTN Index;
> > + EFI_STATUS Status;
> > +
> > + // Zero Sector initially
> > + ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE);
> > +
> > + // OEM Name & Jump Code
> > + Fs->CurrentSector.Sector[0] = 0xEB;
> > + Fs->CurrentSector.Sector[1] = 0x3C;
> > + Fs->CurrentSector.Sector[2] = 0x90;
> > + Fs->CurrentSector.Sector[3] = 0x4D;
> > + Fs->CurrentSector.Sector[4] = 0x53;
> > + Fs->CurrentSector.Sector[5] = 0x44;
> > + Fs->CurrentSector.Sector[6] = 0x4F;
> > + Fs->CurrentSector.Sector[7] = 0x53;
> > + Fs->CurrentSector.Sector[8] = 0x35;
> > + Fs->CurrentSector.Sector[9] = 0x2E;
> > + Fs->CurrentSector.Sector[10] = 0x30;
> > +
> > + // Bytes per Sector
> > + Fs->CurrentSector.Sector[11] = (FAT_SECTOR_SIZE >> 0) & 0xFF;
> > + Fs->CurrentSector.Sector[12] = (FAT_SECTOR_SIZE >> 8) & 0xFF;
> > +
> > + // Get sectors per cluster size for the disk
> > + Fs->SectorsPerCluster = CalcClusterSize (VolSectors, IsFat32);
> > + if (!Fs->SectorsPerCluster)
> > + return 0; // Invalid disk size
> > +
> > + // Sectors per cluster
> > + Fs->CurrentSector.Sector[13] = Fs->SectorsPerCluster;
> > +
> > + // Reserved Sectors
> > + if (!IsFat32)
> > + Fs->ReservedSectors = 8;
> > + else
> > + Fs->ReservedSectors = 32;
> > + Fs->CurrentSector.Sector[14] = (Fs->ReservedSectors >> 0) & 0xFF;
> > + Fs->CurrentSector.Sector[15] = (Fs->ReservedSectors >> 8) & 0xFF;
> > +
> > + // Number of FATS
> > + Fs->NumOfFats = 2;
> > + Fs->CurrentSector.Sector[16] = Fs->NumOfFats;
> > +
> > + // Max entries in root dir (FAT16 only)
> > + if (!IsFat32) {
> > + Fs->RootEntryCount = 512;
> > + Fs->CurrentSector.Sector[17] = (Fs->RootEntryCount >> 0) & 0xFF;
> > + Fs->CurrentSector.Sector[18] = (Fs->RootEntryCount >> 8) & 0xFF;
> > + } else {
> > + Fs->RootEntryCount = 0;
> > + Fs->CurrentSector.Sector[17] = 0;
> > + Fs->CurrentSector.Sector[18] = 0;
> > + }
> > +
> > + // [FAT16] Total sectors (use FAT32 count instead)
> > + Fs->CurrentSector.Sector[19] = 0x00;
> > + Fs->CurrentSector.Sector[20] = 0x00;
> > +
> > + // Media type
> > + Fs->CurrentSector.Sector[21] = 0xF8;
> > +
> > +
> > + // FAT16 BS Details
> > + if (!IsFat32) {
> > + // Count of sectors used by the FAT table (FAT16 only)
> > + TotalClusters = (VolSectors / Fs->SectorsPerCluster) + 1;
> > + Fs->FatSectors = (TotalClusters / (FAT_SECTOR_SIZE / 2)) + 1;
> > + Fs->CurrentSector.Sector[22] = (UINT8)((Fs->FatSectors >> 0) & 0xFF);
> > + Fs->CurrentSector.Sector[23] = (UINT8)((Fs->FatSectors >> 8) & 0xFF);
> > +
> > + // Sectors per track
> > + Fs->CurrentSector.Sector[24] = 0x00;
> > + Fs->CurrentSector.Sector[25] = 0x00;
> > +
> > + // Heads
> > + Fs->CurrentSector.Sector[26] = 0x00;
> > + Fs->CurrentSector.Sector[27] = 0x00;
> > +
> > + // Hidden sectors
> > + Fs->CurrentSector.Sector[28] = 0x20;
> > + Fs->CurrentSector.Sector[29] = 0x00;
> > + Fs->CurrentSector.Sector[30] = 0x00;
> > + Fs->CurrentSector.Sector[31] = 0x00;
> > +
> > + // Total sectors for this volume
> > + Fs->CurrentSector.Sector[32] = (UINT8)((VolSectors >> 0) & 0xFF);
> > + Fs->CurrentSector.Sector[33] = (UINT8)((VolSectors >> 8) & 0xFF);
> > + Fs->CurrentSector.Sector[34] = (UINT8)((VolSectors >> 16) & 0xFF);
> > + Fs->CurrentSector.Sector[35] = (UINT8)((VolSectors >> 24) & 0xFF);
> > +
> > + // Drive number
> > + Fs->CurrentSector.Sector[36] = 0x00;
> > +
> > + // Reserved
> > + Fs->CurrentSector.Sector[37] = 0x00;
> > +
> > + // Boot signature
> > + Fs->CurrentSector.Sector[38] = 0x29;
> > +
> > + // Volume ID
> > + Fs->CurrentSector.Sector[39] = 0x12;
> > + Fs->CurrentSector.Sector[40] = 0x34;
> > + Fs->CurrentSector.Sector[41] = 0x56;
> > + Fs->CurrentSector.Sector[42] = 0x78;
> > +
> > + // Volume name
> > + for (Index = 0; Index < 11; Index++) {
> > + if (Index < AsciiStrLen (Name))
> > + Fs->CurrentSector.Sector[Index + 43] = Name[Index];
> > + else
> > + Fs->CurrentSector.Sector[Index + 43] = ' ';
> > + }
> > +
> > + // File sys type
> > + Fs->CurrentSector.Sector[54] = 'F';
> > + Fs->CurrentSector.Sector[55] = 'A';
> > + Fs->CurrentSector.Sector[56] = 'T';
> > + Fs->CurrentSector.Sector[57] = '1';
> > + Fs->CurrentSector.Sector[58] = '6';
> > + Fs->CurrentSector.Sector[59] = ' ';
> > + Fs->CurrentSector.Sector[60] = ' ';
> > + Fs->CurrentSector.Sector[61] = ' ';
> > +
> > + // Signature
> > + Fs->CurrentSector.Sector[510] = 0x55;
> > + Fs->CurrentSector.Sector[511] = 0xAA;
> > + }
> > + // FAT32 BS Details
> > + else {
> > + // Count of sectors used by the FAT table (FAT16 only)
> > + Fs->CurrentSector.Sector[22] = 0;
> > + Fs->CurrentSector.Sector[23] = 0;
> > +
> > + // Sectors per track (default)
> > + Fs->CurrentSector.Sector[24] = 0x3F;
> > + Fs->CurrentSector.Sector[25] = 0x00;
> > +
> > + // Heads (default)
> > + Fs->CurrentSector.Sector[26] = 0xFF;
> > + Fs->CurrentSector.Sector[27] = 0x00;
> > +
> > + // Hidden sectors
> > + Fs->CurrentSector.Sector[28] = 0x00;
> > + Fs->CurrentSector.Sector[29] = 0x00;
> > + Fs->CurrentSector.Sector[30] = 0x00;
> > + Fs->CurrentSector.Sector[31] = 0x00;
> > +
> > + // Total sectors for this volume
> > + Fs->CurrentSector.Sector[32] = (UINT8)((VolSectors >> 0) & 0xFF);
> > + Fs->CurrentSector.Sector[33] = (UINT8)((VolSectors >> 8) & 0xFF);
> > + Fs->CurrentSector.Sector[34] = (UINT8)((VolSectors >> 16) & 0xFF);
> > + Fs->CurrentSector.Sector[35] = (UINT8)((VolSectors >> 24) & 0xFF);
> > +
> > + TotalClusters = (VolSectors / Fs->SectorsPerCluster) + 1;
> > + Fs->FatSectors = (TotalClusters / (FAT_SECTOR_SIZE / 4)) + 1;
> > +
> > + // BPB_FATSz32
> > + Fs->CurrentSector.Sector[36] = (UINT8)((Fs->FatSectors >> 0) & 0xFF);
> > + Fs->CurrentSector.Sector[37] = (UINT8)((Fs->FatSectors >> 8) & 0xFF);
> > + Fs->CurrentSector.Sector[38] = (UINT8)((Fs->FatSectors >> 16) & 0xFF);
> > + Fs->CurrentSector.Sector[39] = (UINT8)((Fs->FatSectors >> 24) & 0xFF);
> > +
> > + // BPB_ExtFlags
> > + Fs->CurrentSector.Sector[40] = 0;
> > + Fs->CurrentSector.Sector[41] = 0;
> > +
> > + // BPB_FSVer
> > + Fs->CurrentSector.Sector[42] = 0;
> > + Fs->CurrentSector.Sector[43] = 0;
> > +
> > + // BPB_RootClus
> > + Fs->CurrentSector.Sector[44] = (UINT8)((Fs->RootdirFirstCluster >> 0) &
> > 0xFF);
> > + Fs->CurrentSector.Sector[45] = (UINT8)((Fs->RootdirFirstCluster >> 8) &
> > 0xFF);
> > + Fs->CurrentSector.Sector[46] = (UINT8)((Fs->RootdirFirstCluster >> 16)
> &
> > 0xFF);
> > + Fs->CurrentSector.Sector[47] = (UINT8)((Fs->RootdirFirstCluster >> 24)
> &
> > 0xFF);
> > +
> > + // BPB_FSInfo
> > + Fs->CurrentSector.Sector[48] = (UINT8)((Fs->FsInfoSector >> 0) & 0xFF);
> > + Fs->CurrentSector.Sector[49] = (UINT8)((Fs->FsInfoSector >> 8) & 0xFF);
> > +
> > + // BPB_BkBootSec
> > + Fs->CurrentSector.Sector[50] = 6;
> > + Fs->CurrentSector.Sector[51] = 0;
> > +
> > + // Drive number
> > + Fs->CurrentSector.Sector[64] = 0x00;
> > +
> > + // Boot signature
> > + Fs->CurrentSector.Sector[66] = 0x29;
> > +
> > + // Volume ID
> > + Fs->CurrentSector.Sector[67] = 0x12;
> > + Fs->CurrentSector.Sector[68] = 0x34;
> > + Fs->CurrentSector.Sector[69] = 0x56;
> > + Fs->CurrentSector.Sector[70] = 0x78;
> > +
> > + // Volume name
> > + for (Index = 0; Index < 11; Index++) {
> > + if (Index < (int)AsciiStrLen (Name))
> > + Fs->CurrentSector.Sector[Index + 71] = Name[Index];
> > + else
> > + Fs->CurrentSector.Sector[Index + 71] = ' ';
> > + }
> > +
> > + // File sys type
> > + Fs->CurrentSector.Sector[82] = 'F';
> > + Fs->CurrentSector.Sector[83] = 'A';
> > + Fs->CurrentSector.Sector[84] = 'T';
> > + Fs->CurrentSector.Sector[85] = '3';
> > + Fs->CurrentSector.Sector[86] = '2';
> > + Fs->CurrentSector.Sector[87] = ' ';
> > + Fs->CurrentSector.Sector[88] = ' ';
> > + Fs->CurrentSector.Sector[89] = ' ';
> > +
> > + // Signature
> > + Fs->CurrentSector.Sector[510] = 0x55;
> > + Fs->CurrentSector.Sector[511] = 0xAA;
> > + }
> > +
> > + Status = Fs->DiskIo->WriteDisk (
> > + Fs->DiskIo, Fs->BlockIo->Media->MediaId,
> > + MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) +
> > + MultU64x32 (Fs->FatBeginLba, FAT_SECTOR_SIZE),
> > + FAT_SECTOR_SIZE,
> > + Fs->CurrentSector.Sector);
> > +
> > + return Status;
> > +}
> > +//-----------------------------------------------------------------------------
> > +// fatfs_create_fsinfo_sector: Create the FSInfo Sector (FAT32)
> > +//-----------------------------------------------------------------------------
> > +STATIC
> > +EFI_STATUS
> > +CreateFsinfoSector (
> > + IN FATFS *Fs,
> > + IN EFI_LBA SectorLba
> > + )
> > +{
> > + EFI_STATUS Status;
> > +
> > + // Zero Sector initially
> > + ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE);
> > +
> > + // FSI_LeadSig
> > + Fs->CurrentSector.Sector[0] = 0x52;
> > + Fs->CurrentSector.Sector[1] = 0x52;
> > + Fs->CurrentSector.Sector[2] = 0x61;
> > + Fs->CurrentSector.Sector[3] = 0x41;
> > +
> > + // FSI_StrucSig
> > + Fs->CurrentSector.Sector[484] = 0x72;
> > + Fs->CurrentSector.Sector[485] = 0x72;
> > + Fs->CurrentSector.Sector[486] = 0x41;
> > + Fs->CurrentSector.Sector[487] = 0x61;
> > +
> > + // FSI_Free_Count
> > + Fs->CurrentSector.Sector[488] = 0xFF;
> > + Fs->CurrentSector.Sector[489] = 0xFF;
> > + Fs->CurrentSector.Sector[490] = 0xFF;
> > + Fs->CurrentSector.Sector[491] = 0xFF;
> > +
> > + // FSI_Nxt_Free
> > + Fs->CurrentSector.Sector[492] = 0xFF;
> > + Fs->CurrentSector.Sector[493] = 0xFF;
> > + Fs->CurrentSector.Sector[494] = 0xFF;
> > + Fs->CurrentSector.Sector[495] = 0xFF;
> > +
> > + // Signature
> > + Fs->CurrentSector.Sector[510] = 0x55;
> > + Fs->CurrentSector.Sector[511] = 0xAA;
> > +
> > + Status = Fs->DiskIo->WriteDisk (
> > + Fs->DiskIo, Fs->BlockIo->Media->MediaId,
> > + MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) +
> > + MultU64x32 (SectorLba, FAT_SECTOR_SIZE),
> > + FAT_SECTOR_SIZE,
> > + Fs->CurrentSector.Sector);
> > +
> > + return Status;
> > +}
> > +//-----------------------------------------------------------------------------
> > +// fatfs_erase_fat: Erase FAT table using fs details in fs struct
> > +//-----------------------------------------------------------------------------
> > +STATIC
> > +EFI_STATUS
> > +EraseFat (
> > + IN FATFS *Fs,
> > + IN BOOLEAN IsFat32)
> > +{
> > + UINTN Index;
> > + EFI_STATUS Status;
> > +
> > + // Zero Sector initially
> > + ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE);
> > +
> > + // Initialise default allocate / reserved clusters
> > + if (!IsFat32) {
> > + SET_16BIT_WORD (Fs->CurrentSector.Sector, 0, 0xFFF8);
> > + SET_16BIT_WORD (Fs->CurrentSector.Sector, 2, 0xFFFF);
> > + } else {
> > + SET_32BIT_WORD (Fs->CurrentSector.Sector, 0, 0x0FFFFFF8);
> > + SET_32BIT_WORD (Fs->CurrentSector.Sector, 4, 0xFFFFFFFF);
> > + SET_32BIT_WORD (Fs->CurrentSector.Sector, 8, 0x0FFFFFFF);
> > + }
> > +
> > + Status = Fs->DiskIo->WriteDisk (
> > + Fs->DiskIo, Fs->BlockIo->Media->MediaId,
> > + MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) +
> > + MultU64x32 (Fs->FatBeginLba, FAT_SECTOR_SIZE),
> > + FAT_SECTOR_SIZE,
> > + Fs->CurrentSector.Sector);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + // Zero remaining FAT sectors
> > + ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE);
> > + for (Index = 1; Index < Fs->FatSectors * Fs->NumOfFats; Index++) {
> > + Status = Fs->DiskIo->WriteDisk (
> > + Fs->DiskIo,
> > + Fs->BlockIo->Media->MediaId,
> > + MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) +
> > + MultU64x32 ((Fs->FatBeginLba + Index), FAT_SECTOR_SIZE),
> > + FAT_SECTOR_SIZE,
> > + Fs->CurrentSector.Sector);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > + }
> > + return Status;
> > +}
> > +//-----------------------------------------------------------------------------
> > +// fatfs_format_fat16: Format a FAT16 partition
> > +//-----------------------------------------------------------------------------
> > +STATIC
> > +EFI_STATUS
> > +FormatFat16 (
> > + IN FATFS *Fs,
> > + IN UINT64 VolumeSectors,
> > + IN CONST CHAR8 *Name
> > + )
> > +{
> > + EFI_STATUS Status;
> > +
> > + Fs->CurrentSector.Address = FAT32_INVALID_CLUSTER;
> > + Fs->CurrentSector.Dirty = 0;
> > +
> > + Fs->NextFreeCluster = 0; // Invalid
> > +
> > + // Volume is FAT16
> > + Fs->FatType = FAT_TYPE_16;
> > +
> > + // Not valid for FAT16
> > + Fs->FsInfoSector = 0;
> > + Fs->RootdirFirstCluster = 0;
> > +
> > + Fs->LbaBegin = 0;
> > + Status = CreateBootSector (Fs, Fs->LbaBegin, VolumeSectors, Name, 0);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + // For FAT16 (which this may be), RootdirFirstCluster is actuall
> > RootdirFirstSector
> > + Fs->RootdirFirstSector = Fs->ReservedSectors + (Fs->NumOfFats * Fs-
> > >FatSectors);
> > + Fs->RootdirSectors = ((Fs->RootEntryCount * 32) +
> > + (FAT_SECTOR_SIZE - 1)) / FAT_SECTOR_SIZE;
> > +
> > + // First FAT LBA Address
> > + Fs->FatBeginLba = Fs->LbaBegin + Fs->ReservedSectors;
> > +
> > + // The Address of the first data cluster on this volume
> > + Fs->ClusterBeginLba = Fs->FatBeginLba +
> > + (Fs->NumOfFats * Fs->FatSectors);
> > +
> > + // Initialise FAT sectors
> > + Status = EraseFat (Fs, 0);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + // Erase Root directory
> > + Status = EraseSectors (
> > + Fs,
> > + Fs->LbaBegin + Fs->RootdirFirstSector,
> > + Fs->RootdirSectors);
> > +
> > + return Status;
> > +}
> > +//-----------------------------------------------------------------------------
> > +// fatfs_format_fat32: Format a FAT32 partition
> > +//-----------------------------------------------------------------------------
> > +STATIC
> > +EFI_STATUS
> > +FormatFat32 (
> > + IN FATFS *Fs,
> > + IN UINTN VolumeSectors,
> > + IN CONST CHAR8 *Name
> > + )
> > +{
> > + EFI_STATUS Status;
> > +
> > + Fs->CurrentSector.Address = FAT32_INVALID_CLUSTER;
> > + Fs->CurrentSector.Dirty = 0;
> > +
> > + Fs->NextFreeCluster = 0; // Invalid
> > +
> > + // Volume is FAT32
> > + Fs->FatType = FAT_TYPE_32;
> > +
> > + // Basic defaults for normal FAT32 partitions
> > + Fs->FsInfoSector = 1;
> > + Fs->RootdirFirstCluster = 2;
> > +
> > + // Sector 0: Boot Sector
> > + // NOTE: We don't need an MBR, it is a waste of a good Sector!
> > + Fs->LbaBegin = 0;
> > + Status = CreateBootSector (Fs, Fs->LbaBegin, VolumeSectors, Name, 1);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + // First FAT LBA address
> > + Fs->FatBeginLba = Fs->LbaBegin + Fs->ReservedSectors;
> > +
> > + // The address of the first data cluster on this volume
> > + Fs->ClusterBeginLba = Fs->FatBeginLba + (Fs->NumOfFats * Fs-
> > >FatSectors);
> > +
> > + // Initialise FSInfo sector
> > + Status = CreateFsinfoSector (Fs, Fs->FsInfoSector);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + // Initialise FAT sectors
> > + Status = EraseFat (Fs, 1);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + // Erase Root directory
> > + Status = EraseSectors (
> > + Fs,
> > + LbaOfCluster (Fs, Fs->RootdirFirstCluster),
> > + Fs->SectorsPerCluster);
> > +
> > + return Status;
> > +}
> > +//-----------------------------------------------------------------------------
> > +// fatfs_format: Format a partition with either FAT16 or FAT32 based on
> size
> > +//-----------------------------------------------------------------------------
> > +EFI_STATUS
> > +FatFormat (
> > + IN EFI_LBA StartingLBA,
> > + IN EFI_LBA EndingLBA,
> > + IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
> > + IN EFI_DISK_IO_PROTOCOL *DiskIo,
> > + IN CHAR8 *VolumeName,
> > + IN BOOLEAN ForceFat32
> > + )
> > +{
> > + FATFS Fs;
> > + UINT64 VolumeSectors;
> > +
> > + VolumeSectors = DivU64x32 (
> > + MultU64x32 (
> > + EndingLBA - StartingLBA + 1, BlockIo->Media->BlockSize),
> > + FAT_SECTOR_SIZE);
> > +
> > + if (VolumeName == NULL) {
> > + VolumeName = DEFAULT_FAT_LABEL_NAME;
> > + }
> > +
> > + ZeroMem (&Fs, sizeof(Fs));
> > +
> > + Fs.StartingLBA = StartingLBA;
> > + Fs.EndingLBA = EndingLBA;
> > + Fs.BlockIo = BlockIo;
> > + Fs.DiskIo = DiskIo;
> > + // 2GB - 32K limit for safe behaviour for FAT16
> > + if ((VolumeSectors <= 4194304) && (!ForceFat32)) {
> > + return FormatFat16 (&Fs, VolumeSectors, VolumeName);
> > + } else {
> > + return FormatFat32 (&Fs, VolumeSectors, VolumeName);
> > + }
> > +}
> > diff --git a/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> > b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> > new file mode 100644
> > index 000000000000..d1a325a57abe
> > --- /dev/null
> > +++ b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> > @@ -0,0 +1,111 @@
> > +/** @file
> > +
> > + Copyright (c) 2003 - 2012, Ultra-Embedded.com. All rights reserved<BR>
> > +
> > + This program and the accompanying materials
> > + are licensed and made available under the terms and conditions of the
> BSD
> > License
> > + which accompanies this distribution. The full text of the license may be
> > found at
> > + http://opensource.org/licenses/bsd-license.php
> > +
> > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> > BASIS,
> > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> > EXPRESS OR IMPLIED.
> > +
> > +**/
> > +
> > +/* Portions Copyright (c) 2016, Broadcom. All rights reserved */
> > +
> > +#ifndef __FAT_FORMAT_H__
> > +#define __FAT_FORMAT_H__
> > +
> > +#include "GptWorker.h"
> > +
> > +#define FAT_SECTOR_SIZE 512
> > +#define FAT_BUFFER_SECTORS 1
> > +#define FAT32_LAST_CLUSTER 0xFFFFFFFF
> > +#define FAT32_INVALID_CLUSTER 0xFFFFFFFF
> > +#define FAT_DIR_ENTRY_SIZE 32
> > +#define FAT_BUFFERS 1
> > +#define DEFAULT_FAT_LABEL_NAME "EFIVOL"
> > +
> > +#define GET_32BIT_WORD(Buffer, Location)
> > ( ((UINT32)Buffer[Location + 3] << 24) + \
> > + ((UINT32)Buffer[Location + 2] <<16 ) + \
> > + ((UINT32)Buffer[Location + 1] << 8) + \
> > + (UINT32)Buffer[Location+0] )
> > +
> > +#define GET_16BIT_WORD(Buffer, Location)
> > ( ((UINT16)Buffer[Location + 1] << 8) + \
> > + (UINT16)Buffer[Location+0])
> > +
> > +#define SET_32BIT_WORD(Buffer, Location, Value) { Buffer[Location + 0]
> =
> > (UINT8)((Value) & 0xFF); \
> > + Buffer[Location + 1] = (UINT8)((Value >> 8) &
> 0xFF);
> > \
> > + Buffer[Location + 2] = (UINT8)((Value >> 16) &
> > 0xFF); \
> > + Buffer[Location + 3] = (UINT8)((Value >> 24) &
> > 0xFF); }
> > +
> > +#define SET_16BIT_WORD(Buffer, Location, Value) { Buffer[Location + 0]
> =
> > (UINT8)((Value) & 0xFF); \
> > + Buffer[Location + 1] = (UINT8)((Value >> 8) &
> > 0xFF); }
> > +
> > +typedef enum eFatType
> > +{
> > + FAT_TYPE_16,
> > + FAT_TYPE_32
> > +} FAT_FS_TYPE;
> > +
> > +
> > +// Forward declaration
> > +typedef struct _FAT_BUFFER FAT_BUFFER;
> > +
> > +struct _FAT_BUFFER {
> > + UINT8 Sector[FAT_SECTOR_SIZE * FAT_BUFFER_SECTORS];
> > + UINTN Address;
> > + BOOLEAN Dirty;
> > + UINT8 *Ptr;
> > +
> > + // Next in chain of sector buffers
> > + struct FAT_BUFFER *NextBuf;
> > +};
> > +
> > +typedef struct
> > +{
> > + // Filesystem globals
> > + UINT8 SectorsPerCluster;
> > + EFI_LBA ClusterBeginLba;
> > + UINTN RootdirFirstCluster;
> > + UINTN RootdirFirstSector;
> > + UINTN RootdirSectors;
> > + EFI_LBA FatBeginLba;
> > + UINT16 FsInfoSector;
> > + EFI_LBA LbaBegin;
> > + UINTN FatSectors;
> > + UINTN NextFreeCluster;
> > + UINT16 RootEntryCount;
> > + UINT16 ReservedSectors;
> > + UINT8 NumOfFats;
> > + FAT_FS_TYPE FatType;
> > +
> > + // Working buffer
> > + FAT_BUFFER CurrentSector;
> > + // FAT Buffer
> > + FAT_BUFFER *FatBufferHead;
> > + FAT_BUFFER FatBuffers[FAT_BUFFERS];
> > + EFI_LBA StartingLBA;
> > + EFI_LBA EndingLBA;
> > + EFI_BLOCK_IO_PROTOCOL *BlockIo;
> > + EFI_DISK_IO_PROTOCOL *DiskIo;
> > +
> > +} FATFS;
> > +
> > +
> > +
> > +//-----------------------------------------------------------------------------
> > +// Prototypes
> > +//-----------------------------------------------------------------------------
> > +EFI_STATUS
> > +FatFormat (
> > + IN EFI_LBA StartingLBA,
> > + IN EFI_LBA EndingLBA,
> > + IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
> > + IN EFI_DISK_IO_PROTOCOL *DiskIo,
> > + IN CHAR8 *VolumeName,
> > + IN BOOLEAN ForceFat32
> > + );
> > +
> > +#endif
> > diff --git a/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> > b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> > new file mode 100644
> > index 000000000000..0546c94488b0
> > --- /dev/null
> > +++ b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> > @@ -0,0 +1,1902 @@
> > +/** @file
> > +Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
> > +Copyright (c) 2016, Broadcom. All rights reserved.<BR>
> > +This program and the accompanying materials
> > +are licensed and made available under the terms and conditions of the
> BSD
> > License
> > +which accompanies this distribution. The full text of the license may be
> > found at
> > +http://opensource.org/licenses/bsd-license.php
> > +
> > +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> > BASIS,
> > +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> > EXPRESS OR IMPLIED.
> > +
> > +**/
> > +
> > +#include "GptWorker.h"
> > +
> > +#define GPT_DEBUG_LEVEL 0
> > +
> > +STATIC EFI_PARTITION_TABLE_HEADER *PrimaryHeader = NULL;
> > +STATIC EFI_PARTITION_TABLE_HEADER *BackupHeader = NULL;
> > +STATIC EFI_PARTITION_ENTRY *PartEntry = NULL;
> > +STATIC EFI_PARTITION_ENTRY_STATUS *PEntryStatus = NULL;
> > +
> > +STATIC EFI_BLOCK_IO_PROTOCOL *BlockIo;
> > +STATIC EFI_DISK_IO_PROTOCOL *DiskIo;
> > +
> > +STATIC BOOLEAN MbrValid;
> > +STATIC BOOLEAN GptValid;
> > +
> > +STATIC EFI_KNOWN_PARTITION_TYPE PartitionTypes[] =
> > +{
> > + // Known Partition type GUIDs
> > + // Expand this table as needed.
> > + // Starting with EFI System partition
> > + { { 0xC12A7328L, 0xF81F, 0x11D2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E,
> 0xC9,
> > 0x3B } }, L"EFI System" },
> > + // Known Windows partition types
> > + { { 0xE3C9E316L, 0x0B5C, 0x4DB8, { 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02,
> 0x15,
> > 0xAE } }, L"MS Windows Reserved (MSR)" },
> > + { { 0xEBD0A0A2L, 0xB9E5, 0x4433, { 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26,
> 0x99,
> > 0xC7 } }, L"MS Windows Basic Data" },
> > + { { 0x5808C8AAL, 0x7E8F, 0x42E0, { 0x85, 0xD2, 0xE1, 0xE9, 0x04, 0x34,
> 0xCF,
> > 0xB3 } }, L"MS Windows LDM Metadata" },
> > + { { 0xAF9B60A0L, 0x1431, 0x4F62, { 0xBC, 0x68, 0x33, 0x11, 0x71, 0x4A,
> 0x69,
> > 0xAD } }, L"MS Windows LDM Data" },
> > + { { 0xDE94BBA4L, 0x06D1, 0x4D40, { 0xA1, 0x6A, 0xBF, 0xD5, 0x01, 0x79,
> > 0xD6, 0xAC } }, L"MS Windows Recovery Environment" },
> > + { { 0xE75CAF8FL, 0xF680, 0x4CEE, { 0xAF, 0xA3, 0xB0, 0x01, 0xE5, 0x6E,
> 0xFC,
> > 0x2D } }, L"MS Windows Storage Spaces" },
> > + // Known Linux partition types
> > + { { 0x0FC63DAFL, 0x8483, 0x4772, { 0x8E, 0x79, 0x3D, 0x69, 0xD8, 0x47,
> 0x7D,
> > 0xE4 } }, L"Linux Filesystem Data" },
> > + { { 0xA19D880FL, 0x05FC, 0x4D3B, { 0xA0, 0x06, 0x74, 0x3F, 0x0F, 0x84,
> 0x91,
> > 0x1E } }, L"Linux RAID" },
> > + { { 0x44479540L, 0xF297, 0x41B2, { 0x9A, 0xF7, 0xD1, 0x31, 0xD5, 0xF0,
> 0x45,
> > 0x8A } }, L"Linux Root (x86)" },
> > + { { 0x4F68BCE3L, 0xE8CD, 0x4DB1, { 0x96, 0xE7, 0xFB, 0xCA, 0xF9, 0x84,
> 0xB7,
> > 0x09 } }, L"Linux Root (x86-64)" },
> > + { { 0x69DAD710L, 0x2CE4, 0x4E3C, { 0xB1, 0x6C, 0x21, 0xA1, 0xD4, 0x9A,
> > 0xBe, 0xD3 } }, L"Linux Root (ARM 32-bit)" },
> > + { { 0xB921B045L, 0x1DF0, 0x41C3, { 0xAF, 0x44, 0x4C, 0x6F, 0x28, 0x0D,
> 0x3F,
> > 0xAE } }, L"Linux Root (ARM 64-bit/AARCH64)" },
> > + { { 0x0657FD6DL, 0xA4AB, 0x43C4, { 0x84, 0xE5, 0x09, 0x33, 0xC8, 0x4B,
> 0x4F,
> > 0x4F } }, L"Linux Swap" },
> > + { { 0xE6D6D379L, 0xF507, 0x44C2, { 0xA2, 0x3C, 0x23, 0x8F, 0x2A, 0x3D,
> 0xF9,
> > 0x28 } }, L"Linux Logical Volume Manager (LVM)" },
> > + { { 0x933AC7E1L, 0x2EB4, 0x4F13, { 0xB8, 0x44, 0x0E, 0x14, 0xE2, 0xAE,
> 0xF9,
> > 0x15 } }, L"Linux /home" },
> > + { { 0x3B8F8425L, 0x20E0, 0x4F3B, { 0x90, 0x7F, 0x1A, 0x25, 0xA7, 0x6F,
> 0x98,
> > 0xE8 } }, L"Linux /srv (server data)" },
> > + { { 0x7FFEC5C9L, 0x2D00, 0x49B7, { 0x89, 0x41, 0x3E, 0xA1, 0x0A, 0x55,
> 0x86,
> > 0xB7 } }, L"Linux Plain dm-crypt" },
> > + { { 0xCA7D7CCBL, 0x63ED, 0x4C53, { 0x86, 0x1C, 0x17, 0x42, 0x53, 0x60,
> 0x59,
> > 0xCC } }, L"Linux LUKS" },
> > + { { 0x8DA63339L, 0x0007, 0x60C0, { 0xC4, 0x36, 0x08, 0x3A, 0xC8, 0x23,
> 0x09,
> > 0x08 } }, L"Linux Reserved" },
> > +};
> > +
> > +MASTER_BOOT_RECORD ProtectiveMbrTemplate = {
> > + { 0 }, // BoostStrapCode [440]
> > + { 0 }, // UniqueMbrSignature[4] (unused)
> > + { 0 }, // Unknown[2]
> > +
> > + // PARTITIONS
> > + {
> > + // MBR_PARTITION_RECORD
> > + {
> > + 0, // BootIndicator
> > + 0, // StartHead
> > + 0x1, // StartSector
> > + 0x1, // StartTrack
> > + PMBR_GPT_PARTITION, // OSIndicator
> > + 0xff, // EndHead
> > + 0xff, // EndSector
> > + 0xff, // EndTrack
> > + { 0x1, 0x0, 0x0, 0x0 }, // StartingLba[4]
> > + { 0xff, 0xff, 0xff, 0xff }, // SizeInLba[4]
> > + },
> > + { 0 }, { 0 }, { 0 }, // Unused partitions
> > + },
> > +
> > + MBR_SIGNATURE // Signature
> > +};
> > +
> > +STATIC UINT32 CurRand = 1;
> > +
> > +/**
> > + Get random seed based on the RTC
> > +
> > +**/
> > +
> > +STATIC
> > +VOID
> > +Srand (VOID)
> > +{
> > + EFI_TIME Time;
> > + UINT32 Seed;
> > + UINT64 MonotonicCount;
> > +
> > + gRT->GetTime (&Time, NULL);
> > + Seed = (~Time.Hour << 24 | Time.Day << 16 | Time.Minute << 8 |
> > Time.Second);
> > + Seed ^= Time.Nanosecond;
> > + Seed ^= Time.Year << 7;
> > +
> > + gBS->GetNextMonotonicCount (&MonotonicCount);
> > + Seed += (UINT32)MonotonicCount;
> > +
> > + /* Store this seed */
> > + CurRand = (UINT32)Seed;
> > +}
> > +
> > +/**
> > + Get a pseudo-random number
> > +
> > + @retval A pseudo-random number in the range 0 - 0x7fff
> > +**/
> > +
> > +STATIC UINTN Rand (VOID)
> > +{
> > + /* return a pseudo-random in range 0 - 0x7fff */
> > + return ((CurRand = CurRand * 214013L + 2531011L) >> 16) & 0x7fff;
> > +}
> > +
> > +/**
> > + Generate a GUID
> > +
> > + @param[in] Guid A pointer to a GUID receiving a generated value
> > +**/
> > +
> > +STATIC VOID
> > +GenerateGuid (OUT GUID *Guid)
> > +{
> > + UINTN Index;
> > + UINT16 Buffer[sizeof(GUID)];
> > +
> > + /* Generates 128 random bits for new UUID */
> > + for (Index = 0; Index < sizeof(GUID); Index++) {
> > + UINTN V;
> > +
> > + V = Rand () >> 7;
> > + Buffer[Index] = (UINT16)V;
> > + }
> > + /* set variant 10x and version 4 as required by RFC 4122 */
> > + Buffer[8] = 0x80 | (Buffer[8] & 0x3f);
> > + Buffer[6] = 0x40 | (Buffer[6] & 0xf);
> > + CopyGuid (Guid, (CONST GUID *)Buffer);
> > +}
> > +
> > +/**
> > + Clean up globals
> > +**/
> > +VOID
> > +GptCleanupGlobals (VOID)
> > +{
> > + SHELL_FREE_NON_NULL (PrimaryHeader);
> > + SHELL_FREE_NON_NULL (BackupHeader);
> > + SHELL_FREE_NON_NULL (PartEntry);
> > + SHELL_FREE_NON_NULL (PEntryStatus);
> > + GptValid = FALSE;
> > + MbrValid = FALSE;
> > +}
> > +
> > +/**
> > + Caution: This function may receive untrusted input.
> > + The GPT partition table header is external input, so this routine
> > + will do basic validation for GPT partition table header before return.
> > +
> > + @param[in] Lba The starting Lba of the Partition Table
> > + @param[out] PartHeader Stores the partition table that is read
> > +
> > + @retval EFI_SUCCESS The partition table is valid
> > + @retval ERROR The partition table is not valid
> > +
> > +**/
> > +STATIC
> > +EFI_STATUS
> > +PartitionValidGptTable (
> > + IN EFI_LBA Lba,
> > + OUT EFI_PARTITION_TABLE_HEADER *PartHeader
> > + );
> > +
> > +/**
> > + Check if the CRC field in the Partition table header is valid
> > + for Partition entry array.
> > +
> > + @param[in] PartHeader Partition table header structure
> > +
> > + @retval TRUE the CRC is valid
> > + @retval FALSE the CRC is invalid
> > +
> > +**/
> > +STATIC
> > +BOOLEAN
> > +PartitionCheckGptEntryArrayCRC (
> > + IN EFI_PARTITION_TABLE_HEADER *PartHeader
> > + );
> > +
> > +
> > +/**
> > + Restore Partition Table to its alternate place
> > + (Primary -> Backup or Backup -> Primary).
> > +
> > + @param[in] PartHeader Partition table header structure.
> > +
> > + @retval TRUE Restoring succeeds
> > + @retval FALSE Restoring failed
> > +
> > +**/
> > +STATIC
> > +BOOLEAN
> > +PartitionRestoreGptTable (
> > + IN EFI_PARTITION_TABLE_HEADER *PartHeader
> > + );
> > +
> > +
> > +/**
> > + This routine will check GPT partition entry and return entry status.
> > +
> > + Caution: This function may receive untrusted input.
> > + The GPT partition entry is external input, so this routine
> > + will do basic validation for GPT partition entry and report status.
> > +
> > + @param[in] PartHeader Partition table header structure
> > + @param[in] PartEntry The partition entry array
> > + @param[out] PEntryStatus the partition entry status array
> > + recording the status of each partition
> > +
> > +**/
> > +STATIC
> > +VOID
> > +PartitionCheckGptEntry (
> > + IN EFI_PARTITION_TABLE_HEADER *PartHeader,
> > + IN EFI_PARTITION_ENTRY *PartEntry,
> > + OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus
> > + );
> > +
> > +
> > +/**
> > + Checks the CRC32 value in the table header.
> > +
> > + @param MaxSize Max Size limit
> > + @param Size The size of the table
> > + @param Hdr Table to check
> > +
> > + @return TRUE CRC Valid
> > + @return FALSE CRC Invalid
> > +
> > +**/
> > +STATIC
> > +BOOLEAN
> > +PartitionCheckCrcAltSize (
> > + IN UINTN MaxSize,
> > + IN UINTN Size,
> > + IN OUT EFI_TABLE_HEADER *Hdr
> > + );
> > +
> > +
> > +/**
> > + Checks the CRC32 value in the table header.
> > +
> > + @param MaxSize Max Size limit
> > + @param Hdr Table to check
> > +
> > + @return TRUE CRC Valid
> > + @return FALSE CRC Invalid
> > +
> > +**/
> > +STATIC
> > +BOOLEAN
> > +PartitionCheckCrc (
> > + IN UINTN MaxSize,
> > + IN OUT EFI_TABLE_HEADER *Hdr
> > + );
> > +
> > +
> > +/**
> > + Updates the CRC32 value in the table header.
> > +
> > + @param Size The size of the table
> > + @param Hdr Table to update
> > +
> > +**/
> > +STATIC
> > +VOID
> > +PartitionSetCrcAltSize (
> > + IN UINTN Size,
> > + IN OUT EFI_TABLE_HEADER *Hdr
> > + );
> > +
> > +
> > +/**
> > + Updates the CRC32 value in the table header.
> > +
> > + @param Hdr Table to update
> > +
> > +**/
> > +STATIC
> > +VOID
> > +PartitionSetCrc (
> > + IN OUT EFI_TABLE_HEADER *Hdr
> > + );
> > +
> > +
> > +/**
> > + Get GPT tables.
> > +
> > + Caution: This function may receive untrusted input.
> > + The GPT partition table is external input, so this routine
> > + will do basic validation for GPT partition table before install
> > + child handle for each GPT partition.
> > +
> > + @param[in] DiskIoProt DiskIo interface.
> > + @param[in] BlockIoProt BlockIo interface.
> > +
> > + @retval EFI_SUCCESS Valid GPT disk.
> > + @retval EFI_MEDIA_CHANGED Media changed Detected.
> > + @retval other Not a valid GPT disk.
> > +
> > +**/
> > +EFI_STATUS
> > +PartitionGetGptTables (
> > + IN EFI_DISK_IO_PROTOCOL *DiskIoProt,
> > + IN EFI_BLOCK_IO_PROTOCOL *BlockIoProt
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINT32 BlockSize;
> > + EFI_LBA LastBlock;
> > + UINTN Index;
> > + EFI_STATUS GptValidStatus;
> > + UINT32 MediaId;
> > + MASTER_BOOT_RECORD *ProtectiveMbr;
> > +
> > + // Clear leftovers
> > + GptCleanupGlobals ();
> > +
> > + MbrValid = FALSE;
> > + GptValid = FALSE;
> > +
> > + ProtectiveMbr = NULL;
> > +
> > + BlockIo = BlockIoProt;
> > + DiskIo = DiskIoProt;
> > +
> > + if (CurRand == 1) {
> > + Srand ();
> > + }
> > +
> > + BlockSize = BlockIo->Media->BlockSize;
> > + LastBlock = BlockIo->Media->LastBlock;
> > + MediaId = BlockIo->Media->MediaId;
> > +
> > + DEBUG ((EFI_D_VERBOSE, " BlockSize : %d \n", BlockSize));
> > + DEBUG ((EFI_D_VERBOSE, " LastBlock : %lx \n", LastBlock));
> > +
> > + GptValidStatus = EFI_NOT_FOUND;
> > + GptValid = FALSE;
> > + MbrValid = FALSE;
> > +
> > + //
> > + // Allocate a buffer for the Protective MBR
> > + //
> > + ProtectiveMbr = AllocatePool (BlockSize);
> > + if (ProtectiveMbr == NULL) {
> > + return EFI_OUT_OF_RESOURCES;
> > + }
> > +
> > + //
> > + // Read the Protective MBR from LBA #0
> > + //
> > + Status = DiskIo->ReadDisk (
> > + DiskIo,
> > + MediaId,
> > + 0,
> > + BlockSize,
> > + ProtectiveMbr
> > + );
> > + if (EFI_ERROR (Status)) {
> > + GptValidStatus = Status;
> > + goto Done;
> > + }
> > +
> > + //
> > + // Verify that the Protective MBR is valid
> > + //
> > + for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
> > + if (ProtectiveMbr->Partition[Index].BootIndicator == 0x00 &&
> > + ProtectiveMbr->Partition[Index].OSIndicator ==
> > PMBR_GPT_PARTITION &&
> > + UNPACK_UINT32 (ProtectiveMbr->Partition[Index].StartingLBA) == 1
> > + ) {
> > + break;
> > + }
> > + }
> > + if (Index == MAX_MBR_PARTITIONS) {
> > + goto Done;
> > + }
> > +
> > + MbrValid = TRUE;
> > +
> > + //
> > + // Allocate the GPT structures
> > + //
> > + PrimaryHeader = AllocateZeroPool
> > (sizeof(EFI_PARTITION_TABLE_HEADER));
> > + if (PrimaryHeader == NULL) {
> > + goto Done;
> > + }
> > +
> > + BackupHeader = AllocateZeroPool
> > (sizeof(EFI_PARTITION_TABLE_HEADER));
> > + if (BackupHeader == NULL) {
> > + goto Done;
> > + }
> > +
> > + //
> > + // Check primary and backup partition tables
> > + //
> > + Status = PartitionValidGptTable (PRIMARY_PART_HEADER_LBA,
> > PrimaryHeader);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((EFI_D_INFO, " Not Valid primary partition table\n"));
> > +
> > + Status = PartitionValidGptTable (LastBlock, BackupHeader);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((EFI_D_INFO, " Not Valid backup partition table\n"));
> > + goto Done;
> > + } else {
> > + DEBUG ((EFI_D_INFO, " Valid backup partition table\n"));
> > + DEBUG ((EFI_D_INFO, " Restore primary partition table by the
> > backup\n"));
> > + if (!PartitionRestoreGptTable (BackupHeader)) {
> > + DEBUG ((EFI_D_INFO, " Restore primary partition table error\n"));
> > + }
> > +
> > + Status = PartitionValidGptTable (BackupHeader->AlternateLBA,
> > PrimaryHeader);
> > + if (!EFI_ERROR (Status)) {
> > + DEBUG ((EFI_D_INFO, " Restore backup partition table success\n"));
> > + }
> > + }
> > + } else if (EFI_ERROR (PartitionValidGptTable (PrimaryHeader-
> > >AlternateLBA, BackupHeader))) {
> > + DEBUG ((EFI_D_INFO, " Valid primary and !Valid backup partition
> > table\n"));
> > + DEBUG ((EFI_D_INFO, " Restore backup partition table by the
> > primary\n"));
> > + if (!PartitionRestoreGptTable (PrimaryHeader)) {
> > + DEBUG ((EFI_D_INFO, " Restore backup partition table error\n"));
> > + }
> > +
> > + Status = PartitionValidGptTable (PrimaryHeader->AlternateLBA,
> > BackupHeader);
> > + if (!EFI_ERROR (Status)) {
> > + DEBUG ((EFI_D_INFO, " Restore backup partition table success\n"));
> > + }
> > + }
> > +
> > + DEBUG ((EFI_D_VERBOSE, " Valid primary and Valid backup partition
> > table\n"));
> > +
> > + //
> > + // Read the EFI Partition Entries
> > + //
> > + PartEntry = AllocatePool (PrimaryHeader->NumberOfPartitionEntries *
> > PrimaryHeader->SizeOfPartitionEntry);
> > + if (PartEntry == NULL) {
> > + DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
> > + goto Done;
> > + }
> > +
> > + Status = DiskIo->ReadDisk (
> > + DiskIo,
> > + MediaId,
> > + MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockSize),
> > + PrimaryHeader->NumberOfPartitionEntries * (PrimaryHeader-
> > >SizeOfPartitionEntry),
> > + PartEntry
> > + );
> > + if (EFI_ERROR (Status)) {
> > + GptValidStatus = Status;
> > + DEBUG ((EFI_D_ERROR, " Partition Entry ReadDisk error\n"));
> > + goto Done;
> > + }
> > +
> > + DEBUG ((EFI_D_VERBOSE, " Partition entries read block success\n"));
> > +
> > + DEBUG ((EFI_D_VERBOSE, " Number of partition entries: %d\n",
> > PrimaryHeader->NumberOfPartitionEntries));
> > +
> > + PEntryStatus = AllocateZeroPool (PrimaryHeader-
> > >NumberOfPartitionEntries * sizeof(EFI_PARTITION_ENTRY_STATUS));
> > + if (PEntryStatus == NULL) {
> > + DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
> > + goto Done;
> > + }
> > +
> > + //
> > + // Check the integrity of partition entries
> > + //
> > + PartitionCheckGptEntry (PrimaryHeader, PartEntry, PEntryStatus);
> > +
> > + //
> > + // If we got this far the GPT layout of the disk is valid and we should
> return
> > true
> > + //
> > + GptValidStatus = EFI_SUCCESS;
> > +
> > + Done:
> > + SHELL_FREE_NON_NULL (ProtectiveMbr);
> > + if (EFI_ERROR (GptValidStatus)) {
> > + SHELL_FREE_NON_NULL (PrimaryHeader);
> > + SHELL_FREE_NON_NULL (BackupHeader);
> > + SHELL_FREE_NON_NULL (PartEntry);
> > + SHELL_FREE_NON_NULL (PEntryStatus);
> > + } else {
> > + GptValid = TRUE;
> > + }
> > +
> > + return GptValidStatus;
> > +}
> > +
> > +/**
> > + This routine will read GPT partition table header and return it.
> > +
> > + Caution: This function may receive untrusted input.
> > + The GPT partition table header is external input, so this routine
> > + will do basic validation for GPT partition table header before return.
> > +
> > + @param[in] Lba The starting Lba of the Partition Table
> > + @param[out] PartHeader Stores the partition table that is read
> > +
> > + @retval TRUE The partition table is valid
> > + @retval FALSE The partition table is not valid
> > +
> > +**/
> > +STATIC
> > +EFI_STATUS
> > +PartitionValidGptTable (
> > + IN EFI_LBA Lba,
> > + OUT EFI_PARTITION_TABLE_HEADER *PartHeader
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINT32 BlockSize;
> > + EFI_PARTITION_TABLE_HEADER *PartHdr;
> > + UINT32 MediaId;
> > +
> > + BlockSize = BlockIo->Media->BlockSize;
> > + MediaId = BlockIo->Media->MediaId;
> > + PartHdr = AllocateZeroPool (BlockSize);
> > +
> > + if (PartHdr == NULL) {
> > + DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
> > + return EFI_OUT_OF_RESOURCES;
> > + }
> > + //
> > + // Read the EFI Partition Table Header
> > + //
> > + Status = DiskIo->ReadDisk (
> > + DiskIo,
> > + MediaId,
> > + MultU64x32 (Lba, BlockSize),
> > + BlockSize,
> > + PartHdr
> > + );
> > + if (EFI_ERROR (Status)) {
> > + FreePool (PartHdr);
> > + return Status;
> > + }
> > +
> > + if ((PartHdr->Header.Signature != EFI_PTAB_HEADER_ID) ||
> > + !PartitionCheckCrc (BlockSize, &PartHdr->Header) ||
> > + PartHdr->MyLBA != Lba ||
> > + (PartHdr->SizeOfPartitionEntry < sizeof(EFI_PARTITION_ENTRY))
> > + ) {
> > + DEBUG ((EFI_D_ERROR, "Invalid efi partition table header\n"));
> > + FreePool (PartHdr);
> > + return EFI_VOLUME_CORRUPTED;
> > + }
> > +
> > + //
> > + // Ensure the NumberOfPartitionEntries * SizeOfPartitionEntry doesn't
> > overflow.
> > + //
> > + if (PartHdr->NumberOfPartitionEntries > DivU64x32 (MAX_UINTN,
> > PartHdr->SizeOfPartitionEntry)) {
> > + FreePool (PartHdr);
> > + return EFI_VOLUME_CORRUPTED;
> > + }
> > +
> > + CopyMem (PartHeader, PartHdr,
> sizeof(EFI_PARTITION_TABLE_HEADER));
> > + if (!PartitionCheckGptEntryArrayCRC (PartHeader)) {
> > + FreePool (PartHdr);
> > + return EFI_VOLUME_CORRUPTED;
> > + }
> > +
> > + DEBUG ((EFI_D_VERBOSE, " Valid efi partition table header\n"));
> > + FreePool (PartHdr);
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + Check if the CRC field in the Partition table header is valid
> > + for Partition entry array.
> > +
> > + @param[in] PartHeader Partition table header structure
> > +
> > + @retval TRUE the CRC is valid
> > + @retval FALSE the CRC is invalid
> > +
> > +**/
> > +STATIC
> > +BOOLEAN
> > +PartitionCheckGptEntryArrayCRC (
> > + IN EFI_PARTITION_TABLE_HEADER *PartHeader
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINT8 *Ptr;
> > + UINT32 Crc;
> > + UINTN Size;
> > +
> > + //
> > + // Read the EFI Partition Entries
> > + //
> > + Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries *
> PartHeader-
> > >SizeOfPartitionEntry);
> > + if (Ptr == NULL) {
> > + DEBUG ((EFI_D_ERROR, " Allocate pool error\n"));
> > + return FALSE;
> > + }
> > +
> > + Status = DiskIo->ReadDisk (
> > + DiskIo,
> > + BlockIo->Media->MediaId,
> > + MultU64x32 (PartHeader->PartitionEntryLBA, BlockIo->Media-
> >BlockSize),
> > + PartHeader->NumberOfPartitionEntries * PartHeader-
> > >SizeOfPartitionEntry,
> > + Ptr
> > + );
> > + if (EFI_ERROR (Status)) {
> > + FreePool (Ptr);
> > + return FALSE;
> > + }
> > +
> > + Size = PartHeader->NumberOfPartitionEntries * PartHeader-
> > >SizeOfPartitionEntry;
> > +
> > + Status = gBS->CalculateCrc32 (Ptr, Size, &Crc);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((EFI_D_ERROR, "CheckPEntryArrayCRC: Crc calculation
> failed\n"));
> > + FreePool (Ptr);
> > + return FALSE;
> > + }
> > +
> > + FreePool (Ptr);
> > +
> > + return (BOOLEAN)(PartHeader->PartitionEntryArrayCRC32 == Crc);
> > +}
> > +
> > +
> > +/**
> > + Restore Partition Table to its alternate place
> > + (Primary -> Backup or Backup -> Primary).
> > +
> > + @param[in] PartHeader Partition table header structure.
> > +
> > + @retval TRUE Restoring succeeds
> > + @retval FALSE Restoring failed
> > +
> > +**/
> > +STATIC
> > +BOOLEAN
> > +PartitionRestoreGptTable (
> > + IN EFI_PARTITION_TABLE_HEADER *PartHeader
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINTN BlockSize;
> > + EFI_PARTITION_TABLE_HEADER *PartHdr;
> > + EFI_LBA PEntryLBA;
> > + UINT8 *Ptr;
> > + UINT32 MediaId;
> > +
> > + PartHdr = NULL;
> > + Ptr = NULL;
> > +
> > + BlockSize = BlockIo->Media->BlockSize;
> > + MediaId = BlockIo->Media->MediaId;
> > +
> > + PartHdr = AllocateZeroPool (BlockSize);
> > +
> > + if (PartHdr == NULL) {
> > + DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
> > + return FALSE;
> > + }
> > +
> > + PEntryLBA = (PartHeader->MyLBA == PRIMARY_PART_HEADER_LBA) ?\
> > + (PartHeader->LastUsableLBA + 1) :\
> > + (PRIMARY_PART_HEADER_LBA + 1);
> > +
> > + CopyMem (PartHdr, PartHeader,
> sizeof(EFI_PARTITION_TABLE_HEADER));
> > +
> > + PartHdr->MyLBA = PartHeader->AlternateLBA;
> > + PartHdr->AlternateLBA = PartHeader->MyLBA;
> > + PartHdr->PartitionEntryLBA = PEntryLBA;
> > + PartitionSetCrc ((EFI_TABLE_HEADER *)PartHdr);
> > +
> > + Status = DiskIo->WriteDisk (
> > + DiskIo,
> > + MediaId,
> > + MultU64x32 (PartHdr->MyLBA, (UINT32)BlockSize),
> > + BlockSize,
> > + PartHdr
> > + );
> > + if (EFI_ERROR (Status)) {
> > + goto Done;
> > + }
> > +
> > + Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries *
> PartHeader-
> > >SizeOfPartitionEntry);
> > + if (Ptr == NULL) {
> > + DEBUG ((EFI_D_ERROR, " Allocate pool error\n"));
> > + Status = EFI_OUT_OF_RESOURCES;
> > + goto Done;
> > + }
> > +
> > + Status = DiskIo->ReadDisk (
> > + DiskIo,
> > + MediaId,
> > + MultU64x32 (PartHeader->PartitionEntryLBA, (UINT32)BlockSize),
> > + PartHeader->NumberOfPartitionEntries * PartHeader-
> > >SizeOfPartitionEntry,
> > + Ptr
> > + );
> > + if (EFI_ERROR (Status)) {
> > + goto Done;
> > + }
> > +
> > + Status = DiskIo->WriteDisk (
> > + DiskIo,
> > + MediaId,
> > + MultU64x32 (PEntryLBA, (UINT32)BlockSize),
> > + PartHeader->NumberOfPartitionEntries * PartHeader-
> > >SizeOfPartitionEntry,
> > + Ptr
> > + );
> > +
> > + Done:
> > + FreePool (PartHdr);
> > +
> > + if (Ptr != NULL) {
> > + FreePool (Ptr);
> > + }
> > +
> > + if (EFI_ERROR (Status)) {
> > + return FALSE;
> > + }
> > +
> > + return TRUE;
> > +}
> > +
> > +/**
> > + This routine will check GPT partition entry and return entry status.
> > +
> > + Caution: This function may receive untrusted input.
> > + The GPT partition entry is external input, so this routine
> > + will do basic validation for GPT partition entry and report status.
> > +
> > + @param[in] PartHeader Partition table header structure
> > + @param[in] PartEntry The partition entry array
> > + @param[out] PEntryStatus the partition entry status array
> > + recording the status of each partition
> > +
> > +**/
> > +STATIC
> > +VOID
> > +PartitionCheckGptEntry (
> > + IN EFI_PARTITION_TABLE_HEADER *PartHeader,
> > + IN EFI_PARTITION_ENTRY *PartEntry,
> > + OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus
> > + )
> > +{
> > + EFI_LBA StartingLBA;
> > + EFI_LBA EndingLBA;
> > + EFI_PARTITION_ENTRY *Entry;
> > + UINTN Index1;
> > + UINTN Index2;
> > +
> > + DEBUG ((EFI_D_VERBOSE, " start check partition entries\n"));
> > + for (Index1 = 0; Index1 < PartHeader->NumberOfPartitionEntries;
> > Index1++) {
> > + Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index1 *
> > PartHeader->SizeOfPartitionEntry);
> > + if (CompareGuid (&Entry->PartitionTypeGUID,
> > &gEfiPartTypeUnusedGuid)) {
> > + continue;
> > + }
> > +
> > + StartingLBA = Entry->StartingLBA;
> > + EndingLBA = Entry->EndingLBA;
> > + if (StartingLBA > EndingLBA ||
> > + StartingLBA < PartHeader->FirstUsableLBA ||
> > + StartingLBA > PartHeader->LastUsableLBA ||
> > + EndingLBA < PartHeader->FirstUsableLBA ||
> > + EndingLBA > PartHeader->LastUsableLBA
> > + ) {
> > + PEntryStatus[Index1].OutOfRange = TRUE;
> > + continue;
> > + }
> > +
> > + if ((Entry->Attributes & BIT1) != 0) {
> > + //
> > + // If Bit 1 is set, this indicate that this is an OS specific GUID partition.
> > + //
> > + PEntryStatus[Index1].OsSpecific = TRUE;
> > + }
> > +
> > + for (Index2 = Index1 + 1; Index2 < PartHeader-
> > >NumberOfPartitionEntries; Index2++) {
> > + Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index2 *
> > PartHeader->SizeOfPartitionEntry);
> > + if (CompareGuid (&Entry->PartitionTypeGUID,
> > &gEfiPartTypeUnusedGuid)) {
> > + continue;
> > + }
> > +
> > + if (Entry->EndingLBA >= StartingLBA && Entry->StartingLBA <=
> EndingLBA)
> > {
> > + //
> > + // This region overlaps with the Index1'th region
> > + //
> > + PEntryStatus[Index1].Overlap = TRUE;
> > + PEntryStatus[Index2].Overlap = TRUE;
> > + continue;
> > + }
> > + }
> > + }
> > +
> > + DEBUG ((EFI_D_VERBOSE, " End check partition entries\n"));
> > +}
> > +
> > +
> > +/**
> > + Updates the CRC32 value in the table header.
> > +
> > + @param Hdr Table to update
> > +
> > +**/
> > +STATIC
> > +VOID
> > +PartitionSetCrc (
> > + IN OUT EFI_TABLE_HEADER *Hdr
> > + )
> > +{
> > + PartitionSetCrcAltSize (Hdr->HeaderSize, Hdr);
> > +}
> > +
> > +
> > +/**
> > + Updates the CRC32 value in the table header.
> > +
> > + @param Size The size of the table
> > + @param Hdr Table to update
> > +
> > +**/
> > +STATIC
> > +VOID
> > +PartitionSetCrcAltSize (
> > + IN UINTN Size,
> > + IN OUT EFI_TABLE_HEADER *Hdr
> > + )
> > +{
> > + UINT32 Crc;
> > +
> > + Hdr->CRC32 = 0;
> > + gBS->CalculateCrc32 ((UINT8 *)Hdr, Size, &Crc);
> > + Hdr->CRC32 = Crc;
> > +}
> > +
> > +
> > +/**
> > + Checks the CRC32 value in the table header.
> > +
> > + @param MaxSize Max Size limit
> > + @param Hdr Table to check
> > +
> > + @return TRUE CRC Valid
> > + @return FALSE CRC Invalid
> > +
> > +**/
> > +STATIC
> > +BOOLEAN
> > +PartitionCheckCrc (
> > + IN UINTN MaxSize,
> > + IN OUT EFI_TABLE_HEADER *Hdr
> > + )
> > +{
> > + return PartitionCheckCrcAltSize (MaxSize, Hdr->HeaderSize, Hdr);
> > +}
> > +
> > +
> > +/**
> > + Checks the CRC32 value in the table header.
> > +
> > + @param MaxSize Max Size limit
> > + @param Size The size of the table
> > + @param Hdr Table to check
> > +
> > + @return TRUE CRC Valid
> > + @return FALSE CRC Invalid
> > +
> > +**/
> > +STATIC
> > +BOOLEAN
> > +PartitionCheckCrcAltSize (
> > + IN UINTN MaxSize,
> > + IN UINTN Size,
> > + IN OUT EFI_TABLE_HEADER *Hdr
> > + )
> > +{
> > + UINT32 Crc;
> > + UINT32 OrgCrc;
> > + EFI_STATUS Status;
> > +
> > + Crc = 0;
> > +
> > + if (Size == 0) {
> > + //
> > + // If header size is 0 CRC will pass so return FALSE here
> > + //
> > + return FALSE;
> > + }
> > +
> > + if ((MaxSize != 0) && (Size > MaxSize)) {
> > + DEBUG ((EFI_D_ERROR, "CheckCrc32: Size > MaxSize\n"));
> > + return FALSE;
> > + }
> > + //
> > + // clear old crc from header
> > + //
> > + OrgCrc = Hdr->CRC32;
> > + Hdr->CRC32 = 0;
> > +
> > + Status = gBS->CalculateCrc32 ((UINT8 *)Hdr, Size, &Crc);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc calculation failed\n"));
> > + return FALSE;
> > + }
> > + //
> > + // set results
> > + //
> > + Hdr->CRC32 = Crc;
> > +
> > + //
> > + // return status
> > + //
> > + DEBUG_CODE_BEGIN ();
> > + if (OrgCrc != Crc) {
> > + DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc check failed\n"));
> > + }
> > + DEBUG_CODE_END ();
> > +
> > + return (BOOLEAN)(OrgCrc == Crc);
> > +}
> > +
> > +/**
> > + Converts a GUID into a unicode string.
> > +
> > + @param [in] Guid A GUID to be converted
> > + @param [out] Buffer A pointer to a buffer receiving the string
> > + @param [in] BufferSize Size of the buffer
> > +
> > + @return EFI_SUCCESS Successful conversion
> > + @return EFI_INVALID_PARAMETER Conversion failed
> > +
> > +**/
> > +
> > +STATIC
> > +EFI_STATUS
> > +GuidToString (
> > + IN EFI_GUID *Guid,
> > + OUT CHAR16 *Buffer,
> > + IN UINTN BufferSize
> > + )
> > +{
> > + UINTN Size;
> > + EFI_STATUS Status;
> > +
> > + Status = EFI_SUCCESS;
> > +
> > + Size = UnicodeSPrint (
> > + Buffer,
> > + BufferSize,
> > + L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
> > + (UINTN)Guid->Data1,
> > + (UINTN)Guid->Data2,
> > + (UINTN)Guid->Data3,
> > + (UINTN)Guid->Data4[0],
> > + (UINTN)Guid->Data4[1],
> > + (UINTN)Guid->Data4[2],
> > + (UINTN)Guid->Data4[3],
> > + (UINTN)Guid->Data4[4],
> > + (UINTN)Guid->Data4[5],
> > + (UINTN)Guid->Data4[6],
> > + (UINTN)Guid->Data4[7]
> > + );
> > + if (!Size) {
> > + Status = EFI_INVALID_PARAMETER;
> > + }
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Get a string representation of a known
> > + partition type GUID. If partition GUID is not
> > + known, gets a string representation of the GUID
> > +
> > + @param GUID Guid to be searched for
> > + @param PartTypeStr Buffer receiving the string
> > + @param NoGuidStr Do not convert GUID to string
> > + for an unknown partition type
> > +
> > + @return EFI_SUCCESS GUID type is known
> > + @return EFI_NOT_FOUND Unknown GUID partition type
> > +
> > +**/
> > +EFI_STATUS
> > +GetPartitionTypeStr (
> > + IN EFI_GUID Guid,
> > + OUT CHAR16 *PartTypeStr,
> > + IN BOOLEAN NoGuidStr)
> > +{
> > + UINTN Index;
> > + EFI_STATUS Status;
> > +
> > + Status = EFI_SUCCESS;
> > + for (Index = 0; Index < ARRAY_SIZE (PartitionTypes); Index++) {
> > + if (CompareGuid (&Guid, &PartitionTypes[Index].TypeGuid)) {
> > + StrnCpy (PartTypeStr, PartitionTypes[Index].TypeName,
> > MAX_PARTITION_NAME_LENGTH);
> > + return Status;
> > + }
> > + }
> > + if (!NoGuidStr) {
> > + GuidToString (&Guid, PartTypeStr, (MAX_PARTITION_NAME_LENGTH +
> 1)
> > * sizeof(CHAR16));
> > + }
> > + return EFI_NOT_FOUND;
> > +}
> > +
> > +/**
> > + Lists partitions on a block device.
> > +
> > + @return Number of partitions used
> > +**/
> > +
> > +UINTN
> > +PartitionListGptEntries (VOID)
> > +{
> > + UINTN Index;
> > + EFI_PARTITION_ENTRY *Entry;
> > + EFI_LBA Length;
> > + UINTN NumEntries; // Used entries
> > + UINTN BlockSize;
> > + BOOLEAN FirstTime;
> > + UINT64 BlocksOccupied;
> > +
> > + NumEntries = 0;
> > + BlockSize = BlockIo->Media->BlockSize;
> > + FirstTime = TRUE;
> > +
> > + if (!GptValid) {
> > + return 0;
> > + }
> > +
> > + BlocksOccupied = 0;
> > +
> > + for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries;
> > Index++) {
> > +
> > + BOOLEAN Specific;
> > + CHAR16 PartTypeStr[MAX_PARTITION_NAME_LENGTH + 1];
> > +
> > + Specific = FALSE;
> > +
> > + Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index *
> > PrimaryHeader->SizeOfPartitionEntry);
> > +
> > + Length = Entry->EndingLBA - Entry->StartingLBA + 1;
> > +
> > + if (CompareGuid (&Entry->PartitionTypeGUID,
> > &gEfiPartTypeUnusedGuid)) {
> > + continue;
> > + }
> > +
> > + if (FirstTime) {
> > + Print (L" No \t%-36s\tStart (LBA)\tEnd (LBA)\tSize (MiB)\t Partition
> > Type\r\n", L"Name");
> > + Print (L" ---- -------------------------------------- ----------- ----------- ---
> --
> > ----- -------------------------------\r\n");
> > + FirstTime = FALSE;
> > + }
> > + NumEntries++;
> > + if (PEntryStatus[Index].OutOfRange ||
> > + PEntryStatus[Index].Overlap ||
> > + PEntryStatus[Index].OsSpecific) {
> > + Specific = TRUE;
> > + }
> > +
> > + BlocksOccupied += Length;
> > +
> > + GetPartitionTypeStr (Entry->PartitionTypeGUID, (CHAR16
> *)&PartTypeStr,
> > FALSE);
> > +
> > + Print (L"%1s %-3d\t%-36s\t0x%09llx\t0x%09llx\t%06llu\t %s\r\n",
> > + Specific ? L"S" : L"",
> > + Index + 1,
> > + Entry->PartitionName,
> > + (UINT64)Entry->StartingLBA,
> > + (UINT64)Entry->EndingLBA,
> > + (MultU64x32 (Length, BlockSize)) >> 20,
> > + PartTypeStr);
> > + }
> > +
> > + // This code block is to provide additional info
> > + {
> > + UINT64 DiskSizeMiB, SizeOccupiedMiB;
> > +
> > + DiskSizeMiB = MultU64x32 (PrimaryHeader->LastUsableLBA -
> > PrimaryHeader->FirstUsableLBA + 1, BlockIo->Media->BlockSize) >> 20;
> > + SizeOccupiedMiB = MultU64x32 (BlocksOccupied, BlockIo->Media-
> > >BlockSize) >> 20;
> > + Print (L"\r\n%d partition(s) used out of %d\r\n", NumEntries,
> > PrimaryHeader->NumberOfPartitionEntries);
> > + Print (L"Total device capacity (minus GPT service blocks): %llu
> > MiB\r\nPartitioned space: %llu MiB\r\n",
> > + DiskSizeMiB,
> > + SizeOccupiedMiB);
> > + Print (L"Unpartitioned space available: %llu MiB (%d%%)\n",
> > + DiskSizeMiB - SizeOccupiedMiB,
> > + (100 * (DiskSizeMiB - SizeOccupiedMiB)) / DiskSizeMiB);
> > + }
> > +
> > + return NumEntries;
> > +}
> > +
> > +/**
> > + Locate a partition by criteria
> > +
> > + @param Name Partition name (or ordinal represented a string)
> > + @param StartLba StartLba of the partition to search for
> > + @param EndingLba EndingLba of the partition to search for
> > + @param SearchType A combination (OR) of search options.
> > + Options are:
> > + SRC_BY_NAME = search by partition name
> > + SRC_BY_LBA = search by Start/Ending lba
> > + SRC_ANY = returns a first used partition
> > + SRC_BY_NUM = search by ordinal
> > +
> > +
> > + @return Non-NULL Pointer to th partition found
> > + @return NULL No partition found
> > +
> > +**/
> > +EFI_PARTITION_ENTRY *
> > +PartitionFindPartitionByCriteria (
> > + IN OPTIONAL CONST CHAR16 *Name,
> > + IN OPTIONAL EFI_LBA StartLba,
> > + IN OPTIONAL EFI_LBA EndingLba,
> > + IN SEARCH_TYPE SearchType
> > + )
> > +{
> > + UINTN Index;
> > + EFI_PARTITION_ENTRY *Entry;
> > +
> > + if (!GptValid) {
> > + return NULL;
> > + }
> > +
> > + if (!Name && (SearchType & SRC_BY_NAME)) {
> > + return NULL;
> > + }
> > +
> > + for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries;
> > Index++) {
> > + Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index *
> > PrimaryHeader->SizeOfPartitionEntry);
> > +
> > + if (CompareGuid (&Entry->PartitionTypeGUID,
> > &gEfiPartTypeUnusedGuid)) {
> > + continue;
> > + }
> > +
> > + if (SearchType & SRC_ANY) {
> > + return Entry;
> > + }
> > +
> > + if (SearchType & SRC_BY_NAME) {
> > + if (!StrCmp (Name, Entry->PartitionName)) {
> > + return Entry;
> > + }
> > + }
> > + if (SearchType & SRC_BY_NUM) {
> > + UINTN Ordinal;
> > +
> > + Ordinal = ShellStrToUintn (Name);
> > + if (Index == (Ordinal - 1)) {
> > + return Entry;
> > + }
> > + }
> > + if (SearchType & SRC_BY_LBA) {
> > + if (
> > + ((StartLba >= Entry->StartingLBA) &&
> > + (StartLba <= Entry->EndingLBA)
> > + ) ||
> > + ((EndingLba >= Entry->StartingLBA) &&
> > + (EndingLba <= Entry->EndingLBA)
> > + )
> > + ) {
> > + return Entry;
> > + }
> > + }
> > + }
> > + return NULL;
> > +}
> > +
> > +/**
> > + Prints information on a given partition.
> > +
> > + @param Entry Pointer to the Partition of interest
> > +**/
> > +
> > +VOID
> > +PartitionPrintGptPartInfo (
> > + IN EFI_PARTITION_ENTRY *Entry
> > + )
> > +{
> > + CONST CHAR16 PartStr[MAX_PARTITION_NAME_LENGTH + 1] = { L'\0' };
> > + CONST CHAR16 *StrUnknown = L"Unknown";
> > + EFI_STATUS Status;
> > + EFI_LBA Length;
> > +
> > + ASSERT (Entry);
> > +
> > + Status = GetPartitionTypeStr (Entry->PartitionTypeGUID, (CHAR16
> > *)&PartStr, TRUE);
> > + if (EFI_ERROR (Status)) {
> > + StrCpy ((CHAR16 *)&PartStr, StrUnknown);
> > + }
> > +
> > + Length = Entry->EndingLBA - Entry->StartingLBA + 1;
> > +
> > + Print (L"Partition name: %s\r\n", Entry->PartitionName);
> > + Print (L"Starting LBA : 0x%09llx\r\nEnding LBA : 0x%09llx\r\n",
> > + (UINT64)Entry->StartingLBA, (UINT64)Entry->EndingLBA);
> > + Print (L"Partition Size: %llu MiB (0x%llx blocks)\n",
> > + (MultU64x32 (Length, BlockIo->Media->BlockSize)) >> 20, Length);
> > + Print (L"Attributes : 0x%09llx\r\n", Entry->Attributes);
> > + Print (L"Type/GUID : %s/%g\r\n", PartStr, &Entry->PartitionTypeGUID);
> > + Print (L"Unique GUID : %g\n", &Entry->UniquePartitionGUID);
> > +}
> > +
> > +
> > +/**
> > + Writes protective MBR to a block device.
> > +
> > + @return EFI_SUCCESS MBR written successfully
> > + @return other Failed to write an MBR
> > +
> > +**/
> > +
> > +STATIC
> > +EFI_STATUS
> > +WriteProtectiveMbr (
> > + VOID
> > + )
> > +{
> > + UINT32 BlockSize;
> > + UINT64 DiskSize;
> > + EFI_STATUS Status;
> > + MBR_PARTITION_RECORD *Partition;
> > + MASTER_BOOT_RECORD *ProtectiveMbr;
> > +
> > + BlockSize = BlockIo->Media->BlockSize;
> > +
> > + ProtectiveMbr = NULL;
> > + ProtectiveMbr = AllocateZeroPool (BlockSize);
> > + if (ProtectiveMbr == NULL) {
> > + return EFI_OUT_OF_RESOURCES;
> > + }
> > +
> > + DiskSize = BlockIo->Media->LastBlock + 1;
> > + if (DiskSize > 0xffffffff) {
> > + DiskSize = 0xffffffff;
> > + }
> > +
> > + CopyMem (ProtectiveMbr, &ProtectiveMbrTemplate,
> > sizeof(MASTER_BOOT_RECORD));
> > +
> > + Partition = &ProtectiveMbr->Partition[0];
> > +
> > + Partition->BootIndicator = 0;
> > + Partition->StartSector = 1;
> > +
> > + //
> > + // We don't actually know this data, so we'll make up
> > + // something that seems likely.
> > + //
> > +
> > + //
> > + // Old software is expecting the Partition to start on
> > + // a Track boundary, so we'll set track to 1 to avoid "overlay"
> > + // with the MBR
> > + //
> > +
> > + Partition->StartTrack = 1;
> > +
> > + Status = DiskIo->WriteDisk (
> > + DiskIo,
> > + BlockIo->Media->MediaId,
> > + 0,
> > + BlockSize,
> > + ProtectiveMbr
> > + );
> > +
> > + MbrValid = !EFI_ERROR (Status);
> > +
> > + SHELL_FREE_NON_NULL (ProtectiveMbr);
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Write GPT tables to the block device.
> > +
> > + @return EFI_SUCCESS GPT tables were successfully written/updated
> > + @return other Failed to write/update GPT tables
> > +
> > +**/
> > +
> > +STATIC
> > +EFI_STATUS
> > +WriteGPT (
> > + VOID
> > + )
> > +/*
> > + CALLER is expected to fill in:
> > + FirstUseableLBA
> > + LastUseableLBA
> > + EntryCount
> > + DiskGUID
> > +
> > + We fill in the rest, and blast it out.
> > +
> > + Returns a status.
> > +
> > +*/
> > +{
> > + UINT32 BlockSize;
> > + UINT32 TableSize;
> > + EFI_STATUS Status = EFI_SUCCESS;
> > +
> > + BlockSize = BlockIo->Media->BlockSize;
> > + TableSize = PrimaryHeader->NumberOfPartitionEntries *
> > sizeof(EFI_PARTITION_ENTRY);
> > +
> > + if (!MbrValid) {
> > + WriteProtectiveMbr ();
> > + }
> > + //
> > + // Write out the primary header...
> > + //
> > + PrimaryHeader->Header.Signature = EFI_PTAB_HEADER_ID;
> > + PrimaryHeader->Header.Revision = GPT_REVISION_1_0;
> > + PrimaryHeader->Header.HeaderSize =
> > sizeof(EFI_PARTITION_TABLE_HEADER);
> > +
> > + PrimaryHeader->AlternateLBA = BackupHeader->MyLBA;
> > +
> > + PrimaryHeader->SizeOfPartitionEntry = sizeof(EFI_PARTITION_ENTRY);
> > +
> > + Status = gBS->CalculateCrc32 ((UINT8 *)PartEntry, TableSize,
> > &PrimaryHeader->PartitionEntryArrayCRC32);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + // Write primary header
> > + PartitionSetCrc (&PrimaryHeader->Header);
> > +
> > + Status = DiskIo->WriteDisk (
> > + DiskIo,
> > + BlockIo->Media->MediaId,
> > + MultU64x32 (PrimaryHeader->MyLBA, (UINT32)BlockSize),
> > + BlockSize,
> > + PrimaryHeader
> > + );
> > +
> > +
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + //
> > + // Write out the primary table ...
> > + //
> > + Status = DiskIo->WriteDisk (
> > + DiskIo,
> > + BlockIo->Media->MediaId,
> > + MultU64x32 (PrimaryHeader->PartitionEntryLBA, (UINT32)BlockSize),
> > + TableSize,
> > + PartEntry
> > + );
> > +
> > +
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + //
> > + // Write out the secondary header and table by calling restore
> > + //
> > +
> > + if (!PartitionRestoreGptTable (PrimaryHeader)) {
> > + return EFI_VOLUME_CORRUPTED;
> > + }
> > + BlockIo->FlushBlocks (BlockIo);
> > + GptValid = !EFI_ERROR (Status);
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + (Re)initialize GPT tables on the block device
> > +
> > + @return EFI_SUCCESS Successfully (re)initialized GPT Tables
> > + @return other Failed to (re)initialize GPT tables
> > +
> > +**/
> > +STATIC
> > +EFI_STATUS
> > +TableCreateEmptyGpt (VOID)
> > +{
> > + UINTN EntryCount;
> > + UINTN BlockFit;
> > + UINTN BlockSize;
> > + UINTN EntryBlocks;
> > + UINT64 DiskSize;
> > + UINTN TableSize;
> > + EFI_LBA Header1_LBA;
> > + EFI_LBA Table1_LBA;
> > + EFI_LBA Header2_LBA;
> > + EFI_LBA Table2_LBA;
> > + EFI_LBA FirstUsableLBA;
> > + EFI_LBA LastUsableLBA;
> > + EFI_STATUS Status;
> > +
> > + EntryCount = ENTRY_DEFAULT;
> > + BlockSize = BlockIo->Media->BlockSize;
> > + BlockFit = BlockSize / sizeof(EFI_PARTITION_ENTRY);
> > +
> > + if (BlockFit > ENTRY_DEFAULT) {
> > + EntryCount = BlockFit;
> > + }
> > + EntryBlocks = EntryCount / BlockFit;
> > +
> > + if ((EntryBlocks * BlockFit) != EntryCount) {
> > + Status = EFI_VOLUME_CORRUPTED;
> > + PrintErr (L"Invalid Entry blocks and Entry count combination\n", Status);
> > + return Status;
> > + }
> > +
> > + DiskSize = BlockIo->Media->LastBlock + 1;
> > +
> > + SHELL_FREE_NON_NULL (PrimaryHeader);
> > + SHELL_FREE_NON_NULL (BackupHeader);
> > + SHELL_FREE_NON_NULL (PartEntry);
> > +
> > + PrimaryHeader = AllocateZeroPool (BlockSize);
> > + if (PrimaryHeader == NULL) {
> > + return EFI_OUT_OF_RESOURCES;
> > + }
> > +
> > + BackupHeader = AllocateZeroPool (BlockSize);
> > + if (BackupHeader == NULL) {
> > + return EFI_OUT_OF_RESOURCES;
> > + }
> > +
> > + Header1_LBA = 1;
> > + Table1_LBA = 2;
> > + FirstUsableLBA = Table1_LBA + EntryBlocks;
> > +
> > + Header2_LBA = DiskSize - 1;
> > + Table2_LBA = Header2_LBA - EntryBlocks;
> > + LastUsableLBA = Table2_LBA - 1;
> > +
> > + TableSize = EntryBlocks * BlockSize;
> > +
> > + if (TableSize != (EntryCount * sizeof(EFI_PARTITION_ENTRY))) {
> > + Status = EFI_VOLUME_CORRUPTED;
> > + PrintErr (L"Invalid Table size and Entry count combination\n", Status);
> > + return Status;
> > + }
> > +
> > + if (GPT_DEBUG_LEVEL) {
> > + Print (L"DiskSize = %lx\n", DiskSize);
> > + Print (L"BlockSize = %x\n", BlockSize);
> > + Print (L"Header1_LBA = %lx\n", Header1_LBA);
> > + Print (L"Table1_LBA = %lx\n", Table1_LBA);
> > + Print (L"FirstUsableLBA = %lx\n", FirstUsableLBA);
> > + Print (L"Header2_LBA = %lx\n", Header2_LBA);
> > + Print (L"Table2_LBA = %lx\n", Table2_LBA);
> > + Print (L"LastUsableLBA = %lx\n", LastUsableLBA);
> > + Print (L"EntryCount = %x\n", EntryCount);
> > + Print (L"EntryBlocks = %x\n", EntryBlocks);
> > + }
> > +
> > + //
> > + // Since we're making empty tables, we just write zeros...
> > + //
> > +
> > + PartEntry = AllocateZeroPool (TableSize);
> > + if (PartEntry == NULL) {
> > + SHELL_FREE_NON_NULL (PrimaryHeader);
> > + SHELL_FREE_NON_NULL (BackupHeader);
> > + return EFI_OUT_OF_RESOURCES;
> > + }
> > +
> > + PEntryStatus = AllocateZeroPool (TableSize);
> > +
> > + PrimaryHeader->FirstUsableLBA = FirstUsableLBA;
> > + PrimaryHeader->LastUsableLBA = LastUsableLBA;
> > + PrimaryHeader->NumberOfPartitionEntries = (UINT32)EntryCount;
> > + GenerateGuid (&PrimaryHeader->DiskGUID);
> > +
> > + PrimaryHeader->MyLBA = Header1_LBA;
> > + BackupHeader->MyLBA = Header2_LBA;
> > + PrimaryHeader->PartitionEntryLBA = Table1_LBA;
> > + BackupHeader->PartitionEntryLBA = Table2_LBA;
> > +
> > + Status = WriteGPT ();
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Clear GPT partitions.
> > +
> > + @return EFI_SUCCESS Cleared successfully
> > + @return FALSE Failed to clear
> > +
> > +**/
> > +
> > +EFI_STATUS
> > +PartitionGptClearAll (VOID)
> > +{
> > + GptCleanupGlobals ();
> > + GptValid = FALSE;
> > + MbrValid = FALSE;
> > + return TableCreateEmptyGpt ();
> > +}
> > +
> > +/**
> > + Create a GPT partition.
> > +
> > + @param PartName Partition Name
> > + @param StartLba Starting LBA of the partition.
> > + if zero, will be calculated
> > + @param SizeInMegaBytes Size of the partition in MB
> > + @param Attributes Partition attributes
> > + @param PartTypeGuid a Type GUID to be assigned to the partition
> > (not a partition unique GUID)
> > +
> > +
> > + @return EFI_SUCCESS Partition successfully created
> > + @return EFI_INVALID_PARAMETER Either partition exists, or wrong
> > parameters specified
> > + @return other Failed to create a partition
> > +**/
> > +EFI_STATUS
> > +PartitionGptCreatePartition (
> > + IN CONST CHAR16 *PartName,
> > + IN EFI_LBA StartLba,
> > + IN UINT64 SizeInMegabytes,
> > + IN UINT64 Attributes,
> > + IN EFI_GUID PartTypeGuid)
> > +{
> > + EFI_GUID Guid, PartitionIdGuid;
> > + EFI_STATUS Status;
> > + UINT64 StartBlock;
> > + UINT64 EndBlock;
> > + UINT64 SizeInBytes = 0;
> > + UINT32 BlockSize;
> > + UINT64 DiskSizeBlocks;
> > + UINT8 *p;
> > + BOOLEAN OffsetSpecified = FALSE;
> > + BOOLEAN AllZeros;
> > + INTN AllZeroEntry;
> > + INTN OldFreeEntry;
> > + UINT64 AvailBlocks;
> > + UINT64 BlocksToAllocate;
> > + UINT64 HighSeen;
> > + UINTN Slot;
> > + UINT64 LowestAlignedLba;
> > + UINT32 OptimalTransferBlocks;
> > + UINTN i, j;
> > + CHAR16 PartNameUsed[MAX_PARTITION_NAME_LENGTH + 1] =
> { L'\0' };
> > + EFI_PARTITION_ENTRY *Entry;
> > +
> > + LowestAlignedLba = 0;
> > + OptimalTransferBlocks = 1;
> > +
> > + AllZeroEntry = -1;
> > + OldFreeEntry = -1;
> > +
> > + BlockSize = BlockIo->Media->BlockSize;
> > + OffsetSpecified = (StartLba != 0);
> > + CopyMem (&PartNameUsed, PartName, sizeof(CHAR16) * StrSize
> > (PartName));
> > +
> > + GenerateGuid (&Guid);
> > +
> > + // Creating a new partition
> > + if (!GptValid) {
> > + // Creating a GPT for the first time
> > + Status = TableCreateEmptyGpt ();
> > + if (!EFI_ERROR (Status)) {
> > + // Fill in the structures
> > + Status = PartitionGetGptTables (DiskIo, BlockIo);
> > + }
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > + }
> > +
> > + Entry = PartitionFindPartitionByCriteria (PartName, 0, 0, SRC_BY_NAME);
> > + if (Entry) {
> > + Status = EFI_INVALID_PARAMETER;
> > + PrintErr (L"Partition with this name already exists", Status);
> > + return Status;
> > + }
> > + HighSeen = PrimaryHeader->FirstUsableLBA - 1;
> > +
> > + if (StartLba) {
> > + //
> > + // if offset is specified, compute the start and end blocks
> > + //
> > + StartBlock = StartLba;
> > + //
> > + // StartBlock should be aligned to OptimalTransferBlocks, the least
> > common multiple of:
> > + // a). the physical block boundary, if any
> > + // b). the optimal transfer length granularity, if any
> > + //
> > + if (StartBlock < LowestAlignedLba) {
> > + StartBlock = LowestAlignedLba;
> > + } else {
> > + while (((StartBlock - LowestAlignedLba) % OptimalTransferBlocks) != 0)
> {
> > + StartBlock++;
> > + }
> > + }
> > +
> > + if (StartBlock < PrimaryHeader->FirstUsableLBA ||
> > + StartBlock > PrimaryHeader->LastUsableLBA) {
> > + //
> > + // Offset specified is too large
> > + //
> > + Status = EFI_INVALID_PARAMETER;
> > + PrintErr (L"Specified offset is too large", EFI_INVALID_PARAMETER);
> > + goto Exit;
> > + }
> > +
> > + SizeInBytes = MultU64x32 (SizeInMegabytes, (1024 * 1024));
> > + if (SizeInBytes < SizeInMegabytes || SizeInBytes == 0) {
> > + //
> > + // If size is not specified or too large,
> > + // try to make the partition as big as it can be
> > + //
> > + BlocksToAllocate = EndBlock = SizeInBytes = 0xffffffffffffffff;
> > + } else {
> > + BlocksToAllocate = DivU64x32 (SizeInBytes, BlockSize);
> > + EndBlock = StartBlock + BlocksToAllocate - 1;
> > + if (EndBlock > PrimaryHeader->LastUsableLBA) {
> > + EndBlock = PrimaryHeader->LastUsableLBA;
> > + BlocksToAllocate = EndBlock - StartBlock + 1;
> > + }
> > + }
> > + }
> > +
> > + for (i = 0; i < PrimaryHeader->NumberOfPartitionEntries; i++) {
> > + Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + i *
> > PrimaryHeader->SizeOfPartitionEntry);
> > + if (!CompareGuid (&Entry->PartitionTypeGUID,
> > &gEfiPartTypeUnusedGuid)) {
> > +
> > + //
> > + // Type not null, so it's allocated
> > + //
> > + if (Entry->EndingLBA > HighSeen) {
> > + HighSeen = Entry->EndingLBA;
> > + }
> > + if (OffsetSpecified) {
> > + //
> > + // make sure new partition does not overlap with existing partitions
> > + //
> > + if (Entry->StartingLBA <= StartBlock &&
> > + StartBlock <= Entry->EndingLBA) {
> > + //
> > + // starting block is inside an existing partition
> > + //
> > + Status = EFI_INVALID_PARAMETER;
> > + PrintErr (L"Starting block is inside an existing partition", Status);
> > + goto Exit;
> > + }
> > + if ((Entry->StartingLBA <= EndBlock &&
> > + EndBlock <= Entry->EndingLBA) ||
> > + (StartBlock <= Entry->StartingLBA &&
> > + Entry->StartingLBA <= EndBlock) ||
> > + (StartBlock <= Entry->EndingLBA &&
> > + Entry->EndingLBA <= EndBlock)) {
> > + //
> > + // new partition overlaps with an existing partition
> > + // readjust new partition size to avoid overlapping
> > + //
> > + EndBlock = Entry->StartingLBA - 1;
> > + if (EndBlock < StartBlock) {
> > + Status = EFI_INVALID_PARAMETER;
> > + PrintErr (L"Cannot readjust new partition size - overlapping", Status);
> > + goto Exit;
> > + } else {
> > + BlocksToAllocate = EndBlock - StartBlock + 1;
> > + }
> > + }
> > + }
> > + } else {
> > + p = (UINT8 *)(Entry);
> > + AllZeros = TRUE;
> > + for (j = 0; j < sizeof(EFI_PARTITION_ENTRY); j++) {
> > + if (p[j] != 0) {
> > + AllZeros = FALSE;
> > + }
> > + }
> > + if (AllZeros) {
> > + if (AllZeroEntry == -1) {
> > + AllZeroEntry = i;
> > + }
> > + } else if (OldFreeEntry == -1) {
> > + OldFreeEntry = i;
> > + }
> > + }
> > + }
> > +
> > + //
> > + // AllZeroEntry - if not -1, is pointer to a never before used entry (free)
> > + // OldFreeEntry - if not -1, is pointer to some pre-used free entry
> > + //
> > + if ((AllZeroEntry == -1) && (OldFreeEntry == -1)) {
> > + //
> > + // TABLE IS FULL!!
> > + //
> > + Status = EFI_OUT_OF_RESOURCES;
> > + PrintErr (L"Table is full", Status);
> > + goto Exit;
> > + }
> > +
> > + if (OffsetSpecified) {
> > + //
> > + // the user haven't specified the new partition size and we haven't
> > + // run into any partition that will limit the size of this new partition.
> > + // So, use the max it can
> > + //
> > + if (BlocksToAllocate == -1) {
> > + EndBlock = PrimaryHeader->LastUsableLBA;
> > + BlocksToAllocate = EndBlock - StartBlock + 1;
> > + }
> > + } else {
> > + //
> > + // Because HighSeen is the last LBA of the used blocks, let HighSeen
> align
> > to the least common multiple of:
> > + // a). the physical block boundary, if any
> > + // b). the optimal transfer length granularity, if any
> > + //
> > + if (HighSeen + 1 < LowestAlignedLba) {
> > + HighSeen = LowestAlignedLba - 1;
> > + } else {
> > + while (((HighSeen + 1 - LowestAlignedLba) % OptimalTransferBlocks) !=
> 0)
> > {
> > + HighSeen++;
> > + }
> > + }
> > +
> > + if (PrimaryHeader->LastUsableLBA <= HighSeen) {
> > + Status = EFI_OUT_OF_RESOURCES;
> > + PrintErr (L"Disk has no free blocks (FULL) cannot create", Status);
> > + goto Exit;
> > + }
> > + //
> > + // [HighSeen+1 ... LastUsableLBA] is available...
> > + // avail = (LastUsableLBA - (HighSeen+1)) + 1 => LastUsabbleLBA -
> > HighSeen
> > + //
> > + AvailBlocks = PrimaryHeader->LastUsableLBA - HighSeen;
> > +
> > + SizeInBytes = MultU64x32 (SizeInMegabytes, (1024 * 1024));
> > + if (SizeInBytes < SizeInMegabytes) {
> > + //
> > + // overflow, force a very big answer
> > + //
> > + SizeInBytes = 0xffffffffffffffff;
> > + }
> > +
> > + if ((SizeInBytes == 0) ||
> > + (SizeInBytes > (MultU64x32 (AvailBlocks, BlockSize)))) {
> > + //
> > + // User asked for zero, or for more than we've got,
> > + // so give them all that is left
> > + //
> > + BlocksToAllocate = AvailBlocks;
> > +
> > + } else {
> > +
> > + //
> > + // We would have to have a BlockSize > 1mb for Remainder to
> > + // not be 0. Since we cannot actually test this case, we
> > + // ingore it...
> > + //
> > + BlocksToAllocate = DivU64x32 (SizeInBytes, BlockSize);
> > +
> > + }
> > + }
> > +
> > + //
> > + // We have a name
> > + // We have a type guid
> > + // We have a size in blocks
> > + // We have an attribute mask
> > + //
> > +
> > + if (BlocksToAllocate < ((1024 * 1024) / BlockSize)) {
> > + Status = EFI_OUT_OF_RESOURCES;
> > + PrintErr (L"Partition is too small to be created", Status);
> > + goto Exit;
> > + }
> > +
> > + if (GPT_DEBUG_LEVEL) {
> > + Print (L"Requested SizeInMegaBytes = %ld\n", SizeInMegabytes);
> > + Print (L"Resulting size in Blocks = %ld\n", BlocksToAllocate);
> > + Print (L"Results size in Bytes = %ld\n", MultU64x32 (BlocksToAllocate,
> > BlockSize));
> > + }
> > +
> > + if (AllZeroEntry != -1) {
> > + Slot = AllZeroEntry;
> > + } else {
> > + Slot = OldFreeEntry;
> > + }
> > +
> > + GenerateGuid (&PartitionIdGuid);
> > + Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Slot *
> > PrimaryHeader->SizeOfPartitionEntry);
> > +
> > + CopyMem (&Entry->PartitionTypeGUID, &PartTypeGuid,
> > sizeof(EFI_GUID));
> > + CopyMem (&Entry->UniquePartitionGUID, &PartitionIdGuid,
> > sizeof(EFI_GUID));
> > + if (OffsetSpecified) {
> > + PartEntry[Slot].StartingLBA = StartBlock;
> > + PartEntry[Slot].EndingLBA = EndBlock;
> > + } else {
> > + PartEntry[Slot].StartingLBA = HighSeen + 1;
> > + PartEntry[Slot].EndingLBA = HighSeen + BlocksToAllocate;
> > + }
> > +
> > + if (!(((Entry->EndingLBA - Entry->StartingLBA) + 1) == BlocksToAllocate)) {
> > + PrintErr (L"Wrong Size for new partiton", EFI_INVALID_PARAMETER);
> > + goto Exit;
> > + }
> > +
> > + if ((Entry->StartingLBA < PrimaryHeader->FirstUsableLBA) ||
> > + (Entry->EndingLBA > PrimaryHeader->LastUsableLBA)) {
> > + PrintErr (L"New Partition out of bounds", EFI_INVALID_PARAMETER);
> > + goto Exit;
> > + }
> > +
> > + Entry->Attributes = Attributes;
> > + CopyMem (&(Entry->PartitionName[0]), PartName,
> > MAX_PARTITION_NAME_LENGTH * sizeof(CHAR16));
> > +
> > + DiskSizeBlocks = BlockIo->Media->LastBlock + 1;
> > + if (DiskSizeBlocks > 0xffffffff) {
> > + DiskSizeBlocks = 0xffffffff;
> > + }
> > +
> > + Status = WriteGPT ();
> > +
> > + if (EFI_ERROR (Status)) {
> > + PrintErr (L"Attempt to Write out partition table failed", Status);
> > + }
> > +
> > + Exit:
> > + return Status;
> > +}
> > +
> > +/**
> > + Modifiy a partition based on parameters.
> > +
> > + @param Entry Pointer to an existing partition
> > + @param Params Parameters to be modified
> > + @param Flags Which parameter is to be modified
> > +
> > + @return EFI_SUCCESS Successfully modified the partition
> > + @return other Failed to modify a partition
> > +
> > +**/
> > +
> > +EFI_STATUS
> > +PartitionGptModifyPartition (
> > + IN EFI_PARTITION_ENTRY *Entry,
> > + IN MOD_PARAMS *Params,
> > + IN MOD_FLAGS Flags
> > + )
> > +{
> > + EFI_STATUS Status;
> > +
> > + ASSERT (Entry);
> > +
> > + Status = EFI_INVALID_PARAMETER;
> > +
> > + switch (Flags) {
> > + case MOD_DELETE:
> > + ZeroMem (Entry, sizeof(EFI_PARTITION_ENTRY));
> > + break;
> > + case MOD_ATTR:
> > + Entry->Attributes = Params->Attributes;
> > + break;
> > + case MOD_TYPE:
> > + Entry->PartitionTypeGUID = Params->PartTypeGuid;
> > + break;
> > + case MOD_RENAME:
> > + StrCpy (Entry->PartitionName, Params->NewName);
> > + break;
> > + default:
> > + PrintErr (L"Unknown modification flag(s)", Status);
> > + return Status;
> > + }
> > +
> > + return WriteGPT ();
> > +}
> > +
> > +EFI_KNOWN_PARTITION_TYPE *PartitionGetKnownType (
> > + IN UINTN Index,
> > + IN OUT OPTIONAL UINTN *NumEntries
> > + )
> > +{
> > + if (NumEntries) {
> > + *NumEntries = ARRAY_SIZE(PartitionTypes);
> > + }
> > + if (Index > ARRAY_SIZE(PartitionTypes)) {
> > + return NULL;
> > + }
> > +
> > + return &PartitionTypes[Index];
> > +}
> > +
> > diff --git a/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> > b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> > new file mode 100644
> > index 000000000000..9efec5cefe94
> > --- /dev/null
> > +++ b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> > @@ -0,0 +1,186 @@
> > +/*
> > + * BSD LICENSE
> > + *
> > + * Copyright(c) 2016 Broadcom. All rights reserved.
> > + *
> > + * Redistribution and use in source and binary forms, with or without
> > + * modification, are permitted provided that the following conditions
> > + * are met:
> > + *
> > + * * Redistributions of source code must retain the above copyright
> > + * notice, this list of conditions and the following disclaimer.
> > + * * Redistributions in binary form must reproduce the above copyright
> > + * notice, this list of conditions and the following disclaimer in
> > + * the documentation and/or other materials provided with the
> > + * distribution.
> > + * * Neither the name of Broadcom nor the names of its
> > + * contributors may be used to endorse or promote products derived
> > + * from this software without specific prior written permission.
> > + *
> > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> > CONTRIBUTORS
> > + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
> > NOT
> > + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
> > FITNESS FOR
> > + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
> > COPYRIGHT
> > + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> > INCIDENTAL,
> > + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> BUT
> > NOT
> > + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
> LOSS
> > OF USE,
> > + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
> > AND ON ANY
> > + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> > TORT
> > + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
> OF
> > THE USE
> > + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> > DAMAGE.
> > + */
> > +
> > +/* GPT partitioner header file */
> > +
> > +#ifndef _GPTWORKER_H_
> > +#define _GPTWORKER_H_
> > +
> > +#include <Uefi.h>
> > +#include <ShellBase.h>
> > +
> > +#include <Library/BaseLib.h>
> > +#include <Library/BaseMemoryLib.h>
> > +#include <Library/DebugLib.h>
> > +#include <Library/MemoryAllocationLib.h>
> > +#include <Library/ShellCommandLib.h>
> > +#include <Library/ShellLib.h>
> > +#include <Library/UefiLib.h>
> > +#include <Library/UefiShellLib/UefiShellLib.h>
> > +#include <Library/UefiBootServicesTableLib.h>
> > +#include <Library/UefiRuntimeServicesTableLib.h>
> > +#include <Library/PrintLib.h>
> > +#include <Library/ShellCEntryLib.h>
> > +#include <Library/HiiLib.h>
> > +#include <Library/FileHandleLib.h>
> > +#include <Protocol/DevicePath.h>
> > +#include <Library/DevicePathLib.h>
> > +#include <Protocol/BlockIo.h>
> > +#include <Protocol/DiskIo.h>
> > +#include <IndustryStandard/Mbr.h>
> > +
> > +typedef enum {
> > + MOD_NAME = BIT0,
> > + MOD_ATTR = BIT1,
> > + MOD_TYPE = BIT2,
> > + MOD_DELETE = BIT3,
> > + MOD_RENAME = BIT4
> > +} MOD_FLAGS;
> > +
> > +typedef struct {
> > + UINTN Attributes;
> > + EFI_GUID PartTypeGuid;
> > + CONST CHAR16 *PartName;
> > + CONST CHAR16 *NewName;
> > +} MOD_PARAMS;
> > +
> > +typedef enum {
> > + SRC_BY_NAME = BIT0,
> > + SRC_BY_LBA = BIT1,
> > + SRC_BY_NUM = BIT2,
> > + SRC_ANY = BIT3
> > +} SEARCH_TYPE;
> > +
> > +#define MAX_PARTITION_NAME_LENGTH 36
> > +#define ENTRY_DEFAULT 128
> > +#define GPT_REVISION_1_0 0x00010000
> > +
> > +#define ARRAY_SIZE(x) \
> > + (sizeof(x) / sizeof((x)[0]))
> > +
> > +//
> > +// Extract INT32 from char array
> > +//
> > +#define UNPACK_INT32(a) (INT32)( (((UINT8 *) a)[0] << 0) | \
> > + (((UINT8 *) a)[1] << 8) | \
> > + (((UINT8 *) a)[2] << 16) | \
> > + (((UINT8 *) a)[3] << 24) )
> > +
> > +//
> > +// Extract UINT32 from char array
> > +//
> > +#define UNPACK_UINT32(a) (UINT32)( (((UINT8 *) a)[0] << 0) | \
> > + (((UINT8 *) a)[1] << 8) | \
> > + (((UINT8 *) a)[2] << 16) | \
> > + (((UINT8 *) a)[3] << 24) )
> > +
> > +
> > +//
> > +// GPT Partition Entry Status
> > +//
> > +typedef struct {
> > + BOOLEAN OutOfRange;
> > + BOOLEAN Overlap;
> > + BOOLEAN OsSpecific;
> > +} EFI_PARTITION_ENTRY_STATUS;
> > +
> > +typedef struct {
> > + CONST EFI_GUID TypeGuid;
> > + CONST CHAR16 *TypeName;
> > +
> > +} EFI_KNOWN_PARTITION_TYPE;
> > +
> > +EFI_KNOWN_PARTITION_TYPE *PartitionGetKnownType (
> > + IN UINTN Index,
> > + IN OUT OPTIONAL UINTN *NumEntries
> > + );
> > +
> > +EFI_STATUS
> > +PartitionGetGptTables (
> > + IN EFI_DISK_IO_PROTOCOL *DiskIoProt,
> > + IN EFI_BLOCK_IO_PROTOCOL *BlockIoProt
> > + );
> > +
> > +UINTN
> > +PartitionListGptEntries (
> > + VOID
> > + );
> > +
> > +VOID
> > +PartitionPrintGptPartInfo (
> > + IN EFI_PARTITION_ENTRY *Entry
> > + );
> > +
> > +EFI_STATUS
> > +GetPartitionTypeStr (
> > + EFI_GUID Guid,
> > + CHAR16 *PartTypeStr,
> > + BOOLEAN NoGuidStr
> > + );
> > +
> > +
> > +EFI_STATUS
> > +PartitionGptClearAll (
> > + VOID
> > + );
> > +
> > +EFI_STATUS
> > +PartitionGptCreatePartition (
> > + CONST CHAR16 *PartName,
> > + EFI_LBA StartLba,
> > + EFI_LBA PartitionSize,
> > + UINT64 Attributes,
> > + EFI_GUID PartTypeGuid);
> > +
> > +EFI_STATUS
> > +PartitionGptModifyPartition (
> > + EFI_PARTITION_ENTRY *Entry,
> > + MOD_PARAMS *Params,
> > + MOD_FLAGS Flags
> > + );
> > +
> > +VOID
> > +GptCleanupGlobals (
> > + VOID
> > + );
> > +
> > +EFI_PARTITION_ENTRY *
> > +PartitionFindPartitionByCriteria (
> > + CONST CHAR16 *Name,
> > + EFI_LBA StartLba,
> > + EFI_LBA EndingLba,
> > + SEARCH_TYPE SearchType);
> > +
> > +VOID
> > +PrintErr (IN CONST CHAR16 *Message, IN EFI_STATUS Status);
> > +
> > +#endif //_GPTWORKER_H_
> > diff --git
> > a/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> > b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> > new file mode 100644
> > index 000000000000..a9d74a780911
> > --- /dev/null
> > +++
> > b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> > @@ -0,0 +1,1135 @@
> >
> +/*********************************************************
> > **********************
> > +Copyright (C) 2016 Marvell International Ltd.
> > +
> > +Marvell BSD License Option
> > +
> > +If you received this File from Marvell, you may opt to use, redistribute
> > and/or
> > +modify this File under the following licensing terms.
> > +Redistribution and use in source and binary forms, with or without
> > modification,
> > +are permitted provided that the following conditions are met:
> > +
> > +* Redistributions of source code must retain the above copyright notice,
> > + this list of conditions and the following disclaimer.
> > +
> > +* Redistributions in binary form must reproduce the above copyright
> > + notice, this list of conditions and the following disclaimer in the
> > + documentation and/or other materials provided with the distribution.
> > +
> > +* Neither the name of Marvell nor the names of its contributors may be
> > + used to endorse or promote products derived from this software
> without
> > + specific prior written permission.
> > +
> > +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> > CONTRIBUTORS "AS IS" AND
> > +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
> TO,
> > THE IMPLIED
> > +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> > PURPOSE ARE
> > +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> > CONTRIBUTORS BE LIABLE FOR
> > +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> > CONSEQUENTIAL DAMAGES
> > +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
> GOODS
> > OR SERVICES;
> > +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
> HOWEVER
> > CAUSED AND ON
> > +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> > TORT
> > +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
> > THE USE OF THIS
> > +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> > +
> >
> +*********************************************************
> > **********************/
> > +
> > +/* Portions Copyright (C) 2016 Broadcom */
> > +
> > +#include "FatFormat.h"
> > +#include
> > <Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.h>
> > +#include <Library/TimerLib.h>
> > +
> > +CONST CHAR16 gShellGptFileName[] = L"ShellCommand";
> > +STATIC CONST CHAR16 gAppName[] = L"gpt";
> > +EFI_HANDLE gShellGptHiiHandle = NULL;
> > +
> > +STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
> > + // Partition-related operations
> > + { L"clear", TypeFlag }, // Clears all partitions
> > + { L"create", TypeFlag }, // Creates a partition
> > + { L"delete", TypeFlag }, // Deletes a partition
> > + { L"list", TypeFlag }, // Lists all partitions
> > + { L"rename", TypeFlag }, // Renames a partition
> > + { L"setattr", TypeFlag }, // Set attributes for a partition in partition
> > table
> > + { L"settype", TypeFlag },
> > + { L"sync", TypeFlag }, // Synchronizes either master or
> alternative
> > partition table
> > + { L"typesinfo", TypeFlag }, // Verifies correctness of master and
> > alternative partition tables
> > + // BlockIo-related operations
> > + { L"read", TypeFlag }, // Reads n bytes into memory address
> from
> > a partition starting from a certain lba
> > + { L"readfile", TypeFlag }, // Same as above, but instead of store it
> in
> > memory saves into a file system
> > + { L"write", TypeFlag }, // Writes n bytes from memory into a
> > partition starting from a certain lba
> > + { L"writefile", TypeFlag }, // Same as above, but instead of getting
> > data from memory reads a file
> > + { L"info", TypeFlag }, // Get information on a certain partition
> > (startLba, lastLba, attributes)
> > + { L"fatformat", TypeFlag }, // FAT format of a partition
> > + { L"-type", TypeValue },
> > + { L"-yes", TypeFlag },
> > + { L"-verbose", TypeFlag },
> > + { NULL, TypeMax }
> > +};
> > +
> > +typedef enum {
> > + // Not requires presence
> > + CLEAR = BIT0,
> > + CREATE = BIT1,
> > + LIST = BIT2,
> > + SYNC = BIT3,
> > + TYPES_INFO = BIT4,
> > +
> > + // Requires presence
> > + DELETE = BIT5,
> > + INFO = BIT6,
> > + READ = BIT7,
> > + READ_FILE = BIT8,
> > + RENAME = BIT9,
> > + SETATTR = BIT10,
> > + SETTYPE = BIT11,
> > + WRITE = BIT12,
> > + WRITE_FILE = BIT13,
> > + FAT_FORMAT = BIT14,
> > +} Flags;
> > +
> > +/**
> > + Return the file name of the help text file if not using HII.
> > +
> > + @return The string pointer to the file name.
> > +**/
> > +CONST CHAR16 *
> > +EFIAPI
> > +ShellCommandGetManFileNameGpt (
> > + VOID
> > + )
> > +{
> > +
> > + return gShellGptFileName;
> > +}
> > +
> > +STATIC
> > +EFI_STATUS
> > +OpenAndPrepareFile (
> > + IN CHAR16 *FilePath,
> > + OUT SHELL_FILE_HANDLE *FileHandle,
> > + IN BOOLEAN WriteNeeded
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINT64 OpenMode;
> > +
> > + OpenMode = EFI_FILE_MODE_READ;
> > +
> > + if (WriteNeeded) {
> > + OpenMode |= EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE;
> > + }
> > +
> > + Status = ShellOpenFileByName (FilePath, FileHandle, OpenMode, 0);
> > + if (EFI_ERROR (Status)) {
> > + ShellPrintHiiEx (-1, -1,
> > + NULL, STRING_TOKEN (STR_GPT_ERROR),
> > + gShellGptHiiHandle,
> > + gAppName,
> > + Status,
> > + L"Cannot open file"
> > + );
> > + return Status;
> > + }
> > +
> > + Status = FileHandleSetPosition (*FileHandle, 0);
> > +
> > + if (EFI_ERROR (Status)) {
> > + ShellPrintHiiEx (-1, -1,
> > + NULL, STRING_TOKEN (STR_GPT_ERROR),
> > + gShellGptHiiHandle,
> > + gAppName,
> > + Status,
> > + "Cannot set file position to the first byte"
> > + );
> > +
> > + ShellCloseFile (FileHandle);
> > + return Status;
> > + }
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +VOID
> > +PrintErr (
> > + IN CONST CHAR16 *Message,
> > + IN EFI_STATUS Status
> > + )
> > +{
> > + ShellPrintHiiEx (-1, -1,
> > + NULL, STRING_TOKEN (STR_GPT_ERROR),
> > + gShellGptHiiHandle,
> > + gAppName,
> > + Status,
> > + Message
> > + );
> > +}
> > +
> > +STATIC
> > +BOOLEAN
> > +IsPartitionableDevicePath (
> > + IN EFI_DEVICE_PATH *DevicePath
> > + )
> > +{
> > + UINTN PathSize;
> > + EFI_DEVICE_PATH *PathInstance;
> > + BOOLEAN Partitionable;
> > +
> > + Partitionable = TRUE;
> > + while (DevicePath != NULL) {
> > + PathInstance = GetNextDevicePathInstance (&DevicePath, &PathSize);
> > +
> > + while (!IsDevicePathEnd (PathInstance)) {
> > + if ((DevicePathType (PathInstance) == MEDIA_DEVICE_PATH)) {
> > + Partitionable = FALSE;
> > + }
> > +
> > + PathInstance = NextDevicePathNode (PathInstance);
> > + }
> > + }
> > + return Partitionable;
> > +}
> > +
> > +STATIC
> > +EFI_STATUS
> > +GptPromptYesNo (
> > + IN CONST EFI_STRING_ID HiiFormatStringId
> > + )
> > +{
> > + EFI_STATUS Status;
> > + VOID *Response;
> > +
> > + Status = ShellPromptForResponseHii (ShellPromptResponseTypeYesNo,
> > HiiFormatStringId, gShellGptHiiHandle, &Response);
> > + if ((EFI_ERROR (Status)) || (*(SHELL_PROMPT_RESPONSE
> *)Response) !=
> > ShellPromptResponseYes) {
> > + return EFI_ABORTED;
> > + }
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +STATIC
> > +VOID FormatSize(
> > + UINT64 Size, CHAR16 *Buffer)
> > +{
> > +#define MAX_SIZE_BUF_SIZE 32
> > + UINT64 Base, Frac;
> > + CHAR16 Metric;
> > +
> > + Metric = L'B';
> > + Frac = 0;
> > + if (Size < SIZE_1KB) {
> > + Base = Size;
> > + } else if (Size < SIZE_1MB) {
> > + Base = Size / SIZE_1KB;
> > + Frac = ((Size % SIZE_1KB) * 10) >> 10;
> > + Metric = L'K';
> > + } else if (Size < SIZE_1GB) {
> > + Base = Size / SIZE_1MB;
> > + Frac = ((Size % SIZE_1MB) * 10) >> 20;
> > + Metric = L'M';
> > + } else if (Size < SIZE_1TB) {
> > + Base = Size / SIZE_1GB;
> > + Frac = ((Size % SIZE_1GB) * 10) >> 30;
> > + Metric = L'G';
> > + } else {
> > + Base = Size / SIZE_1TB;
> > + Frac = ((Size % SIZE_1TB) * 10) >> 40;
> > + Metric = L'T';
> > + }
> > + if (Frac) {
> > + UnicodeSPrint (Buffer, MAX_SIZE_BUF_SIZE, L"%d.%d%c", Base, Frac,
> > Metric);
> > + } else {
> > + UnicodeSPrint (Buffer, MAX_SIZE_BUF_SIZE, L"%d%c", Base, Metric);
> > + }
> > +}
> > +
> > +STATIC
> > +EFI_STATUS
> > +FindAndPrintPartitionableDevices (VOID)
> > +{
> > + UINTN Index;
> > + EFI_HANDLE *HandlePointer;
> > + UINTN HandleCount;
> > + UINTN DevCount;
> > + EFI_STATUS Status;
> > + BOOLEAN FirstTime;
> > +
> > + Status = gBS->LocateHandleBuffer (ByProtocol,
> &gEfiBlockIoProtocolGuid,
> > NULL, &HandleCount, &HandlePointer);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + DevCount = 0;
> > + FirstTime = TRUE;
> > +
> > + for (Index = 0; Index < HandleCount; Index++) {
> > + EFI_DEVICE_PATH *DevicePath;
> > + CONST CHAR16 *MapPath;
> > + CHAR16 *Match;
> > + EFI_BLOCK_IO *BlkIo;
> > + EFI_DISK_IO *DiskIo;
> > + CHAR16 *BufferForSize;
> > +
> > + Status = gBS->HandleProtocol (HandlePointer[Index],
> > &gEfiBlockIoProtocolGuid, (VOID **)&BlkIo);
> > + if (EFI_ERROR (Status)) {
> > + continue;
> > + }
> > +
> > + DevicePath = DevicePathFromHandle (HandlePointer[Index]);
> > + if (!IsPartitionableDevicePath (DevicePath)) {
> > + continue;
> > + }
> > + MapPath = gEfiShellProtocol->GetMapFromDevicePath (&DevicePath);
> > + if (MapPath == NULL) {
> > + continue;
> > + }
> > +
> > + Status = gBS->HandleProtocol (HandlePointer[Index],
> > &gEfiDiskIoProtocolGuid, (VOID **)&DiskIo);
> > + if (EFI_ERROR (Status)) {
> > + continue;
> > + }
> > +
> > + Match = StrStr (MapPath, L";BLK");
> > + if (Match) {
> > + MapPath = Match;
> > + MapPath++;
> > + }
> > +
> > + if (FirstTime) {
> > + BufferForSize = AllocateZeroPool (MAX_SIZE_BUF_SIZE * sizeof
> > (CHAR16));
> > + ASSERT (BufferForSize);
> > + Print (L" Device\t Size Comments\n");
> > + Print (L" ------ ------- ------------------------------------------------------------
> > \n");
> > + FirstTime = FALSE;
> > + }
> > + GptCleanupGlobals ();
> > + FormatSize (MultU64x32 (BlkIo->Media->LastBlock + 1, BlkIo->Media-
> > >BlockSize), BufferForSize);
> > + ShellPrintHiiEx (-1, -1,
> > + NULL, STRING_TOKEN (STR_GPT_LIST_DEVS),
> > + gShellGptHiiHandle,
> > + MapPath,
> > + BufferForSize);
> > + if (BlkIo->Media->ReadOnly) {
> > + Print (L"Read-Only! ");
> > + }
> > + if (!BlkIo->Media->MediaPresent) {
> > + Print (L"No Media! ");
> > + }
> > + if (!EFI_ERROR (PartitionGetGptTables (DiskIo, BlkIo))) {
> > + Print (L"Valid GPT. ");
> > + }
> > + if (BlkIo->Media->RemovableMedia) {
> > + Print (L"Removable device.");
> > + }
> > + Print (L"\n");
> > + DevCount++;
> > + }
> > + Print (L"\r\n");
> > + if (DevCount) {
> > + Print (L"%d potentially partitionable device(s) found\n", DevCount);
> > + } else {
> > + Print (L"No potentially partitionable device(s) found\n");
> > + }
> > +
> > + GptCleanupGlobals ();
> > + return EFI_SUCCESS;
> > +}
> > +
> > +SHELL_STATUS
> > +EFIAPI
> > +ShellCommandRunGpt (
> > + IN EFI_HANDLE ImageHandle,
> > + IN EFI_SYSTEM_TABLE *SystemTable
> > + )
> > +{
> > + EFI_STATUS Status;
> > + LIST_ENTRY *CheckPackage;
> > + EFI_PHYSICAL_ADDRESS Address = 0, Offset = 0;
> > + UINT64 PartAttributes = 0;
> > + EFI_GUID PartTypeGuid = { 0 };
> > + SHELL_FILE_HANDLE FileHandle = NULL;
> > + UINT64 ByteCount, FileSize;
> > + UINTN I;
> > + UINT8 *Buffer = NULL, *FileBuffer = NULL;
> > +
> > + CHAR16 * ProblemParam,*FilePath;
> > + CONST CHAR16 *AddressStr = NULL, *OffsetStr = NULL;
> > + CONST CHAR16 *PartName = NULL, *NewPartName = NULL,
> > *AttrStr = NULL,
> > + *GuidStr = NULL, *VolumeName = NULL;
> > + CONST CHAR16 *LengthStr = NULL, *FileStr = NULL;
> > + BOOLEAN AddrFlag = FALSE, LengthFlag = TRUE, FileFlag = FALSE,
> > GuidFlag = FALSE, OffsetFlag = TRUE;
> > + BOOLEAN PartNameFlag = TRUE, NewPartNameFlag = FALSE,
> > AttrFlag = FALSE;
> > + UINTN Flag = 0, CheckFlag = 0;
> > + CONST CHAR16 *BlockName;
> > + EFI_DEVICE_PATH_PROTOCOL *DevPath;
> > + EFI_BLOCK_IO_PROTOCOL *BlockIo;
> > + EFI_DISK_IO_PROTOCOL *DiskIo;
> > + EFI_HANDLE BlockIoHandle;
> > + MOD_PARAMS ModParams;
> > + EFI_PARTITION_ENTRY *Entry;
> > + UINTN NumKnownPartTypesEntries;
> > + BOOLEAN TableNotEmpty, NoPrompt = FALSE, Quiet = TRUE;
> > + UINT64 TimeStampB, TimeStampE, SpeedKB, Freq;
> > +
> > + // Parse Shell command line
> > + Status = ShellInitialize ();
> > + if (EFI_ERROR (Status)) {
> > + PrintErr (L"Cannot initialize Shell", Status);
> > + ASSERT_EFI_ERROR (Status);
> > + return SHELL_ABORTED;
> > + }
> > +
> > + Status = ShellCommandLineParse (ParamList, &CheckPackage,
> > &ProblemParam, TRUE);
> > + if (EFI_ERROR (Status)) {
> > + PrintErr (L"Error while parsing command line", Status);
> > + return SHELL_ABORTED;
> > + }
> > +
> > + TimeStampB = 0;
> > + TimeStampE = 0;
> > +
> > + NoPrompt = ShellCommandLineGetFlag (CheckPackage, L"-yes");
> > + Quiet = !ShellCommandLineGetFlag (CheckPackage, L"-verbose");
> > +
> > + Freq = GetPerformanceCounterProperties (NULL, NULL);
> > +
> > + // Check flags provided by user
> > + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"clear") << 0);
> > + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"create") << 1);
> > + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"list") << 2);
> > + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"sync") << 3);
> > + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"typesinfo") << 4);
> > + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"delete") << 5);
> > + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"info") << 6);
> > + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"read") << 7);
> > + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"readfile") << 8);
> > + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"rename") << 9);
> > + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"setattr") << 10);
> > + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"settype") << 11);
> > + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"write") << 12);
> > + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"writefile") << 13);
> > + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"fatformat") << 14);
> > +
> > + PartitionGetKnownType ((UINTN)(-1), &NumKnownPartTypesEntries);
> > +
> > + if (Flag & TYPES_INFO) {
> > + UINTN Index;
> > +
> > + Print (L" No\t%-36s\tGUID\r\n", L"Type name");
> > + Print (L" ---- ---------------------------------- ----------------------------------
> --
> > \n");
> > + for (Index = 0; Index < NumKnownPartTypesEntries; Index++) {
> > + EFI_KNOWN_PARTITION_TYPE *PartType;
> > +
> > + PartType = PartitionGetKnownType (Index, NULL);
> > + if (PartType == NULL) {
> > + break;
> > + }
> > + Print (L" %3d\t%-36s\t%g\n", Index, PartType->TypeName,
> &PartType-
> > >TypeGuid);
> > + }
> > + if (Flag == TYPES_INFO) {
> > + return SHELL_SUCCESS;
> > + }
> > + }
> > + // Start parsing the command.
> > + // Generally command is:
> > + // block_name:bootpart_no addr or filename offset
> > +
> > + BlockName = ShellCommandLineGetRawValue (CheckPackage, 1);
> > + if (BlockName == NULL) {
> > + if (Flag & LIST) {
> > + Status = FindAndPrintPartitionableDevices ();
> > + if (EFI_ERROR (Status)) {
> > + PrintErr (L"Error getting list of partitionable devices", Status);
> > + Status = SHELL_ABORTED;
> > + }
> > + return Status;
> > + }
> > + PrintErr (L"Missing block device name", EFI_INVALID_PARAMETER);
> > + return SHELL_INVALID_PARAMETER;
> > + }
> > +
> > + // Find device handle by mapped name
> > + if (gEfiShellProtocol->GetDevicePathFromMap (BlockName) == NULL) {
> > + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
> > gShellGptHiiHandle, gAppName, BlockName);
> > + Status = SHELL_INVALID_PARAMETER;
> > + } else {
> > + DevPath = (EFI_DEVICE_PATH_PROTOCOL *)gEfiShellProtocol-
> > >GetDevicePathFromMap (BlockName);
> > + if (gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &DevPath, NULL)
> > == EFI_NOT_FOUND) {
> > + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN
> > (STR_GEN_MAP_PROTOCOL), gShellGptHiiHandle, gAppName, BlockName,
> > L"BlockIo");
> > + Status = SHELL_INVALID_PARAMETER;
> > + }
> > + }
> > +
> > + if (Status) {
> > + return SHELL_INVALID_PARAMETER;
> > + }
> > +
> > + BlockIoHandle = 0;
> > +
> > + Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid,
> > (EFI_DEVICE_PATH_PROTOCOL **)&DevPath, &BlockIoHandle);
> > + if (EFI_ERROR (Status)) {
> > + goto CleanUp;
> > + }
> > +
> > + Status = gBS->OpenProtocol (BlockIoHandle, &gEfiBlockIoProtocolGuid,
> > (VOID **)&BlockIo, gImageHandle, NULL,
> > EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> > + if (EFI_ERROR (Status)) {
> > + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN
> > (STR_GEN_MAP_PROTOCOL), gShellGptHiiHandle, gAppName, BlockName,
> > L"BlockIo");
> > + goto CleanUp;
> > + }
> > +
> > + Status = gBS->HandleProtocol (
> > + BlockIoHandle,
> > + &gEfiDiskIoProtocolGuid,
> > + (VOID **)&DiskIo
> > + );
> > + if (EFI_ERROR (Status)) {
> > + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN
> > (STR_GEN_MAP_PROTOCOL), gShellGptHiiHandle, gAppName, BlockName,
> > L"DiskIo");
> > + goto CleanUp;
> > + }
> > +
> > + CheckFlag = Flag;
> > + for (I = 0; CheckFlag; CheckFlag >>= 1) {
> > + I += CheckFlag & 1;
> > + if (I > 1) {
> > + PrintErr (L"Too many flags", EFI_INVALID_PARAMETER);
> > + Status = SHELL_INVALID_PARAMETER;
> > + goto CleanUp;
> > + }
> > + }
> > +
> > + if (Flag & SYNC) {
> > + // Let the Partition table driver know that
> > + // we want to reread the tables
> > + Status = gBS->ReinstallProtocolInterface (
> > + BlockIoHandle,
> > + &gEfiBlockIoProtocolGuid,
> > + BlockIo,
> > + BlockIo
> > + );
> > + Status = SHELL_SUCCESS;
> > + goto CleanUp;
> > + }
> > +
> > + if (!IsPartitionableDevicePath (DevicePathFromHandle (BlockIoHandle)))
> {
> > + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
> > gShellGptHiiHandle, gAppName, BlockName);
> > + Print (L"%s is not a raw block device\n", BlockName);
> > + Status = SHELL_INVALID_PARAMETER;
> > + goto CleanUp;
> > + }
> > +
> > + if (!BlockIo->Media->MediaPresent) {
> > + PrintErr (L"Media is not present!\n", EFI_NO_MEDIA);
> > + Status = EFI_NO_MEDIA;
> > + goto CleanUp;
> > + }
> > +
> > + // Preload GPT tables with validation
> > + Status = PartitionGetGptTables (DiskIo, BlockIo);
> > + if (EFI_ERROR (Status)) {
> > + BOOLEAN CanContinue;
> > +
> > + CanContinue = (Flag & CREATE) || (Flag & CLEAR) || (Flag &
> > FAT_FORMAT);
> > + if (Status != EFI_NOT_FOUND) {
> > + PrintErr (L"Unexpected error getting GPT tables", Status);
> > + goto CleanUp;
> > + } else {
> > + if (!CanContinue) {
> > + PrintErr (L"No GPT table found. Create first", Status);
> > + goto CleanUp;
> > + }
> > + }
> > + }
> > +
> > + // Do we have any partitions already?
> > + TableNotEmpty = (PartitionFindPartitionByCriteria (NULL, 0, 0,
> SRC_ANY) !=
> > NULL);
> > +
> > + Status = SHELL_INVALID_PARAMETER;
> > +
> > + if ((Flag < LIST) ||
> > + (Flag & DELETE) ||
> > + (Flag > READ_FILE)
> > + ) {
> > + if (BlockIo->Media->ReadOnly) {
> > + Status = EFI_INVALID_PARAMETER;
> > + PrintErr (L"Cannot write to a read-only device", Status);
> > + goto CleanUp;
> > + }
> > + }
> > +
> > + if (BlockIo->Media->RemovableMedia) {
> > + Print (L"%s is a removable device. Just a note\n", BlockName);
> > + }
> > +
> > + switch (Flag) {
> > + case INFO:
> > + PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
> > + OffsetFlag = FALSE;
> > + LengthFlag = FALSE;
> > + break;
> > + case LIST:
> > + {
> > + UINTN NumEntries;
> > +
> > + NumEntries = PartitionListGptEntries ();
> > + if (NumEntries == 0) {
> > + Print (L"gpt: GPT is valid on %s, but no partition(s) defined yet. Use
> > create\n", BlockName);
> > + }
> > + Status = SHELL_SUCCESS;
> > + goto CleanUp;
> > + break;
> > + }
> > + case CLEAR:
> > + if (TableNotEmpty) {
> > + // Tell the user what he/she is doing...
> > + ShellPrintHiiEx (-1, -1,
> > + NULL, STRING_TOKEN (STR_GPT_NOT_EMPTY),
> > + gShellGptHiiHandle,
> > + BlockName
> > + );
> > + }
> > +
> > + // Even if GPT tables do not exist, there might be something.
> > + // Warn the user and double sure it is the intention,
> > + // to prevent a user from bricking a device (JTAG would be needed to
> > recover)
> > + // by overwriting an ATF boot device. However with NoPrompt on, the
> > user is
> > + // responsible for operation because there is no confirmation
> (assuming
> > yes on all queries).
> > + if ((NoPrompt) || (!GptPromptYesNo (STRING_TOKEN
> > (STR_GPT_CLEAR_SURE)) &&
> > + (!GptPromptYesNo (STRING_TOKEN
> > (STR_GPT_ABSOLUTELY_SURE))))
> > + ) {
> > + PartitionGptClearAll ();
> > + }
> > + Status = SHELL_SUCCESS;
> > + goto CleanUp;
> > + break;
> > + case CREATE:
> > + PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
> > + OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 3);
> > + LengthStr = ShellCommandLineGetRawValue (CheckPackage, 4);
> > + AttrStr = ShellCommandLineGetRawValue (CheckPackage, 5);
> > + GuidStr = ShellCommandLineGetValue (CheckPackage, L"-type");
> > + GuidFlag = TRUE;
> > + break;
> > + case DELETE:
> > + PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
> > + LengthFlag = FALSE;
> > + OffsetFlag = FALSE;
> > + break;
> > + case RENAME:
> > + PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
> > + NewPartName = ShellCommandLineGetRawValue (CheckPackage, 3);
> > + NewPartNameFlag = TRUE;
> > + LengthFlag = FALSE;
> > + OffsetFlag = FALSE;
> > + break;
> > + case SETATTR:
> > + PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
> > + AttrStr = ShellCommandLineGetRawValue (CheckPackage, 3);
> > + AttrFlag = TRUE;
> > + LengthFlag = FALSE;
> > + OffsetFlag = FALSE;
> > + break;
> > + case SETTYPE:
> > + PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
> > + GuidStr = ShellCommandLineGetValue (CheckPackage, L"-type");
> > + GuidFlag = TRUE;
> > + LengthFlag = FALSE;
> > + OffsetFlag = FALSE;
> > + break;
> > + case FAT_FORMAT:
> > + PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
> > + VolumeName = ShellCommandLineGetRawValue (CheckPackage, 3);
> > + LengthFlag = FALSE;
> > + OffsetFlag = FALSE;
> > + PartNameFlag = (PartName != NULL);
> > + if (!PartNameFlag && TableNotEmpty) {
> > + // Tell the user what he/she is doing...
> > + ShellPrintHiiEx (-1, -1,
> > + NULL, STRING_TOKEN (STR_GPT_NOT_EMPTY),
> > + gShellGptHiiHandle,
> > + BlockName
> > + );
> > + }
> > + break;
> > + // Fall through
> > + case READ:
> > + case WRITE:
> > + AddressStr = ShellCommandLineGetRawValue (CheckPackage, 2);
> > + PartName = ShellCommandLineGetRawValue (CheckPackage, 3);
> > + OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 4);
> > + LengthStr = ShellCommandLineGetRawValue (CheckPackage, 5);
> > + AddrFlag = TRUE;
> > + break;
> > + case READ_FILE:
> > + FileStr = ShellCommandLineGetRawValue (CheckPackage, 2);
> > + PartName = ShellCommandLineGetRawValue (CheckPackage, 3);
> > + OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 4);
> > + LengthStr = ShellCommandLineGetRawValue (CheckPackage, 5);
> > + FileFlag = TRUE;
> > + break;
> > + case WRITE_FILE:
> > + FileStr = ShellCommandLineGetRawValue (CheckPackage, 2);
> > + PartName = ShellCommandLineGetRawValue (CheckPackage, 3);
> > + OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 4);
> > + LengthFlag = FALSE;
> > + FileFlag = TRUE;
> > + break;
> > + default:
> > + Print (L"%s: Unsupported command. Try \"help %s\"", gAppName);
> > + Status = SHELL_INVALID_PARAMETER;
> > + goto CleanUp;
> > + }
> > +
> > + // Read address parameter
> > + if ((AddressStr == NULL) & AddrFlag) {
> > + PrintErr (L"No address parameter", EFI_INVALID_PARAMETER);
> > + goto CleanUp;
> > + } else if (AddrFlag) {
> > + Address = ShellHexStrToUintn (AddressStr);
> > + if (Address == (UINTN)(-1)) {
> > + PrintErr (L"Wrong address parameter", EFI_INVALID_PARAMETER);
> > + goto CleanUp;
> > + }
> > + }
> > +
> > + if ((PartName == NULL) & PartNameFlag) {
> > + PrintErr (L"Missing partition name", EFI_INVALID_PARAMETER);
> > + goto CleanUp;
> > + } else if (PartNameFlag) {
> > + if (StrSize (PartName) > MAX_PARTITION_NAME_LENGTH) {
> > + PrintErr (L"Partition name is too long (max 36 chars)",
> > EFI_INVALID_PARAMETER);
> > + goto CleanUp;
> > + }
> > + }
> > +
> > + // Read offset parameter
> > + if ((OffsetStr == NULL) & OffsetFlag) {
> > + PrintErr (L"No offset Parameter", EFI_INVALID_PARAMETER);
> > + goto CleanUp;
> > + } else if (OffsetFlag) {
> > + Offset = ShellHexStrToUintn (OffsetStr);
> > + if (Offset < 0) {
> > + Print (L"%s: Wrong offset parameter: %s\n", gAppName, OffsetStr);
> > + goto CleanUp;
> > + }
> > + }
> > +
> > + // Read length parameter
> > + if ((LengthStr == NULL) & LengthFlag) {
> > + PrintErr (L"No length parameter", EFI_INVALID_PARAMETER);
> > + goto CleanUp;
> > + } else if (LengthFlag) {
> > + ByteCount = (UINT64)ShellStrToUintn (LengthStr);
> > + if (ByteCount < 0) {
> > + Print (L"%s: Wrong length parameter %s!\n", gAppName, LengthStr);
> > + goto CleanUp;
> > + }
> > + }
> > +
> > + if ((NewPartName == NULL) & NewPartNameFlag) {
> > + PrintErr (L"Missing name to be assigned to partition",
> > EFI_INVALID_PARAMETER);
> > + goto CleanUp;
> > + } else if (NewPartNameFlag) {
> > + if (StrSize (NewPartName) > MAX_PARTITION_NAME_LENGTH) {
> > + PrintErr (L"Partition name is too long (max 36 chars)",
> > EFI_INVALID_PARAMETER);
> > + goto CleanUp;
> > + }
> > + }
> > +
> > + if ((AttrStr == NULL) & AttrFlag) {
> > + PrintErr (L"Missing attributes parameter", EFI_INVALID_PARAMETER);
> > + goto CleanUp;
> > + } else if (AttrStr) {
> > + PartAttributes = (UINT64)ShellStrToUintn (AttrStr);
> > + }
> > +
> > + if ((GuidStr == NULL) & GuidFlag) {
> > + PrintErr (L"Missing partition type GUID parameter",
> > EFI_INVALID_PARAMETER);
> > + goto CleanUp;
> > + } else if (GuidFlag) {
> > + Status = SHELL_INVALID_PARAMETER;
> > + if (InternalShellIsHexOrDecimalNumber (GuidStr, FALSE, TRUE, FALSE)) {
> > + UINTN Ordinal;
> > +
> > + Ordinal = ShellStrToUintn (GuidStr);
> > + if (Ordinal < NumKnownPartTypesEntries) {
> > + PartTypeGuid = PartitionGetKnownType (Ordinal, NULL)->TypeGuid;
> > + Status = SHELL_SUCCESS;
> > + } else {
> > + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
> > gShellGptHiiHandle, gAppName, GuidStr);
> > + goto CleanUp;
> > + }
> > + } else {
> > + Status = ConvertStringToGuid (GuidStr, &PartTypeGuid);
> > + if ((EFI_ERROR (Status)) || (IsZeroGuid (&PartTypeGuid))) {
> > + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
> > gShellGptHiiHandle, gAppName, GuidStr);
> > + Status = SHELL_INVALID_PARAMETER;
> > + goto CleanUp;
> > + }
> > + }
> > + }
> > +
> > + if (FileFlag) {
> > + // Read FilePath parameter
> > + if (FileStr == NULL) {
> > + PrintErr (L"No FilePath parameter", EFI_INVALID_PARAMETER);
> > + goto CleanUp;
> > + } else {
> > + FilePath = (CHAR16 *)FileStr;
> > + Status = ShellIsFile (FilePath);
> > + // When read file into flash, file doesn't have to exist
> > + if (EFI_ERROR (Status && !(Flag & READ_FILE))) {
> > + PrintErr (L"Wrong FilePath parameter", Status);
> > + Status = SHELL_INVALID_PARAMETER;
> > + goto CleanUp;
> > + }
> > + }
> > +
> > + Status = OpenAndPrepareFile (FilePath, &FileHandle, ((Flag &
> > READ_FILE) != 0));
> > + if (EFI_ERROR (Status)) {
> > + Print (L"Error %r while preparing file %s", Status, FilePath);
> > + Status = SHELL_ABORTED;
> > + goto CleanUp;
> > + }
> > +
> > + // Get file size in order to check correctness at the end of transfer
> > + if (Flag & (WRITE_FILE)) {
> > + Status = FileHandleGetSize (FileHandle, &FileSize);
> > + if (EFI_ERROR (Status)) {
> > + PrintErr (L"Cannot get file size", Status);
> > + Status = SHELL_ABORTED;
> > + goto CleanUp;
> > + }
> > + ByteCount = (UINT64)FileSize;
> > + }
> > +
> > + FileBuffer = AllocateZeroPool ((UINTN)ByteCount);
> > + if (FileBuffer == NULL) {
> > + PrintErr (L"Cannot allocate memory", EFI_OUT_OF_RESOURCES);
> > + Status = SHELL_OUT_OF_RESOURCES;
> > + goto Error_Close_File;
> > + }
> > +
> > + // Read file content and store it in FileBuffer
> > + if (Flag & (WRITE_FILE)) {
> > + if (!Quiet) {
> > + Print (L"Reading %s...\r", FilePath);
> > + }
> > + Status = FileHandleRead (FileHandle, &ByteCount, FileBuffer);
> > + if (EFI_ERROR (Status)) {
> > + PrintErr (L"Read from file error", Status);
> > + Status = SHELL_ABORTED;
> > + goto Error_Free_Buffer;
> > + } else if (ByteCount != (UINTN)FileSize) {
> > + PrintErr (L"Not whole file read. Abort", EFI_DEVICE_ERROR);
> > + Status = SHELL_DEVICE_ERROR;
> > + goto Error_Free_Buffer;
> > + }
> > + if (!Quiet) {
> > + Print (L"Writing %s into device %s, partition %s...\n", FilePath,
> > BlockName, PartName);
> > + }
> > + }
> > + }
> > +
> > + Buffer = (UINT8 *)Address;
> > + if (FileFlag) {
> > + Buffer = FileBuffer;
> > + }
> > +
> > + if (Flag > TYPES_INFO) {
> > + Entry = PartitionFindPartitionByCriteria (PartName, 0, 0, SRC_BY_NAME);
> > + if (!Entry && PartName && (InternalShellIsHexOrDecimalNumber
> > (PartName, FALSE, TRUE, FALSE))) {
> > + Entry = PartitionFindPartitionByCriteria (PartName, 0, 0, SRC_BY_NUM);
> > + }
> > + if ((!Entry) && (PartNameFlag)) {
> > + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
> > gShellGptHiiHandle, gAppName, PartName);
> > + Print (L"Could not find partition %s (case-sensitive). Make sure the
> name
> > is spelled properly\n", PartName);
> > + Status = SHELL_NOT_FOUND;
> > + goto CleanUp;
> > + }
> > + }
> > +
> > + switch (Flag) {
> > + case CREATE:
> > + PartitionGptCreatePartition (
> > + PartName,
> > + Offset, // Lba. If 0, the next available is assumed
> > + ByteCount, // in MegaBytes. If 0 the whole remaining space is
> assumed
> > + PartAttributes,
> > + PartTypeGuid);
> > + break;
> > + case DELETE:
> > + ModParams.PartName = PartName;
> > + ShellPrintHiiEx (-1, -1,
> > + NULL, STRING_TOKEN (STR_GPT_DELETE_WARNING),
> > + gShellGptHiiHandle,
> > + Entry->PartitionName
> > + );
> > + if ((NoPrompt) || (!GptPromptYesNo (STRING_TOKEN
> > (STR_GPT_ABSOLUTELY_SURE)))) {
> > + Status = PartitionGptModifyPartition (
> > + Entry, &ModParams, MOD_DELETE);
> > + if (EFI_ERROR (Status)) {
> > + PrintErr (L"Error deleting the partition", Status);
> > + Status = SHELL_ABORTED;
> > + goto CleanUp;
> > + }
> > + Status = SHELL_SUCCESS;
> > + } else {
> > + Status = SHELL_ABORTED;
> > + }
> > + break;
> > + case FAT_FORMAT:
> > + {
> > + EFI_LBA StartingLBA, EndingLBA;
> > + CHAR8 LabelName[12];
> > +
> > + if (VolumeName) {
> > + if (StrLen (VolumeName) > 11) {
> > + Status = EFI_INVALID_PARAMETER;
> > + PrintErr (L"The volume label is too long", Status);
> > + Status = SHELL_INVALID_PARAMETER;
> > + goto CleanUp;
> > + }
> > + UnicodeStrToAsciiStr (VolumeName, (CHAR8 *)LabelName);
> > + }
> > + ShellPrintHiiEx (-1, -1,
> > + NULL, STRING_TOKEN (STR_GPT_FORMAT_WARNING),
> > + gShellGptHiiHandle,
> > + Entry ? Entry->PartitionName : BlockName
> > + );
> > +
> > + if ((NoPrompt) || (!GptPromptYesNo (STRING_TOKEN
> > (STR_GPT_FORMAT_SURE)) &&
> > + (!GptPromptYesNo (STRING_TOKEN
> > (STR_GPT_ABSOLUTELY_SURE))))
> > + ) {
> > + StartingLBA = 0;
> > + EndingLBA = BlockIo->Media->LastBlock;
> > + if (Entry) {
> > + StartingLBA = Entry->StartingLBA;
> > + EndingLBA = Entry->EndingLBA;
> > + }
> > + if (!Quiet) {
> > + Print (L"Formatting %s to FAT32...\r", PartNameFlag ? Entry-
> > >PartitionName : BlockName);
> > + }
> > + Status = FatFormat (StartingLBA, EndingLBA, BlockIo, DiskIo,
> > VolumeName ? LabelName : NULL, TRUE);
> > + if (EFI_ERROR (Status)) {
> > + PrintErr (L"Error formatting the partition to FAT ", Status);
> > + Status = SHELL_ABORTED;
> > + goto CleanUp;
> > + } else if (!Quiet) {
> > + Print (L"%s successfully formatted to FAT. Formatted size %llu
> MiB\n",
> > + PartNameFlag ? Entry->PartitionName : BlockName,
> > + MultU64x32 (EndingLBA - StartingLBA + 1, BlockIo->Media-
> > >BlockSize) >> 20
> > + );
> > + }
> > + } else {
> > + Status = SHELL_ABORTED;
> > + }
> > + }
> > + break;
> > + case RENAME:
> > + ModParams.PartName = PartName;
> > + ModParams.NewName = NewPartName;
> > + Status = PartitionGptModifyPartition (
> > + Entry, &ModParams, MOD_RENAME);
> > + break;
> > + case SETATTR:
> > + ModParams.Attributes = PartAttributes;
> > + Status = PartitionGptModifyPartition (
> > + Entry, &ModParams, MOD_ATTR);
> > + break;
> > + case SETTYPE:
> > + ModParams.PartTypeGuid = PartTypeGuid;
> > + Status = PartitionGptModifyPartition (
> > + Entry, &ModParams, MOD_TYPE);
> > + break;
> > + case INFO:
> > + PartitionPrintGptPartInfo (Entry);
> > + Status = SHELL_SUCCESS;
> > + break;
> > + case READ:
> > + case READ_FILE:
> > + case WRITE:
> > + case WRITE_FILE:
> > + {
> > + UINT64 MaxBytes;
> > + BOOLEAN OpRead;
> > +
> > + OpRead = ((Flag & READ) || (Flag & READ_FILE));
> > + MaxBytes = MultU64x32 (
> > + Entry->EndingLBA - Entry->StartingLBA,
> > + BlockIo->Media->BlockSize) +
> > + BlockIo->Media->BlockSize -
> > + MultU64x32 (Offset, BlockIo->Media->BlockSize);
> > + if (ByteCount > MaxBytes) {
> > + Status = EFI_INVALID_PARAMETER;
> > + ShellPrintHiiEx (-1, -1,
> > + NULL, (OpRead) ?
> > + STRING_TOKEN (STR_GPT_READ_BOUNDARY) :
> > + STRING_TOKEN (STR_GPT_WRITE_BOUNDARY),
> > + gShellGptHiiHandle,
> > + gAppName,
> > + Entry->PartitionName,
> > + MaxBytes,
> > + ByteCount
> > + );
> > + Status = SHELL_INVALID_PARAMETER;
> > + goto CleanUp;
> > + }
> > +
> > + TimeStampB = GetPerformanceCounter ();
> > + if (OpRead) {
> > + Status = DiskIo->ReadDisk (DiskIo,
> > + BlockIo->Media->MediaId,
> > + MultU64x32 (Offset + Entry->StartingLBA, BlockIo-
> > >Media->BlockSize), ByteCount, Buffer);
> > + } else {
> > + Status = DiskIo->WriteDisk (DiskIo, BlockIo->Media->MediaId,
> > + MultU64x32 (Offset + Entry->StartingLBA, BlockIo-
> > >Media->BlockSize), ByteCount, Buffer);
> > + }
> > + }
> > + break;
> > + default:
> > + Status = SHELL_INVALID_PARAMETER;
> > + PrintErr (L"Unknown command. Try \"help gpt\"",
> > EFI_INVALID_PARAMETER);
> > + goto CleanUp;
> > + }
> > +
> > + if (EFI_ERROR (Status)) {
> > + PrintErr (L"Error while performing transfer\n", Status);
> > + Status = SHELL_ABORTED;
> > + goto CleanUp;
> > + }
> > +
> > + TimeStampE = ((GetPerformanceCounter () - TimeStampB) * 1000) /
> Freq;
> > + SpeedKB = TimeStampE ? (ByteCount / (TimeStampE / 1000)) >> 10 : 0;
> > +
> > + switch (Flag) {
> > + case WRITE:
> > + case WRITE_FILE:
> > + if (!Quiet) {
> > + ShellPrintHiiEx (-1, -1,
> > + NULL,
> > + STRING_TOKEN (STR_GPT_WRITE_OK),
> > + gShellGptHiiHandle,
> > + ByteCount,
> > + Offset,
> > + Entry->PartitionName,
> > + TimeStampE,
> > + SpeedKB
> > + );
> > + }
> > + break;
> > + case READ:
> > + if (!Quiet) {
> > + ShellPrintHiiEx (-1, -1,
> > + NULL,
> > + STRING_TOKEN (STR_GPT_READ_OK),
> > + gShellGptHiiHandle,
> > + ByteCount,
> > + Offset,
> > + Entry->PartitionName,
> > + TimeStampE,
> > + SpeedKB
> > + );
> > + }
> > + break;
> > + case READ_FILE:
> > + Status = FileHandleWrite (FileHandle, &ByteCount, FileBuffer);
> > + if (EFI_ERROR (Status)) {
> > + ShellPrintHiiEx (-1, -1,
> > + NULL,
> > + STRING_TOKEN (STR_GPT_FILE_WRITE_FAIL),
> > + gShellGptHiiHandle,
> > + gAppName,
> > + FilePath,
> > + Status
> > + );
> > + Status = SHELL_DEVICE_ERROR;
> > + goto Error_Free_Buffer;
> > + }
> > +
> > + if (!Quiet) {
> > + ShellPrintHiiEx (-1, -1,
> > + NULL,
> > + STRING_TOKEN (STR_GPT_READFILE_OK),
> > + gShellGptHiiHandle,
> > + ByteCount,
> > + Offset,
> > + Entry->PartitionName,
> > + FilePath,
> > + TimeStampE,
> > + SpeedKB
> > + );
> > + }
> > + break;
> > + }
> > +
> > + if (FileFlag) {
> > + SHELL_FREE_NON_NULL (FileBuffer);
> > + if (FileHandle != NULL) {
> > + ShellCloseFile (&FileHandle);
> > + FileHandle = NULL;
> > + }
> > + }
> > +
> > + Status = SHELL_SUCCESS;
> > +
> > + Error_Free_Buffer:
> > + SHELL_FREE_NON_NULL (FileBuffer);
> > + Error_Close_File:
> > + if (FileHandle) {
> > + ShellCloseFile (&FileHandle);
> > + }
> > + CleanUp:
> > + if (BlockIoHandle) {
> > + // By UEFI Spec blocks must be flushed
> > + BlockIo->FlushBlocks (BlockIo);
> > + gBS->CloseProtocol (BlockIoHandle, &gEfiBlockIoProtocolGuid,
> > gImageHandle, NULL);
> > + }
> > +
> > + GptCleanupGlobals ();
> > +
> > + ShellCommandLineFreeVarList (CheckPackage);
> > +
> > + if (EFI_ERROR (Status)) {
> > + Status = SHELL_ABORTED;
> > + }
> > +
> > + return Status;
> > +}
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +ShellGptLibConstructor (
> > + IN EFI_HANDLE ImageHandle,
> > + IN EFI_SYSTEM_TABLE *SystemTable
> > + )
> > +{
> > + gShellGptHiiHandle = NULL;
> > +
> > + gShellGptHiiHandle = HiiAddPackages (
> > + &gShellGptHiiGuid, gImageHandle,
> > + UefiShellGptCommandLibStrings, NULL
> > + );
> > + if (gShellGptHiiHandle == NULL) {
> > + return EFI_DEVICE_ERROR;
> > + }
> > +
> > + ShellCommandRegisterCommandName (
> > + gAppName, ShellCommandRunGpt,
> ShellCommandGetManFileNameGpt,
> > 0,
> > + gAppName, TRUE, gShellGptHiiHandle, STRING_TOKEN
> > (STR_GET_HELP_GPT)
> > + );
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +ShellGptLibDestructor (
> > + IN EFI_HANDLE ImageHandle,
> > + IN EFI_SYSTEM_TABLE *SystemTable
> > + )
> > +{
> > +
> > + if (gShellGptHiiHandle != NULL) {
> > + HiiRemovePackages (gShellGptHiiHandle);
> > + }
> > + return EFI_SUCCESS;
> > +}
> > diff --git
> > a/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> >
> b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> > new file mode 100644
> > index 000000000000..1be4b1ab0f11
> > --- /dev/null
> > +++
> >
> b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> > @@ -0,0 +1,79 @@
> > +#
> > +# Marvell BSD License Option
> > +#
> > +# If you received this File from Marvell, you may opt to use, redistribute
> > +# and/or modify this File under the following licensing terms.
> > +# Redistribution and use in source and binary forms, with or without
> > +# modification, are permitted provided that the following conditions are
> > met:
> > +#
> > +# * Redistributions of source code must retain the above copyright notice,
> > +# this list of conditions and the following disclaimer.
> > +#
> > +# * Redistributions in binary form must reproduce the above copyright
> > +# notice, this list of conditions and the following disclaimer in the
> > +# documentation and/or other materials provided with the distribution.
> > +#
> > +# * Neither the name of Marvell nor the names of its contributors may be
> > +# used to endorse or promote products derived from this software
> without
> > +# specific prior written permission.
> > +#
> > +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> > CONTRIBUTORS "AS IS"
> > +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> > LIMITED TO, THE
> > +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
> > PARTICULAR PURPOSE ARE
> > +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> > CONTRIBUTORS BE LIABLE
> > +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> > CONSEQUENTIAL
> > +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
> > SUBSTITUTE GOODS OR
> > +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> INTERRUPTION)
> > HOWEVER
> > +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
> > STRICT LIABILITY,
> > +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
> WAY
> > OUT OF THE USE
> > +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> > DAMAGE.
> > +#
> > +
> > +#
> > +# Portions Copyright (C) 2016 Broadcom
> > +#
> > +
> > +[Defines]
> > + INF_VERSION = 0x00010006
> > + BASE_NAME = UefiShellGptCommandLib
> > + FILE_GUID = F62ACF25-0D15-22F5-E642-FFB6515E00D7
> > + MODULE_TYPE = UEFI_APPLICATION
> > + VERSION_STRING = 0.1
> > + LIBRARY_CLASS = NULL|UEFI_APPLICATION UEFI_DRIVER
> > + CONSTRUCTOR = ShellGptLibConstructor
> > + DESTRUCTOR = ShellGptLibDestructor
> > +
> > +[Sources]
> > + FatFormat.c
> > + GptWorker.c
> > + UefiShellGptCommandLib.c
> > + UefiShellGptCommandLib.uni
> > +
> > +[Packages]
> > + MdeModulePkg/MdeModulePkg.dec
> > + MdePkg/MdePkg.dec
> > + ShellPkg/ShellPkg.dec
> > +
> > +[LibraryClasses]
> > + BaseLib
> > + BaseMemoryLib
> > + DebugLib
> > + DevicePathLib
> > + FileHandleLib
> > + HiiLib
> > + MemoryAllocationLib
> > + PcdLib
> > + ShellCommandLib
> > + ShellLib
> > + UefiBootServicesTableLib
> > + UefiRuntimeServicesTableLib
> > + UefiLib
> > +
> > +[Protocols]
> > + gEfiBlockIoProtocolGuid
> > + gEfiDevicePathProtocolGuid
> > + gEfiDiskIoProtocolGuid
> > +
> > +[Guids]
> > + gShellGptHiiGuid
> > + gEfiPartTypeUnusedGuid ## SOMETIMES_CONSUMES ##
> GUID
> > diff --git
> >
> a/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
> >
> b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
> > new file mode 100644
> > index 000000000000..55bcb42cfeb3
> > --- /dev/null
> > +++
> >
> b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
> > @@ -0,0 +1,117 @@
> >
> +/*********************************************************
> > **********************
> > +Copyright (C) 2016 Marvell International Ltd.
> > +
> > +Marvell BSD License Option
> > +
> > +If you received this File from Marvell, you may opt to use, redistribute
> > and/or
> > +modify this File under the following licensing terms.
> > +Redistribution and use in source and binary forms, with or without
> > modification,
> > +are permitted provided that the following conditions are met:
> > +
> > + * Redistributions of source code must retain the above copyright
> notice,
> > + this list of conditions and the following disclaimer.
> > +
> > + * Redistributions in binary form must reproduce the above copyright
> > + notice, this list of conditions and the following disclaimer in the
> > + documentation and/or other materials provided with the distribution.
> > +
> > + * Neither the name of Marvell nor the names of its contributors may
> be
> > + used to endorse or promote products derived from this software
> > without
> > + specific prior written permission.
> > +
> > +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> > CONTRIBUTORS "AS IS" AND
> > +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
> TO,
> > THE IMPLIED
> > +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> > PURPOSE ARE
> > +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> > CONTRIBUTORS BE LIABLE FOR
> > +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> > CONSEQUENTIAL DAMAGES
> > +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
> GOODS
> > OR SERVICES;
> > +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
> HOWEVER
> > CAUSED AND ON
> > +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> > TORT
> > +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
> > THE USE OF THIS
> > +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> > +
> >
> +*********************************************************
> > **********************/
> > +
> > +/* Portions Copyright (C) 2016 Broadcom */
> > +/=#
> > +
> > +#langdef en-US "english"
> > +
> > +#string STR_GEN_PARAM_INV #language en-US "%H%s%N: Invalid
> > argument - '%H%s%N'\r\n"
> > +#string STR_GEN_MAP_PROTOCOL #language en-US "%H%s%N:
> > Mapped device '%B%s%N' does not have protocol %B%s%N\r\n"
> > +
> > +#string STR_GPT_ERROR #language en-US "%H%s%N: %r - %s\r\n"
> > +#string STR_GPT_NOT_EMPTY #language en-US "%H%s%N:
> WARNING!!!
> > This device has valid GPT partition tables!\r\n"
> > +#string STR_GPT_CLEAR_SURE #language en-US "Are you sure you
> want
> > to clear the GPT tables on this device? %BY%Nes, %BN%No "
> > +#string STR_GPT_ABSOLUTELY_SURE #language en-US "\r\nAre you ***
> > ABSOLUTELY SURE *** you want to perform this
> > operation ? %BY%Nes, %BN%No "
> > +#string STR_GPT_FORMAT_WARNING #language en-US "%H%s%N:
> > WARNING!!! Formatting of this partition will destroy all data on it!\r\n"
> > +#string STR_GPT_FORMAT_SURE #language en-US "Are you sure you
> > want to format this partition to FAT32 and destroy all data on
> > it ? %BY%Nes, %BN%No "
> > +#string STR_GPT_DELETE_WARNING #language en-US "%H%s%N:
> Deleting
> > of this partition will make data on it unreachable!\r\n"
> > +#string STR_GPT_READ_BOUNDARY #language en-US "%H%s%N:
> Attempt
> > to read beyond %H%s%N partition boundary (can read upto %llu bytes
> from
> > the given offset, requested %llu bytes)\r\n"
> > +#string STR_GPT_WRITE_BOUNDARY #language en-US "%H%s%N:
> > Attempt to write beyond %H%s%N partition boundary (can write upto %llu
> > bytes from the given offset, requested %llu bytes)\r\n"
> > +#string STR_GPT_FILE_WRITE_FAIL #language en-US "%H%s%N: Failed to
> > write to the file %s, error %r\r\n"
> > +
> > +#string STR_GPT_WRITE_OK #language en-US "Written %llu bytes at
> > offset 0x%x, partition %s. Elapsed time %llums (%llu KB/s)\r\n"
> > +#string STR_GPT_READ_OK #language en-US "Read %llu bytes from
> > offset 0x%x, partition %s. Elapsed time %llums (%llu KB/s)\r\n"
> > +#string STR_GPT_READFILE_OK #language en-US "Read %llu bytes from
> > offset 0x%x, partition %s into file %s. Elapsed time %llums (%llu KB/s)\r\n"
> > +#string STR_GPT_LIST_DEVS #language en-US " %H%+6s%N %+8s "
> > +
> > +#string STR_GET_HELP_GPT #language en-US ""
> > +".TH gpt 0 "GPT partition manager."\r\n"
> > +".SH NAME\r\n"
> > +"Manages GPT partitions on a block device.\r\n"
> > +".SH SYNOPSIS\r\n"
> > +" \r\n"
> > +"gpt [read | readfile | write | writefile | list | info | clear |\r\n"
> > +" create | delete | rename | setattrs | sync | fatformat | -typesinfo | -
> yes]
> > \r\n"
> > +"This is a complex utility. Please see examples for usage info\r\n"
> > +".SH OPTIONS\r\n"
> > +" \r\n"
> > +" Device - Block device to be used for the operation\r\n"
> > +" Length - Number of bytes to transfer (for read/write))\r\n"
> > +" Address - Address in RAM to store/load data\r\n"
> > +" Offset - Offset (in blocks) from beggining of the specifie partition to
> > store/load data\r\n"
> > +" FilePath - Path to file to read data into or write/update data
> from\r\n"
> > +" -yes - Assume yes for all queries, do not prompt\r\n\r\n"
> > +".SH EXAMPLES\r\n"
> > +" \r\n"
> > +"EXAMPLES:\r\n"
> > +"Get the list of available partitionable block device(s)\r\n"
> > +" gpt %Hlist%N\r\n"
> > +"Get info on the particular partition with name PartitionName on the
> block
> > device blk0:\r\n"
> > +" gpt %Hinfo%N blk0: PartitionName\r\n"
> > +"List all available GPT partitions on the block device blk0:\r\n"
> > +" gpt list blk0:\r\n"
> > +"Note: the ordinal number shown by this command can be used as a
> > partition name in any command requiring partition name\r\n"
> > +"Thus gpt info blk0: 1 is valid if there is a partition with ordinal 1 present in
> > the output of gpt list command\r\n"
> > +"Get information on all recognized partition types\r\n"
> > +" gpt %Htypesinfo%N\r\n"
> > +"Clear partitions information and install empty GPT tables for a block
> device
> > blk0:\r\n"
> > +" gpt %Hclear%N blk0:\r\n"
> > +"Create a GPT partition with name PartitionName and type EFI SYSTEM in
> > the GPT table, using the next available LBA, with size\r\n"
> > +"64MiB, with system attribute, on block device blk0:\r\n"
> > +" gpt %Hcreate%N blk0: PartitionName 0 64 1 -type 0\r\n"
> > +"Same as above, but now the partition type is not known to the gpt utility,
> > so use some GUID known to a 3rd party\r\n"
> > +" gpt create blk0: PartitionName 0 64 1 -type 44581A4A-C834-D1A6-2602-
> > 9D522A8F2307\r\n"
> > +"Rename the GPT partition PartitionName on blk0: to
> > NewPartitionName\r\n"
> > +" gpt %Hrename%N blk0: PartitionName NewPartitionName\r\n"
> > +"Have the PartitionDxe driver to re-read GPT tables on a block device
> > blk0:(after they were updated with gpt utility)\r\n"
> > +" gpt %Hsync%N blk0:\r\n"
> > +"Read 4K from block offset 0x0e000 in Partition named PartitionName of
> > the block device at blk0: into RAM at address 0x100000\r\n"
> > +" gpt %Hread%N blk0: 0x100000 PartitionName 0xe000 4096\r\n"
> > +"Write 512 bytes from 0x200000 at RAM into the block device at blk0:
> > partition PartitionName at offset 0x1000\r\n"
> > +" gpt %Hwrite%N blk0: 0x200000 PartitionName 0x1000 512\r\n"
> > +"Read 0x3000 bytes from 0x0 offset of Partition PartitionName at the
> block
> > device blk0: into file fs2:file.bin\r\n"
> > +" gpt %Hreadfile%N blk0: fs2:file.bin PartitionName 0x0 0x3000\r\n"
> > +"Write contents of file fs2:file.bin into partition named PartitionName
> with
> > offset (in lba) 0x10 on a block device blk0:\r\n"
> > +" gpt %Hwritefile%N blk0: fs2:file.bin PartitionName 0x10\r\n"
> > +"FAT Format the partition PartitionName on block device blk0:\r\n"
> > +" gpt %Hfatformat%N blk0: PartitionName\r\n"
> > +"FAT Format the whole device blk0:\r\n"
> > +" gpt fatformat blk0:\r\n"
> > +
> > +".SH RETURNVALUES\r\n"
> > +" \r\n"
> > +"RETURN VALUES:\r\n"
> > +" SHELL_SUCCESS The action was completed as requested.\r\n"
> > +" Specific Shell error Error while processing command\r\n"
> > diff --git a/ShellPkg/ShellPkg.dec b/ShellPkg/ShellPkg.dec
> > index 39f8012b98c1..5374a2a62d5f 100644
> > --- a/ShellPkg/ShellPkg.dec
> > +++ b/ShellPkg/ShellPkg.dec
> > @@ -56,6 +56,7 @@ [Guids]
> > gShellNetwork2HiiGuid = {0x174b2b5, 0xf505, 0x4b12, {0xaa, 0x60,
> > 0x59, 0xdf, 0xf8, 0xd6, 0xea, 0x37}}
> > gShellTftpHiiGuid = {0x738a9314, 0x82c1, 0x4592, {0x8f, 0xf7, 0xc1,
> > 0xbd, 0xf1, 0xb2, 0x0e, 0xd4}}
> > gShellBcfgHiiGuid = {0x5f5f605d, 0x1583, 0x4a2d, {0xa6, 0xb2, 0xeb,
> > 0x12, 0xda, 0xb4, 0xa2, 0xb6}}
> > + gShellGptHiiGuid = {0x5a1ed739, 0x5ef1, 0x429a, {0x8d, 0xf8, 0x28,
> > 0xc9, 0x92, 0x64, 0xd7, 0xf8}}
> >
> > [Protocols]
> > gEfiShellProtocolGuid = {0x6302d008, 0x7f9b, 0x4f30, {0x87, 0xac,
> > 0x60, 0xc9, 0xfe, 0xf5, 0xda, 0x4e}}
> > diff --git a/ShellPkg/ShellPkg.dsc b/ShellPkg/ShellPkg.dsc
> > index 809bd4220af2..984c1d0ad48b 100644
> > --- a/ShellPkg/ShellPkg.dsc
> > +++ b/ShellPkg/ShellPkg.dsc
> > @@ -89,6 +89,7 @@ [Components]
> >
> >
> ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib
> > .inf
> >
> >
> ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib
> > .inf
> >
> >
> ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsL
> > ib.inf
> > +
> ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> >
> >
> ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLi
> > b.inf
> >
> >
> ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1Commands
> > Lib.inf
> >
> >
> ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1Comm
> > andsLib.inf
> > @@ -119,6 +120,9 @@ [Components]
> > !ifdef $(INCLUDE_TFTP_COMMAND)
> >
> >
> NULL|ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib
> > .inf
> > !endif #$(INCLUDE_TFTP_COMMAND)
> > +!ifdef $(INCLUDE_GPT_COMMAND)
> > +
> >
> NULL|ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.
> > inf
> > +!endif #$(INCLUDE_GPT_COMMAND)
> > !endif #$(NO_SHELL_PROFILES)
> > }
> >
> > --
> > 1.9.1
>
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] GPT Shell Application/Library
2016-10-18 1:55 ` Ni, Ruiyu
@ 2016-10-18 2:59 ` Carsey, Jaben
0 siblings, 0 replies; 20+ messages in thread
From: Carsey, Jaben @ 2016-10-18 2:59 UTC (permalink / raw)
To: Ni, Ruiyu, Tim Lewis, Vladimir Olovyannikov,
edk2-devel@lists.01.org
Cc: Carsey, Jaben
We already have additional libraries that people can compile at will for things like DP and TFTP. We only include the documented commands in our binary shell deliveries. I think that we can allow a library and could even consume that library and make a stand alone GPT.efi.
I think that the GPT command should not be included in the ShellBinPkg for sure.
-JAben
> -----Original Message-----
> From: Ni, Ruiyu
> Sent: Monday, October 17, 2016 6:55 PM
> To: Tim Lewis <tim.lewis@insyde.com>; Vladimir Olovyannikov
> <vladimir.olovyannikov@broadcom.com>; Carsey, Jaben
> <jaben.carsey@intel.com>; edk2-devel@lists.01.org
> Subject: RE: [PATCH] GPT Shell Application/Library
> Importance: High
>
> Or we could have a common wrapper module, that links to different library to
> provide different <command>.efi.
> This will require the name of the wrapper module is customizable. Haven't tried
> on that, seems doable.
>
> Thanks/Ray
>
> > -----Original Message-----
> > From: Tim Lewis [mailto:tim.lewis@insyde.com]
> > Sent: Tuesday, October 18, 2016 9:48 AM
> > To: Ni, Ruiyu <ruiyu.ni@intel.com>; Vladimir Olovyannikov
> > <vladimir.olovyannikov@broadcom.com>; Carsey, Jaben
> > <jaben.carsey@intel.com>; edk2-devel@lists.01.org
> > Subject: RE: [PATCH] GPT Shell Application/Library
> >
> > We would prefer that this tool be external. Tim
> >
> > -----Original Message-----
> > From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of Ni,
> > Ruiyu
> > Sent: Monday, October 17, 2016 6:46 PM
> > To: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>; Carsey,
> > Jaben <jaben.carsey@intel.com>; edk2-devel@lists.01.org
> > Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> >
> > Jaben,
> > Do you think that providing a standalone gpt.efi is better? So that Shell.efi
> > only provides the internal commands listed in Shell spec.
> >
> > Thanks/Ray
> >
> > > -----Original Message-----
> > > From: Vladimir Olovyannikov
> > [mailto:vladimir.olovyannikov@broadcom.com]
> > > Sent: Sunday, October 16, 2016 1:24 PM
> > > To: Carsey, Jaben <jaben.carsey@intel.com>; edk2-devel@lists.01.org; Ni,
> > > Ruiyu <ruiyu.ni@intel.com>
> > > Cc: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>
> > > Subject: [PATCH] GPT Shell Application/Library
> > >
> > > This allows managing (create, delete, modify, fat format) of GPT
> > > partitions from within UEFI Shell.
> > > Syntax:
> > > gpt <command> [device_mapped_name] [parameters...]
> > > See usage examples in the .uni file
> > > ---
> > > .../Library/UefiShellGptCommandLib/FatFormat.c | 611 +++++++
> > > .../Library/UefiShellGptCommandLib/FatFormat.h | 111 ++
> > > .../Library/UefiShellGptCommandLib/GptWorker.c | 1902
> > > ++++++++++++++++++++
> > > .../Library/UefiShellGptCommandLib/GptWorker.h | 186 ++
> > > .../UefiShellGptCommandLib.c | 1135 ++++++++++++
> > > .../UefiShellGptCommandLib.inf | 79 +
> > > .../UefiShellGptCommandLib.uni | 117 ++
> > > ShellPkg/ShellPkg.dec | 1 +
> > > ShellPkg/ShellPkg.dsc | 4 +
> > > 9 files changed, 4146 insertions(+)
> > > create mode 100644
> > ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> > > create mode 100644
> > > ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> > > create mode 100644
> > > ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> > > create mode 100644
> > > ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> > > create mode 100644
> > > ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> > > create mode 100644
> > > ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> > > create mode 100644
> > > ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
> > >
> > > diff --git a/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> > > b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> > > new file mode 100644
> > > index 000000000000..ba7904e6be28
> > > --- /dev/null
> > > +++ b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> > > @@ -0,0 +1,611 @@
> > > +/** @file
> > > +
> > > + Copyright (c) 2003 - 2012, Rob Riglar, Ultra-Embedded.com. All rights
> > > reserved<BR>
> > > +
> > > + This program and the accompanying materials
> > > + are licensed and made available under the terms and conditions of the
> > BSD
> > > License
> > > + which accompanies this distribution. The full text of the license may be
> > > found at
> > > + http://opensource.org/licenses/bsd-license.php
> > > +
> > > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> > > BASIS,
> > > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> > > EXPRESS OR IMPLIED.
> > > +
> > > +**/
> > > +
> > > +/* Portions Copyright (c) 2016, Broadcom. All rights reserved */
> > > +
> > > +#include "FatFormat.h"
> > > +
> > > +//-----------------------------------------------------------------------------
> > > +// Tables
> > > +//-----------------------------------------------------------------------------
> > > +typedef struct
> > > +{
> > > + UINT64 Sectors;
> > > + UINT8 SectorsPerCluster;
> > > +} SectorsPerClusterTable;
> > > +
> > > +STATIC SectorsPerClusterTable ClusterSizeTable16[] =
> > > +{
> > > + { 32680, 2 }, // 16MB - 1K
> > > + { 262144, 4 }, // 128MB - 2K
> > > + { 524288, 8 }, // 256MB - 4K
> > > + { 1048576, 16 }, // 512MB - 8K
> > > + { 2097152, 32 }, // 1GB - 16K
> > > + { 4194304, 64 }, // 2GB - 32K
> > > + { 8388608, 128 }, // 2GB - 64K [Warning only supported by Windows XP
> > > onwards]
> > > + { 0, 0 } // Invalid
> > > +};
> > > +
> > > +STATIC SectorsPerClusterTable ClusterSizeTable32[] =
> > > +{
> > > + { 532480, 1 }, // 260MB - 512b
> > > + { 16777216, 8 }, // 8GB - 4K
> > > + { 33554432, 16 }, // 16GB - 8K
> > > + { 67108864, 32 }, // 32GB - 16K
> > > + { 0xFFFFFFFF, 64 }, // >32GB - 32K
> > > + { 0, 0 } // Invalid
> > > +};
> > > +
> > > +STATIC
> > > +EFI_LBA LbaOfCluster (
> > > + IN FATFS *Fs,
> > > + IN UINT64 ClusterNumber
> > > + )
> > > +{
> > > + if (Fs->FatType == FAT_TYPE_16)
> > > + return (Fs->ClusterBeginLba +
> > > + (Fs->RootEntryCount * 32 / FAT_SECTOR_SIZE) +
> > > + ((ClusterNumber - 2) * Fs->SectorsPerCluster));
> > > + else
> > > + return ((Fs->ClusterBeginLba +
> > > + ((ClusterNumber - 2) * Fs->SectorsPerCluster)));
> > > +}
> > > +
> > > +//-----------------------------------------------------------------------------
> > > +// fatfs_calc_cluster_size: Calculate what cluster size should be used
> > > +//-----------------------------------------------------------------------------
> > > +STATIC
> > > +UINT8 CalcClusterSize (
> > > + IN UINTN Sectors,
> > > + IN BOOLEAN IsFat32)
> > > +{
> > > + UINTN Index;
> > > +
> > > + if (!IsFat32) {
> > > + for (Index = 0; ClusterSizeTable16[Index].SectorsPerCluster != 0;
> > Index++)
> > > + if (Sectors <= ClusterSizeTable16[Index].Sectors)
> > > + return ClusterSizeTable16[Index].SectorsPerCluster;
> > > + } else {
> > > + for (Index = 0; ClusterSizeTable32[Index].SectorsPerCluster != 0;
> > Index++)
> > > + if (Sectors <= ClusterSizeTable32[Index].Sectors)
> > > + return ClusterSizeTable32[Index].SectorsPerCluster;
> > > + }
> > > +
> > > + return 0;
> > > +}
> > > +//-----------------------------------------------------------------------------
> > > +// fatfs_erase_sectors: Erase a number of sectors
> > > +//-----------------------------------------------------------------------------
> > > +STATIC
> > > +EFI_STATUS
> > > +EraseSectors (
> > > + IN FATFS *Fs,
> > > + IN EFI_LBA Lba,
> > > + IN UINTN Count
> > > + )
> > > +{
> > > + UINTN Index;
> > > + EFI_STATUS Status;
> > > +
> > > + // Zero Sector first
> > > + ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE);
> > > +
> > > + for (Index = 0; Index < Count; Index++)
> > > + Status = Fs->DiskIo->WriteDisk (
> > > + Fs->DiskIo, Fs->BlockIo->Media->MediaId,
> > > + MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) +
> > > + MultU64x32 ((Lba + Index), FAT_SECTOR_SIZE),
> > > + FAT_SECTOR_SIZE, Fs->CurrentSector.Sector);
> > > +
> > > + return Status;
> > > +}
> > > +//-----------------------------------------------------------------------------
> > > +// fatfs_create_boot_sector: Create the boot Sector
> > > +//-----------------------------------------------------------------------------
> > > +STATIC
> > > +EFI_STATUS
> > > +CreateBootSector (
> > > + IN FATFS *Fs,
> > > + IN EFI_LBA BootSectorLba,
> > > + IN UINT64 VolSectors,
> > > + IN CONST CHAR8 *Name,
> > > + IN BOOLEAN IsFat32
> > > + )
> > > +{
> > > + UINTN TotalClusters;
> > > + UINTN Index;
> > > + EFI_STATUS Status;
> > > +
> > > + // Zero Sector initially
> > > + ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE);
> > > +
> > > + // OEM Name & Jump Code
> > > + Fs->CurrentSector.Sector[0] = 0xEB;
> > > + Fs->CurrentSector.Sector[1] = 0x3C;
> > > + Fs->CurrentSector.Sector[2] = 0x90;
> > > + Fs->CurrentSector.Sector[3] = 0x4D;
> > > + Fs->CurrentSector.Sector[4] = 0x53;
> > > + Fs->CurrentSector.Sector[5] = 0x44;
> > > + Fs->CurrentSector.Sector[6] = 0x4F;
> > > + Fs->CurrentSector.Sector[7] = 0x53;
> > > + Fs->CurrentSector.Sector[8] = 0x35;
> > > + Fs->CurrentSector.Sector[9] = 0x2E;
> > > + Fs->CurrentSector.Sector[10] = 0x30;
> > > +
> > > + // Bytes per Sector
> > > + Fs->CurrentSector.Sector[11] = (FAT_SECTOR_SIZE >> 0) & 0xFF;
> > > + Fs->CurrentSector.Sector[12] = (FAT_SECTOR_SIZE >> 8) & 0xFF;
> > > +
> > > + // Get sectors per cluster size for the disk
> > > + Fs->SectorsPerCluster = CalcClusterSize (VolSectors, IsFat32);
> > > + if (!Fs->SectorsPerCluster)
> > > + return 0; // Invalid disk size
> > > +
> > > + // Sectors per cluster
> > > + Fs->CurrentSector.Sector[13] = Fs->SectorsPerCluster;
> > > +
> > > + // Reserved Sectors
> > > + if (!IsFat32)
> > > + Fs->ReservedSectors = 8;
> > > + else
> > > + Fs->ReservedSectors = 32;
> > > + Fs->CurrentSector.Sector[14] = (Fs->ReservedSectors >> 0) & 0xFF;
> > > + Fs->CurrentSector.Sector[15] = (Fs->ReservedSectors >> 8) & 0xFF;
> > > +
> > > + // Number of FATS
> > > + Fs->NumOfFats = 2;
> > > + Fs->CurrentSector.Sector[16] = Fs->NumOfFats;
> > > +
> > > + // Max entries in root dir (FAT16 only)
> > > + if (!IsFat32) {
> > > + Fs->RootEntryCount = 512;
> > > + Fs->CurrentSector.Sector[17] = (Fs->RootEntryCount >> 0) & 0xFF;
> > > + Fs->CurrentSector.Sector[18] = (Fs->RootEntryCount >> 8) & 0xFF;
> > > + } else {
> > > + Fs->RootEntryCount = 0;
> > > + Fs->CurrentSector.Sector[17] = 0;
> > > + Fs->CurrentSector.Sector[18] = 0;
> > > + }
> > > +
> > > + // [FAT16] Total sectors (use FAT32 count instead)
> > > + Fs->CurrentSector.Sector[19] = 0x00;
> > > + Fs->CurrentSector.Sector[20] = 0x00;
> > > +
> > > + // Media type
> > > + Fs->CurrentSector.Sector[21] = 0xF8;
> > > +
> > > +
> > > + // FAT16 BS Details
> > > + if (!IsFat32) {
> > > + // Count of sectors used by the FAT table (FAT16 only)
> > > + TotalClusters = (VolSectors / Fs->SectorsPerCluster) + 1;
> > > + Fs->FatSectors = (TotalClusters / (FAT_SECTOR_SIZE / 2)) + 1;
> > > + Fs->CurrentSector.Sector[22] = (UINT8)((Fs->FatSectors >> 0) & 0xFF);
> > > + Fs->CurrentSector.Sector[23] = (UINT8)((Fs->FatSectors >> 8) & 0xFF);
> > > +
> > > + // Sectors per track
> > > + Fs->CurrentSector.Sector[24] = 0x00;
> > > + Fs->CurrentSector.Sector[25] = 0x00;
> > > +
> > > + // Heads
> > > + Fs->CurrentSector.Sector[26] = 0x00;
> > > + Fs->CurrentSector.Sector[27] = 0x00;
> > > +
> > > + // Hidden sectors
> > > + Fs->CurrentSector.Sector[28] = 0x20;
> > > + Fs->CurrentSector.Sector[29] = 0x00;
> > > + Fs->CurrentSector.Sector[30] = 0x00;
> > > + Fs->CurrentSector.Sector[31] = 0x00;
> > > +
> > > + // Total sectors for this volume
> > > + Fs->CurrentSector.Sector[32] = (UINT8)((VolSectors >> 0) & 0xFF);
> > > + Fs->CurrentSector.Sector[33] = (UINT8)((VolSectors >> 8) & 0xFF);
> > > + Fs->CurrentSector.Sector[34] = (UINT8)((VolSectors >> 16) & 0xFF);
> > > + Fs->CurrentSector.Sector[35] = (UINT8)((VolSectors >> 24) & 0xFF);
> > > +
> > > + // Drive number
> > > + Fs->CurrentSector.Sector[36] = 0x00;
> > > +
> > > + // Reserved
> > > + Fs->CurrentSector.Sector[37] = 0x00;
> > > +
> > > + // Boot signature
> > > + Fs->CurrentSector.Sector[38] = 0x29;
> > > +
> > > + // Volume ID
> > > + Fs->CurrentSector.Sector[39] = 0x12;
> > > + Fs->CurrentSector.Sector[40] = 0x34;
> > > + Fs->CurrentSector.Sector[41] = 0x56;
> > > + Fs->CurrentSector.Sector[42] = 0x78;
> > > +
> > > + // Volume name
> > > + for (Index = 0; Index < 11; Index++) {
> > > + if (Index < AsciiStrLen (Name))
> > > + Fs->CurrentSector.Sector[Index + 43] = Name[Index];
> > > + else
> > > + Fs->CurrentSector.Sector[Index + 43] = ' ';
> > > + }
> > > +
> > > + // File sys type
> > > + Fs->CurrentSector.Sector[54] = 'F';
> > > + Fs->CurrentSector.Sector[55] = 'A';
> > > + Fs->CurrentSector.Sector[56] = 'T';
> > > + Fs->CurrentSector.Sector[57] = '1';
> > > + Fs->CurrentSector.Sector[58] = '6';
> > > + Fs->CurrentSector.Sector[59] = ' ';
> > > + Fs->CurrentSector.Sector[60] = ' ';
> > > + Fs->CurrentSector.Sector[61] = ' ';
> > > +
> > > + // Signature
> > > + Fs->CurrentSector.Sector[510] = 0x55;
> > > + Fs->CurrentSector.Sector[511] = 0xAA;
> > > + }
> > > + // FAT32 BS Details
> > > + else {
> > > + // Count of sectors used by the FAT table (FAT16 only)
> > > + Fs->CurrentSector.Sector[22] = 0;
> > > + Fs->CurrentSector.Sector[23] = 0;
> > > +
> > > + // Sectors per track (default)
> > > + Fs->CurrentSector.Sector[24] = 0x3F;
> > > + Fs->CurrentSector.Sector[25] = 0x00;
> > > +
> > > + // Heads (default)
> > > + Fs->CurrentSector.Sector[26] = 0xFF;
> > > + Fs->CurrentSector.Sector[27] = 0x00;
> > > +
> > > + // Hidden sectors
> > > + Fs->CurrentSector.Sector[28] = 0x00;
> > > + Fs->CurrentSector.Sector[29] = 0x00;
> > > + Fs->CurrentSector.Sector[30] = 0x00;
> > > + Fs->CurrentSector.Sector[31] = 0x00;
> > > +
> > > + // Total sectors for this volume
> > > + Fs->CurrentSector.Sector[32] = (UINT8)((VolSectors >> 0) & 0xFF);
> > > + Fs->CurrentSector.Sector[33] = (UINT8)((VolSectors >> 8) & 0xFF);
> > > + Fs->CurrentSector.Sector[34] = (UINT8)((VolSectors >> 16) & 0xFF);
> > > + Fs->CurrentSector.Sector[35] = (UINT8)((VolSectors >> 24) & 0xFF);
> > > +
> > > + TotalClusters = (VolSectors / Fs->SectorsPerCluster) + 1;
> > > + Fs->FatSectors = (TotalClusters / (FAT_SECTOR_SIZE / 4)) + 1;
> > > +
> > > + // BPB_FATSz32
> > > + Fs->CurrentSector.Sector[36] = (UINT8)((Fs->FatSectors >> 0) & 0xFF);
> > > + Fs->CurrentSector.Sector[37] = (UINT8)((Fs->FatSectors >> 8) & 0xFF);
> > > + Fs->CurrentSector.Sector[38] = (UINT8)((Fs->FatSectors >> 16) & 0xFF);
> > > + Fs->CurrentSector.Sector[39] = (UINT8)((Fs->FatSectors >> 24) & 0xFF);
> > > +
> > > + // BPB_ExtFlags
> > > + Fs->CurrentSector.Sector[40] = 0;
> > > + Fs->CurrentSector.Sector[41] = 0;
> > > +
> > > + // BPB_FSVer
> > > + Fs->CurrentSector.Sector[42] = 0;
> > > + Fs->CurrentSector.Sector[43] = 0;
> > > +
> > > + // BPB_RootClus
> > > + Fs->CurrentSector.Sector[44] = (UINT8)((Fs->RootdirFirstCluster >> 0) &
> > > 0xFF);
> > > + Fs->CurrentSector.Sector[45] = (UINT8)((Fs->RootdirFirstCluster >> 8) &
> > > 0xFF);
> > > + Fs->CurrentSector.Sector[46] = (UINT8)((Fs->RootdirFirstCluster >> 16)
> > &
> > > 0xFF);
> > > + Fs->CurrentSector.Sector[47] = (UINT8)((Fs->RootdirFirstCluster >> 24)
> > &
> > > 0xFF);
> > > +
> > > + // BPB_FSInfo
> > > + Fs->CurrentSector.Sector[48] = (UINT8)((Fs->FsInfoSector >> 0) & 0xFF);
> > > + Fs->CurrentSector.Sector[49] = (UINT8)((Fs->FsInfoSector >> 8) & 0xFF);
> > > +
> > > + // BPB_BkBootSec
> > > + Fs->CurrentSector.Sector[50] = 6;
> > > + Fs->CurrentSector.Sector[51] = 0;
> > > +
> > > + // Drive number
> > > + Fs->CurrentSector.Sector[64] = 0x00;
> > > +
> > > + // Boot signature
> > > + Fs->CurrentSector.Sector[66] = 0x29;
> > > +
> > > + // Volume ID
> > > + Fs->CurrentSector.Sector[67] = 0x12;
> > > + Fs->CurrentSector.Sector[68] = 0x34;
> > > + Fs->CurrentSector.Sector[69] = 0x56;
> > > + Fs->CurrentSector.Sector[70] = 0x78;
> > > +
> > > + // Volume name
> > > + for (Index = 0; Index < 11; Index++) {
> > > + if (Index < (int)AsciiStrLen (Name))
> > > + Fs->CurrentSector.Sector[Index + 71] = Name[Index];
> > > + else
> > > + Fs->CurrentSector.Sector[Index + 71] = ' ';
> > > + }
> > > +
> > > + // File sys type
> > > + Fs->CurrentSector.Sector[82] = 'F';
> > > + Fs->CurrentSector.Sector[83] = 'A';
> > > + Fs->CurrentSector.Sector[84] = 'T';
> > > + Fs->CurrentSector.Sector[85] = '3';
> > > + Fs->CurrentSector.Sector[86] = '2';
> > > + Fs->CurrentSector.Sector[87] = ' ';
> > > + Fs->CurrentSector.Sector[88] = ' ';
> > > + Fs->CurrentSector.Sector[89] = ' ';
> > > +
> > > + // Signature
> > > + Fs->CurrentSector.Sector[510] = 0x55;
> > > + Fs->CurrentSector.Sector[511] = 0xAA;
> > > + }
> > > +
> > > + Status = Fs->DiskIo->WriteDisk (
> > > + Fs->DiskIo, Fs->BlockIo->Media->MediaId,
> > > + MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) +
> > > + MultU64x32 (Fs->FatBeginLba, FAT_SECTOR_SIZE),
> > > + FAT_SECTOR_SIZE,
> > > + Fs->CurrentSector.Sector);
> > > +
> > > + return Status;
> > > +}
> > > +//-----------------------------------------------------------------------------
> > > +// fatfs_create_fsinfo_sector: Create the FSInfo Sector (FAT32)
> > > +//-----------------------------------------------------------------------------
> > > +STATIC
> > > +EFI_STATUS
> > > +CreateFsinfoSector (
> > > + IN FATFS *Fs,
> > > + IN EFI_LBA SectorLba
> > > + )
> > > +{
> > > + EFI_STATUS Status;
> > > +
> > > + // Zero Sector initially
> > > + ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE);
> > > +
> > > + // FSI_LeadSig
> > > + Fs->CurrentSector.Sector[0] = 0x52;
> > > + Fs->CurrentSector.Sector[1] = 0x52;
> > > + Fs->CurrentSector.Sector[2] = 0x61;
> > > + Fs->CurrentSector.Sector[3] = 0x41;
> > > +
> > > + // FSI_StrucSig
> > > + Fs->CurrentSector.Sector[484] = 0x72;
> > > + Fs->CurrentSector.Sector[485] = 0x72;
> > > + Fs->CurrentSector.Sector[486] = 0x41;
> > > + Fs->CurrentSector.Sector[487] = 0x61;
> > > +
> > > + // FSI_Free_Count
> > > + Fs->CurrentSector.Sector[488] = 0xFF;
> > > + Fs->CurrentSector.Sector[489] = 0xFF;
> > > + Fs->CurrentSector.Sector[490] = 0xFF;
> > > + Fs->CurrentSector.Sector[491] = 0xFF;
> > > +
> > > + // FSI_Nxt_Free
> > > + Fs->CurrentSector.Sector[492] = 0xFF;
> > > + Fs->CurrentSector.Sector[493] = 0xFF;
> > > + Fs->CurrentSector.Sector[494] = 0xFF;
> > > + Fs->CurrentSector.Sector[495] = 0xFF;
> > > +
> > > + // Signature
> > > + Fs->CurrentSector.Sector[510] = 0x55;
> > > + Fs->CurrentSector.Sector[511] = 0xAA;
> > > +
> > > + Status = Fs->DiskIo->WriteDisk (
> > > + Fs->DiskIo, Fs->BlockIo->Media->MediaId,
> > > + MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) +
> > > + MultU64x32 (SectorLba, FAT_SECTOR_SIZE),
> > > + FAT_SECTOR_SIZE,
> > > + Fs->CurrentSector.Sector);
> > > +
> > > + return Status;
> > > +}
> > > +//-----------------------------------------------------------------------------
> > > +// fatfs_erase_fat: Erase FAT table using fs details in fs struct
> > > +//-----------------------------------------------------------------------------
> > > +STATIC
> > > +EFI_STATUS
> > > +EraseFat (
> > > + IN FATFS *Fs,
> > > + IN BOOLEAN IsFat32)
> > > +{
> > > + UINTN Index;
> > > + EFI_STATUS Status;
> > > +
> > > + // Zero Sector initially
> > > + ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE);
> > > +
> > > + // Initialise default allocate / reserved clusters
> > > + if (!IsFat32) {
> > > + SET_16BIT_WORD (Fs->CurrentSector.Sector, 0, 0xFFF8);
> > > + SET_16BIT_WORD (Fs->CurrentSector.Sector, 2, 0xFFFF);
> > > + } else {
> > > + SET_32BIT_WORD (Fs->CurrentSector.Sector, 0, 0x0FFFFFF8);
> > > + SET_32BIT_WORD (Fs->CurrentSector.Sector, 4, 0xFFFFFFFF);
> > > + SET_32BIT_WORD (Fs->CurrentSector.Sector, 8, 0x0FFFFFFF);
> > > + }
> > > +
> > > + Status = Fs->DiskIo->WriteDisk (
> > > + Fs->DiskIo, Fs->BlockIo->Media->MediaId,
> > > + MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) +
> > > + MultU64x32 (Fs->FatBeginLba, FAT_SECTOR_SIZE),
> > > + FAT_SECTOR_SIZE,
> > > + Fs->CurrentSector.Sector);
> > > + if (EFI_ERROR (Status)) {
> > > + return Status;
> > > + }
> > > +
> > > + // Zero remaining FAT sectors
> > > + ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE);
> > > + for (Index = 1; Index < Fs->FatSectors * Fs->NumOfFats; Index++) {
> > > + Status = Fs->DiskIo->WriteDisk (
> > > + Fs->DiskIo,
> > > + Fs->BlockIo->Media->MediaId,
> > > + MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) +
> > > + MultU64x32 ((Fs->FatBeginLba + Index), FAT_SECTOR_SIZE),
> > > + FAT_SECTOR_SIZE,
> > > + Fs->CurrentSector.Sector);
> > > + if (EFI_ERROR (Status)) {
> > > + return Status;
> > > + }
> > > + }
> > > + return Status;
> > > +}
> > > +//-----------------------------------------------------------------------------
> > > +// fatfs_format_fat16: Format a FAT16 partition
> > > +//-----------------------------------------------------------------------------
> > > +STATIC
> > > +EFI_STATUS
> > > +FormatFat16 (
> > > + IN FATFS *Fs,
> > > + IN UINT64 VolumeSectors,
> > > + IN CONST CHAR8 *Name
> > > + )
> > > +{
> > > + EFI_STATUS Status;
> > > +
> > > + Fs->CurrentSector.Address = FAT32_INVALID_CLUSTER;
> > > + Fs->CurrentSector.Dirty = 0;
> > > +
> > > + Fs->NextFreeCluster = 0; // Invalid
> > > +
> > > + // Volume is FAT16
> > > + Fs->FatType = FAT_TYPE_16;
> > > +
> > > + // Not valid for FAT16
> > > + Fs->FsInfoSector = 0;
> > > + Fs->RootdirFirstCluster = 0;
> > > +
> > > + Fs->LbaBegin = 0;
> > > + Status = CreateBootSector (Fs, Fs->LbaBegin, VolumeSectors, Name, 0);
> > > + if (EFI_ERROR (Status)) {
> > > + return Status;
> > > + }
> > > +
> > > + // For FAT16 (which this may be), RootdirFirstCluster is actuall
> > > RootdirFirstSector
> > > + Fs->RootdirFirstSector = Fs->ReservedSectors + (Fs->NumOfFats * Fs-
> > > >FatSectors);
> > > + Fs->RootdirSectors = ((Fs->RootEntryCount * 32) +
> > > + (FAT_SECTOR_SIZE - 1)) / FAT_SECTOR_SIZE;
> > > +
> > > + // First FAT LBA Address
> > > + Fs->FatBeginLba = Fs->LbaBegin + Fs->ReservedSectors;
> > > +
> > > + // The Address of the first data cluster on this volume
> > > + Fs->ClusterBeginLba = Fs->FatBeginLba +
> > > + (Fs->NumOfFats * Fs->FatSectors);
> > > +
> > > + // Initialise FAT sectors
> > > + Status = EraseFat (Fs, 0);
> > > + if (EFI_ERROR (Status)) {
> > > + return Status;
> > > + }
> > > +
> > > + // Erase Root directory
> > > + Status = EraseSectors (
> > > + Fs,
> > > + Fs->LbaBegin + Fs->RootdirFirstSector,
> > > + Fs->RootdirSectors);
> > > +
> > > + return Status;
> > > +}
> > > +//-----------------------------------------------------------------------------
> > > +// fatfs_format_fat32: Format a FAT32 partition
> > > +//-----------------------------------------------------------------------------
> > > +STATIC
> > > +EFI_STATUS
> > > +FormatFat32 (
> > > + IN FATFS *Fs,
> > > + IN UINTN VolumeSectors,
> > > + IN CONST CHAR8 *Name
> > > + )
> > > +{
> > > + EFI_STATUS Status;
> > > +
> > > + Fs->CurrentSector.Address = FAT32_INVALID_CLUSTER;
> > > + Fs->CurrentSector.Dirty = 0;
> > > +
> > > + Fs->NextFreeCluster = 0; // Invalid
> > > +
> > > + // Volume is FAT32
> > > + Fs->FatType = FAT_TYPE_32;
> > > +
> > > + // Basic defaults for normal FAT32 partitions
> > > + Fs->FsInfoSector = 1;
> > > + Fs->RootdirFirstCluster = 2;
> > > +
> > > + // Sector 0: Boot Sector
> > > + // NOTE: We don't need an MBR, it is a waste of a good Sector!
> > > + Fs->LbaBegin = 0;
> > > + Status = CreateBootSector (Fs, Fs->LbaBegin, VolumeSectors, Name, 1);
> > > + if (EFI_ERROR (Status)) {
> > > + return Status;
> > > + }
> > > +
> > > + // First FAT LBA address
> > > + Fs->FatBeginLba = Fs->LbaBegin + Fs->ReservedSectors;
> > > +
> > > + // The address of the first data cluster on this volume
> > > + Fs->ClusterBeginLba = Fs->FatBeginLba + (Fs->NumOfFats * Fs-
> > > >FatSectors);
> > > +
> > > + // Initialise FSInfo sector
> > > + Status = CreateFsinfoSector (Fs, Fs->FsInfoSector);
> > > + if (EFI_ERROR (Status)) {
> > > + return Status;
> > > + }
> > > +
> > > + // Initialise FAT sectors
> > > + Status = EraseFat (Fs, 1);
> > > + if (EFI_ERROR (Status)) {
> > > + return Status;
> > > + }
> > > +
> > > + // Erase Root directory
> > > + Status = EraseSectors (
> > > + Fs,
> > > + LbaOfCluster (Fs, Fs->RootdirFirstCluster),
> > > + Fs->SectorsPerCluster);
> > > +
> > > + return Status;
> > > +}
> > > +//-----------------------------------------------------------------------------
> > > +// fatfs_format: Format a partition with either FAT16 or FAT32 based on
> > size
> > > +//-----------------------------------------------------------------------------
> > > +EFI_STATUS
> > > +FatFormat (
> > > + IN EFI_LBA StartingLBA,
> > > + IN EFI_LBA EndingLBA,
> > > + IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
> > > + IN EFI_DISK_IO_PROTOCOL *DiskIo,
> > > + IN CHAR8 *VolumeName,
> > > + IN BOOLEAN ForceFat32
> > > + )
> > > +{
> > > + FATFS Fs;
> > > + UINT64 VolumeSectors;
> > > +
> > > + VolumeSectors = DivU64x32 (
> > > + MultU64x32 (
> > > + EndingLBA - StartingLBA + 1, BlockIo->Media->BlockSize),
> > > + FAT_SECTOR_SIZE);
> > > +
> > > + if (VolumeName == NULL) {
> > > + VolumeName = DEFAULT_FAT_LABEL_NAME;
> > > + }
> > > +
> > > + ZeroMem (&Fs, sizeof(Fs));
> > > +
> > > + Fs.StartingLBA = StartingLBA;
> > > + Fs.EndingLBA = EndingLBA;
> > > + Fs.BlockIo = BlockIo;
> > > + Fs.DiskIo = DiskIo;
> > > + // 2GB - 32K limit for safe behaviour for FAT16
> > > + if ((VolumeSectors <= 4194304) && (!ForceFat32)) {
> > > + return FormatFat16 (&Fs, VolumeSectors, VolumeName);
> > > + } else {
> > > + return FormatFat32 (&Fs, VolumeSectors, VolumeName);
> > > + }
> > > +}
> > > diff --git a/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> > > b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> > > new file mode 100644
> > > index 000000000000..d1a325a57abe
> > > --- /dev/null
> > > +++ b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> > > @@ -0,0 +1,111 @@
> > > +/** @file
> > > +
> > > + Copyright (c) 2003 - 2012, Ultra-Embedded.com. All rights reserved<BR>
> > > +
> > > + This program and the accompanying materials
> > > + are licensed and made available under the terms and conditions of the
> > BSD
> > > License
> > > + which accompanies this distribution. The full text of the license may be
> > > found at
> > > + http://opensource.org/licenses/bsd-license.php
> > > +
> > > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> > > BASIS,
> > > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> > > EXPRESS OR IMPLIED.
> > > +
> > > +**/
> > > +
> > > +/* Portions Copyright (c) 2016, Broadcom. All rights reserved */
> > > +
> > > +#ifndef __FAT_FORMAT_H__
> > > +#define __FAT_FORMAT_H__
> > > +
> > > +#include "GptWorker.h"
> > > +
> > > +#define FAT_SECTOR_SIZE 512
> > > +#define FAT_BUFFER_SECTORS 1
> > > +#define FAT32_LAST_CLUSTER 0xFFFFFFFF
> > > +#define FAT32_INVALID_CLUSTER 0xFFFFFFFF
> > > +#define FAT_DIR_ENTRY_SIZE 32
> > > +#define FAT_BUFFERS 1
> > > +#define DEFAULT_FAT_LABEL_NAME "EFIVOL"
> > > +
> > > +#define GET_32BIT_WORD(Buffer, Location)
> > > ( ((UINT32)Buffer[Location + 3] << 24) + \
> > > + ((UINT32)Buffer[Location + 2] <<16 ) + \
> > > + ((UINT32)Buffer[Location + 1] << 8) + \
> > > + (UINT32)Buffer[Location+0] )
> > > +
> > > +#define GET_16BIT_WORD(Buffer, Location)
> > > ( ((UINT16)Buffer[Location + 1] << 8) + \
> > > + (UINT16)Buffer[Location+0])
> > > +
> > > +#define SET_32BIT_WORD(Buffer, Location, Value) { Buffer[Location + 0]
> > =
> > > (UINT8)((Value) & 0xFF); \
> > > + Buffer[Location + 1] = (UINT8)((Value >> 8) &
> > 0xFF);
> > > \
> > > + Buffer[Location + 2] = (UINT8)((Value >> 16) &
> > > 0xFF); \
> > > + Buffer[Location + 3] = (UINT8)((Value >> 24) &
> > > 0xFF); }
> > > +
> > > +#define SET_16BIT_WORD(Buffer, Location, Value) { Buffer[Location + 0]
> > =
> > > (UINT8)((Value) & 0xFF); \
> > > + Buffer[Location + 1] = (UINT8)((Value >> 8) &
> > > 0xFF); }
> > > +
> > > +typedef enum eFatType
> > > +{
> > > + FAT_TYPE_16,
> > > + FAT_TYPE_32
> > > +} FAT_FS_TYPE;
> > > +
> > > +
> > > +// Forward declaration
> > > +typedef struct _FAT_BUFFER FAT_BUFFER;
> > > +
> > > +struct _FAT_BUFFER {
> > > + UINT8 Sector[FAT_SECTOR_SIZE * FAT_BUFFER_SECTORS];
> > > + UINTN Address;
> > > + BOOLEAN Dirty;
> > > + UINT8 *Ptr;
> > > +
> > > + // Next in chain of sector buffers
> > > + struct FAT_BUFFER *NextBuf;
> > > +};
> > > +
> > > +typedef struct
> > > +{
> > > + // Filesystem globals
> > > + UINT8 SectorsPerCluster;
> > > + EFI_LBA ClusterBeginLba;
> > > + UINTN RootdirFirstCluster;
> > > + UINTN RootdirFirstSector;
> > > + UINTN RootdirSectors;
> > > + EFI_LBA FatBeginLba;
> > > + UINT16 FsInfoSector;
> > > + EFI_LBA LbaBegin;
> > > + UINTN FatSectors;
> > > + UINTN NextFreeCluster;
> > > + UINT16 RootEntryCount;
> > > + UINT16 ReservedSectors;
> > > + UINT8 NumOfFats;
> > > + FAT_FS_TYPE FatType;
> > > +
> > > + // Working buffer
> > > + FAT_BUFFER CurrentSector;
> > > + // FAT Buffer
> > > + FAT_BUFFER *FatBufferHead;
> > > + FAT_BUFFER FatBuffers[FAT_BUFFERS];
> > > + EFI_LBA StartingLBA;
> > > + EFI_LBA EndingLBA;
> > > + EFI_BLOCK_IO_PROTOCOL *BlockIo;
> > > + EFI_DISK_IO_PROTOCOL *DiskIo;
> > > +
> > > +} FATFS;
> > > +
> > > +
> > > +
> > > +//-----------------------------------------------------------------------------
> > > +// Prototypes
> > > +//-----------------------------------------------------------------------------
> > > +EFI_STATUS
> > > +FatFormat (
> > > + IN EFI_LBA StartingLBA,
> > > + IN EFI_LBA EndingLBA,
> > > + IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
> > > + IN EFI_DISK_IO_PROTOCOL *DiskIo,
> > > + IN CHAR8 *VolumeName,
> > > + IN BOOLEAN ForceFat32
> > > + );
> > > +
> > > +#endif
> > > diff --git a/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> > > b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> > > new file mode 100644
> > > index 000000000000..0546c94488b0
> > > --- /dev/null
> > > +++ b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> > > @@ -0,0 +1,1902 @@
> > > +/** @file
> > > +Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
> > > +Copyright (c) 2016, Broadcom. All rights reserved.<BR>
> > > +This program and the accompanying materials
> > > +are licensed and made available under the terms and conditions of the
> > BSD
> > > License
> > > +which accompanies this distribution. The full text of the license may be
> > > found at
> > > +http://opensource.org/licenses/bsd-license.php
> > > +
> > > +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> > > BASIS,
> > > +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> > > EXPRESS OR IMPLIED.
> > > +
> > > +**/
> > > +
> > > +#include "GptWorker.h"
> > > +
> > > +#define GPT_DEBUG_LEVEL 0
> > > +
> > > +STATIC EFI_PARTITION_TABLE_HEADER *PrimaryHeader = NULL;
> > > +STATIC EFI_PARTITION_TABLE_HEADER *BackupHeader = NULL;
> > > +STATIC EFI_PARTITION_ENTRY *PartEntry = NULL;
> > > +STATIC EFI_PARTITION_ENTRY_STATUS *PEntryStatus = NULL;
> > > +
> > > +STATIC EFI_BLOCK_IO_PROTOCOL *BlockIo;
> > > +STATIC EFI_DISK_IO_PROTOCOL *DiskIo;
> > > +
> > > +STATIC BOOLEAN MbrValid;
> > > +STATIC BOOLEAN GptValid;
> > > +
> > > +STATIC EFI_KNOWN_PARTITION_TYPE PartitionTypes[] =
> > > +{
> > > + // Known Partition type GUIDs
> > > + // Expand this table as needed.
> > > + // Starting with EFI System partition
> > > + { { 0xC12A7328L, 0xF81F, 0x11D2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E,
> > 0xC9,
> > > 0x3B } }, L"EFI System" },
> > > + // Known Windows partition types
> > > + { { 0xE3C9E316L, 0x0B5C, 0x4DB8, { 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02,
> > 0x15,
> > > 0xAE } }, L"MS Windows Reserved (MSR)" },
> > > + { { 0xEBD0A0A2L, 0xB9E5, 0x4433, { 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26,
> > 0x99,
> > > 0xC7 } }, L"MS Windows Basic Data" },
> > > + { { 0x5808C8AAL, 0x7E8F, 0x42E0, { 0x85, 0xD2, 0xE1, 0xE9, 0x04, 0x34,
> > 0xCF,
> > > 0xB3 } }, L"MS Windows LDM Metadata" },
> > > + { { 0xAF9B60A0L, 0x1431, 0x4F62, { 0xBC, 0x68, 0x33, 0x11, 0x71, 0x4A,
> > 0x69,
> > > 0xAD } }, L"MS Windows LDM Data" },
> > > + { { 0xDE94BBA4L, 0x06D1, 0x4D40, { 0xA1, 0x6A, 0xBF, 0xD5, 0x01, 0x79,
> > > 0xD6, 0xAC } }, L"MS Windows Recovery Environment" },
> > > + { { 0xE75CAF8FL, 0xF680, 0x4CEE, { 0xAF, 0xA3, 0xB0, 0x01, 0xE5, 0x6E,
> > 0xFC,
> > > 0x2D } }, L"MS Windows Storage Spaces" },
> > > + // Known Linux partition types
> > > + { { 0x0FC63DAFL, 0x8483, 0x4772, { 0x8E, 0x79, 0x3D, 0x69, 0xD8, 0x47,
> > 0x7D,
> > > 0xE4 } }, L"Linux Filesystem Data" },
> > > + { { 0xA19D880FL, 0x05FC, 0x4D3B, { 0xA0, 0x06, 0x74, 0x3F, 0x0F, 0x84,
> > 0x91,
> > > 0x1E } }, L"Linux RAID" },
> > > + { { 0x44479540L, 0xF297, 0x41B2, { 0x9A, 0xF7, 0xD1, 0x31, 0xD5, 0xF0,
> > 0x45,
> > > 0x8A } }, L"Linux Root (x86)" },
> > > + { { 0x4F68BCE3L, 0xE8CD, 0x4DB1, { 0x96, 0xE7, 0xFB, 0xCA, 0xF9, 0x84,
> > 0xB7,
> > > 0x09 } }, L"Linux Root (x86-64)" },
> > > + { { 0x69DAD710L, 0x2CE4, 0x4E3C, { 0xB1, 0x6C, 0x21, 0xA1, 0xD4, 0x9A,
> > > 0xBe, 0xD3 } }, L"Linux Root (ARM 32-bit)" },
> > > + { { 0xB921B045L, 0x1DF0, 0x41C3, { 0xAF, 0x44, 0x4C, 0x6F, 0x28, 0x0D,
> > 0x3F,
> > > 0xAE } }, L"Linux Root (ARM 64-bit/AARCH64)" },
> > > + { { 0x0657FD6DL, 0xA4AB, 0x43C4, { 0x84, 0xE5, 0x09, 0x33, 0xC8, 0x4B,
> > 0x4F,
> > > 0x4F } }, L"Linux Swap" },
> > > + { { 0xE6D6D379L, 0xF507, 0x44C2, { 0xA2, 0x3C, 0x23, 0x8F, 0x2A, 0x3D,
> > 0xF9,
> > > 0x28 } }, L"Linux Logical Volume Manager (LVM)" },
> > > + { { 0x933AC7E1L, 0x2EB4, 0x4F13, { 0xB8, 0x44, 0x0E, 0x14, 0xE2, 0xAE,
> > 0xF9,
> > > 0x15 } }, L"Linux /home" },
> > > + { { 0x3B8F8425L, 0x20E0, 0x4F3B, { 0x90, 0x7F, 0x1A, 0x25, 0xA7, 0x6F,
> > 0x98,
> > > 0xE8 } }, L"Linux /srv (server data)" },
> > > + { { 0x7FFEC5C9L, 0x2D00, 0x49B7, { 0x89, 0x41, 0x3E, 0xA1, 0x0A, 0x55,
> > 0x86,
> > > 0xB7 } }, L"Linux Plain dm-crypt" },
> > > + { { 0xCA7D7CCBL, 0x63ED, 0x4C53, { 0x86, 0x1C, 0x17, 0x42, 0x53, 0x60,
> > 0x59,
> > > 0xCC } }, L"Linux LUKS" },
> > > + { { 0x8DA63339L, 0x0007, 0x60C0, { 0xC4, 0x36, 0x08, 0x3A, 0xC8, 0x23,
> > 0x09,
> > > 0x08 } }, L"Linux Reserved" },
> > > +};
> > > +
> > > +MASTER_BOOT_RECORD ProtectiveMbrTemplate = {
> > > + { 0 }, // BoostStrapCode [440]
> > > + { 0 }, // UniqueMbrSignature[4] (unused)
> > > + { 0 }, // Unknown[2]
> > > +
> > > + // PARTITIONS
> > > + {
> > > + // MBR_PARTITION_RECORD
> > > + {
> > > + 0, // BootIndicator
> > > + 0, // StartHead
> > > + 0x1, // StartSector
> > > + 0x1, // StartTrack
> > > + PMBR_GPT_PARTITION, // OSIndicator
> > > + 0xff, // EndHead
> > > + 0xff, // EndSector
> > > + 0xff, // EndTrack
> > > + { 0x1, 0x0, 0x0, 0x0 }, // StartingLba[4]
> > > + { 0xff, 0xff, 0xff, 0xff }, // SizeInLba[4]
> > > + },
> > > + { 0 }, { 0 }, { 0 }, // Unused partitions
> > > + },
> > > +
> > > + MBR_SIGNATURE // Signature
> > > +};
> > > +
> > > +STATIC UINT32 CurRand = 1;
> > > +
> > > +/**
> > > + Get random seed based on the RTC
> > > +
> > > +**/
> > > +
> > > +STATIC
> > > +VOID
> > > +Srand (VOID)
> > > +{
> > > + EFI_TIME Time;
> > > + UINT32 Seed;
> > > + UINT64 MonotonicCount;
> > > +
> > > + gRT->GetTime (&Time, NULL);
> > > + Seed = (~Time.Hour << 24 | Time.Day << 16 | Time.Minute << 8 |
> > > Time.Second);
> > > + Seed ^= Time.Nanosecond;
> > > + Seed ^= Time.Year << 7;
> > > +
> > > + gBS->GetNextMonotonicCount (&MonotonicCount);
> > > + Seed += (UINT32)MonotonicCount;
> > > +
> > > + /* Store this seed */
> > > + CurRand = (UINT32)Seed;
> > > +}
> > > +
> > > +/**
> > > + Get a pseudo-random number
> > > +
> > > + @retval A pseudo-random number in the range 0 - 0x7fff
> > > +**/
> > > +
> > > +STATIC UINTN Rand (VOID)
> > > +{
> > > + /* return a pseudo-random in range 0 - 0x7fff */
> > > + return ((CurRand = CurRand * 214013L + 2531011L) >> 16) & 0x7fff;
> > > +}
> > > +
> > > +/**
> > > + Generate a GUID
> > > +
> > > + @param[in] Guid A pointer to a GUID receiving a generated value
> > > +**/
> > > +
> > > +STATIC VOID
> > > +GenerateGuid (OUT GUID *Guid)
> > > +{
> > > + UINTN Index;
> > > + UINT16 Buffer[sizeof(GUID)];
> > > +
> > > + /* Generates 128 random bits for new UUID */
> > > + for (Index = 0; Index < sizeof(GUID); Index++) {
> > > + UINTN V;
> > > +
> > > + V = Rand () >> 7;
> > > + Buffer[Index] = (UINT16)V;
> > > + }
> > > + /* set variant 10x and version 4 as required by RFC 4122 */
> > > + Buffer[8] = 0x80 | (Buffer[8] & 0x3f);
> > > + Buffer[6] = 0x40 | (Buffer[6] & 0xf);
> > > + CopyGuid (Guid, (CONST GUID *)Buffer);
> > > +}
> > > +
> > > +/**
> > > + Clean up globals
> > > +**/
> > > +VOID
> > > +GptCleanupGlobals (VOID)
> > > +{
> > > + SHELL_FREE_NON_NULL (PrimaryHeader);
> > > + SHELL_FREE_NON_NULL (BackupHeader);
> > > + SHELL_FREE_NON_NULL (PartEntry);
> > > + SHELL_FREE_NON_NULL (PEntryStatus);
> > > + GptValid = FALSE;
> > > + MbrValid = FALSE;
> > > +}
> > > +
> > > +/**
> > > + Caution: This function may receive untrusted input.
> > > + The GPT partition table header is external input, so this routine
> > > + will do basic validation for GPT partition table header before return.
> > > +
> > > + @param[in] Lba The starting Lba of the Partition Table
> > > + @param[out] PartHeader Stores the partition table that is read
> > > +
> > > + @retval EFI_SUCCESS The partition table is valid
> > > + @retval ERROR The partition table is not valid
> > > +
> > > +**/
> > > +STATIC
> > > +EFI_STATUS
> > > +PartitionValidGptTable (
> > > + IN EFI_LBA Lba,
> > > + OUT EFI_PARTITION_TABLE_HEADER *PartHeader
> > > + );
> > > +
> > > +/**
> > > + Check if the CRC field in the Partition table header is valid
> > > + for Partition entry array.
> > > +
> > > + @param[in] PartHeader Partition table header structure
> > > +
> > > + @retval TRUE the CRC is valid
> > > + @retval FALSE the CRC is invalid
> > > +
> > > +**/
> > > +STATIC
> > > +BOOLEAN
> > > +PartitionCheckGptEntryArrayCRC (
> > > + IN EFI_PARTITION_TABLE_HEADER *PartHeader
> > > + );
> > > +
> > > +
> > > +/**
> > > + Restore Partition Table to its alternate place
> > > + (Primary -> Backup or Backup -> Primary).
> > > +
> > > + @param[in] PartHeader Partition table header structure.
> > > +
> > > + @retval TRUE Restoring succeeds
> > > + @retval FALSE Restoring failed
> > > +
> > > +**/
> > > +STATIC
> > > +BOOLEAN
> > > +PartitionRestoreGptTable (
> > > + IN EFI_PARTITION_TABLE_HEADER *PartHeader
> > > + );
> > > +
> > > +
> > > +/**
> > > + This routine will check GPT partition entry and return entry status.
> > > +
> > > + Caution: This function may receive untrusted input.
> > > + The GPT partition entry is external input, so this routine
> > > + will do basic validation for GPT partition entry and report status.
> > > +
> > > + @param[in] PartHeader Partition table header structure
> > > + @param[in] PartEntry The partition entry array
> > > + @param[out] PEntryStatus the partition entry status array
> > > + recording the status of each partition
> > > +
> > > +**/
> > > +STATIC
> > > +VOID
> > > +PartitionCheckGptEntry (
> > > + IN EFI_PARTITION_TABLE_HEADER *PartHeader,
> > > + IN EFI_PARTITION_ENTRY *PartEntry,
> > > + OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus
> > > + );
> > > +
> > > +
> > > +/**
> > > + Checks the CRC32 value in the table header.
> > > +
> > > + @param MaxSize Max Size limit
> > > + @param Size The size of the table
> > > + @param Hdr Table to check
> > > +
> > > + @return TRUE CRC Valid
> > > + @return FALSE CRC Invalid
> > > +
> > > +**/
> > > +STATIC
> > > +BOOLEAN
> > > +PartitionCheckCrcAltSize (
> > > + IN UINTN MaxSize,
> > > + IN UINTN Size,
> > > + IN OUT EFI_TABLE_HEADER *Hdr
> > > + );
> > > +
> > > +
> > > +/**
> > > + Checks the CRC32 value in the table header.
> > > +
> > > + @param MaxSize Max Size limit
> > > + @param Hdr Table to check
> > > +
> > > + @return TRUE CRC Valid
> > > + @return FALSE CRC Invalid
> > > +
> > > +**/
> > > +STATIC
> > > +BOOLEAN
> > > +PartitionCheckCrc (
> > > + IN UINTN MaxSize,
> > > + IN OUT EFI_TABLE_HEADER *Hdr
> > > + );
> > > +
> > > +
> > > +/**
> > > + Updates the CRC32 value in the table header.
> > > +
> > > + @param Size The size of the table
> > > + @param Hdr Table to update
> > > +
> > > +**/
> > > +STATIC
> > > +VOID
> > > +PartitionSetCrcAltSize (
> > > + IN UINTN Size,
> > > + IN OUT EFI_TABLE_HEADER *Hdr
> > > + );
> > > +
> > > +
> > > +/**
> > > + Updates the CRC32 value in the table header.
> > > +
> > > + @param Hdr Table to update
> > > +
> > > +**/
> > > +STATIC
> > > +VOID
> > > +PartitionSetCrc (
> > > + IN OUT EFI_TABLE_HEADER *Hdr
> > > + );
> > > +
> > > +
> > > +/**
> > > + Get GPT tables.
> > > +
> > > + Caution: This function may receive untrusted input.
> > > + The GPT partition table is external input, so this routine
> > > + will do basic validation for GPT partition table before install
> > > + child handle for each GPT partition.
> > > +
> > > + @param[in] DiskIoProt DiskIo interface.
> > > + @param[in] BlockIoProt BlockIo interface.
> > > +
> > > + @retval EFI_SUCCESS Valid GPT disk.
> > > + @retval EFI_MEDIA_CHANGED Media changed Detected.
> > > + @retval other Not a valid GPT disk.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +PartitionGetGptTables (
> > > + IN EFI_DISK_IO_PROTOCOL *DiskIoProt,
> > > + IN EFI_BLOCK_IO_PROTOCOL *BlockIoProt
> > > + )
> > > +{
> > > + EFI_STATUS Status;
> > > + UINT32 BlockSize;
> > > + EFI_LBA LastBlock;
> > > + UINTN Index;
> > > + EFI_STATUS GptValidStatus;
> > > + UINT32 MediaId;
> > > + MASTER_BOOT_RECORD *ProtectiveMbr;
> > > +
> > > + // Clear leftovers
> > > + GptCleanupGlobals ();
> > > +
> > > + MbrValid = FALSE;
> > > + GptValid = FALSE;
> > > +
> > > + ProtectiveMbr = NULL;
> > > +
> > > + BlockIo = BlockIoProt;
> > > + DiskIo = DiskIoProt;
> > > +
> > > + if (CurRand == 1) {
> > > + Srand ();
> > > + }
> > > +
> > > + BlockSize = BlockIo->Media->BlockSize;
> > > + LastBlock = BlockIo->Media->LastBlock;
> > > + MediaId = BlockIo->Media->MediaId;
> > > +
> > > + DEBUG ((EFI_D_VERBOSE, " BlockSize : %d \n", BlockSize));
> > > + DEBUG ((EFI_D_VERBOSE, " LastBlock : %lx \n", LastBlock));
> > > +
> > > + GptValidStatus = EFI_NOT_FOUND;
> > > + GptValid = FALSE;
> > > + MbrValid = FALSE;
> > > +
> > > + //
> > > + // Allocate a buffer for the Protective MBR
> > > + //
> > > + ProtectiveMbr = AllocatePool (BlockSize);
> > > + if (ProtectiveMbr == NULL) {
> > > + return EFI_OUT_OF_RESOURCES;
> > > + }
> > > +
> > > + //
> > > + // Read the Protective MBR from LBA #0
> > > + //
> > > + Status = DiskIo->ReadDisk (
> > > + DiskIo,
> > > + MediaId,
> > > + 0,
> > > + BlockSize,
> > > + ProtectiveMbr
> > > + );
> > > + if (EFI_ERROR (Status)) {
> > > + GptValidStatus = Status;
> > > + goto Done;
> > > + }
> > > +
> > > + //
> > > + // Verify that the Protective MBR is valid
> > > + //
> > > + for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
> > > + if (ProtectiveMbr->Partition[Index].BootIndicator == 0x00 &&
> > > + ProtectiveMbr->Partition[Index].OSIndicator ==
> > > PMBR_GPT_PARTITION &&
> > > + UNPACK_UINT32 (ProtectiveMbr->Partition[Index].StartingLBA) == 1
> > > + ) {
> > > + break;
> > > + }
> > > + }
> > > + if (Index == MAX_MBR_PARTITIONS) {
> > > + goto Done;
> > > + }
> > > +
> > > + MbrValid = TRUE;
> > > +
> > > + //
> > > + // Allocate the GPT structures
> > > + //
> > > + PrimaryHeader = AllocateZeroPool
> > > (sizeof(EFI_PARTITION_TABLE_HEADER));
> > > + if (PrimaryHeader == NULL) {
> > > + goto Done;
> > > + }
> > > +
> > > + BackupHeader = AllocateZeroPool
> > > (sizeof(EFI_PARTITION_TABLE_HEADER));
> > > + if (BackupHeader == NULL) {
> > > + goto Done;
> > > + }
> > > +
> > > + //
> > > + // Check primary and backup partition tables
> > > + //
> > > + Status = PartitionValidGptTable (PRIMARY_PART_HEADER_LBA,
> > > PrimaryHeader);
> > > + if (EFI_ERROR (Status)) {
> > > + DEBUG ((EFI_D_INFO, " Not Valid primary partition table\n"));
> > > +
> > > + Status = PartitionValidGptTable (LastBlock, BackupHeader);
> > > + if (EFI_ERROR (Status)) {
> > > + DEBUG ((EFI_D_INFO, " Not Valid backup partition table\n"));
> > > + goto Done;
> > > + } else {
> > > + DEBUG ((EFI_D_INFO, " Valid backup partition table\n"));
> > > + DEBUG ((EFI_D_INFO, " Restore primary partition table by the
> > > backup\n"));
> > > + if (!PartitionRestoreGptTable (BackupHeader)) {
> > > + DEBUG ((EFI_D_INFO, " Restore primary partition table error\n"));
> > > + }
> > > +
> > > + Status = PartitionValidGptTable (BackupHeader->AlternateLBA,
> > > PrimaryHeader);
> > > + if (!EFI_ERROR (Status)) {
> > > + DEBUG ((EFI_D_INFO, " Restore backup partition table success\n"));
> > > + }
> > > + }
> > > + } else if (EFI_ERROR (PartitionValidGptTable (PrimaryHeader-
> > > >AlternateLBA, BackupHeader))) {
> > > + DEBUG ((EFI_D_INFO, " Valid primary and !Valid backup partition
> > > table\n"));
> > > + DEBUG ((EFI_D_INFO, " Restore backup partition table by the
> > > primary\n"));
> > > + if (!PartitionRestoreGptTable (PrimaryHeader)) {
> > > + DEBUG ((EFI_D_INFO, " Restore backup partition table error\n"));
> > > + }
> > > +
> > > + Status = PartitionValidGptTable (PrimaryHeader->AlternateLBA,
> > > BackupHeader);
> > > + if (!EFI_ERROR (Status)) {
> > > + DEBUG ((EFI_D_INFO, " Restore backup partition table success\n"));
> > > + }
> > > + }
> > > +
> > > + DEBUG ((EFI_D_VERBOSE, " Valid primary and Valid backup partition
> > > table\n"));
> > > +
> > > + //
> > > + // Read the EFI Partition Entries
> > > + //
> > > + PartEntry = AllocatePool (PrimaryHeader->NumberOfPartitionEntries *
> > > PrimaryHeader->SizeOfPartitionEntry);
> > > + if (PartEntry == NULL) {
> > > + DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
> > > + goto Done;
> > > + }
> > > +
> > > + Status = DiskIo->ReadDisk (
> > > + DiskIo,
> > > + MediaId,
> > > + MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockSize),
> > > + PrimaryHeader->NumberOfPartitionEntries * (PrimaryHeader-
> > > >SizeOfPartitionEntry),
> > > + PartEntry
> > > + );
> > > + if (EFI_ERROR (Status)) {
> > > + GptValidStatus = Status;
> > > + DEBUG ((EFI_D_ERROR, " Partition Entry ReadDisk error\n"));
> > > + goto Done;
> > > + }
> > > +
> > > + DEBUG ((EFI_D_VERBOSE, " Partition entries read block success\n"));
> > > +
> > > + DEBUG ((EFI_D_VERBOSE, " Number of partition entries: %d\n",
> > > PrimaryHeader->NumberOfPartitionEntries));
> > > +
> > > + PEntryStatus = AllocateZeroPool (PrimaryHeader-
> > > >NumberOfPartitionEntries * sizeof(EFI_PARTITION_ENTRY_STATUS));
> > > + if (PEntryStatus == NULL) {
> > > + DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
> > > + goto Done;
> > > + }
> > > +
> > > + //
> > > + // Check the integrity of partition entries
> > > + //
> > > + PartitionCheckGptEntry (PrimaryHeader, PartEntry, PEntryStatus);
> > > +
> > > + //
> > > + // If we got this far the GPT layout of the disk is valid and we should
> > return
> > > true
> > > + //
> > > + GptValidStatus = EFI_SUCCESS;
> > > +
> > > + Done:
> > > + SHELL_FREE_NON_NULL (ProtectiveMbr);
> > > + if (EFI_ERROR (GptValidStatus)) {
> > > + SHELL_FREE_NON_NULL (PrimaryHeader);
> > > + SHELL_FREE_NON_NULL (BackupHeader);
> > > + SHELL_FREE_NON_NULL (PartEntry);
> > > + SHELL_FREE_NON_NULL (PEntryStatus);
> > > + } else {
> > > + GptValid = TRUE;
> > > + }
> > > +
> > > + return GptValidStatus;
> > > +}
> > > +
> > > +/**
> > > + This routine will read GPT partition table header and return it.
> > > +
> > > + Caution: This function may receive untrusted input.
> > > + The GPT partition table header is external input, so this routine
> > > + will do basic validation for GPT partition table header before return.
> > > +
> > > + @param[in] Lba The starting Lba of the Partition Table
> > > + @param[out] PartHeader Stores the partition table that is read
> > > +
> > > + @retval TRUE The partition table is valid
> > > + @retval FALSE The partition table is not valid
> > > +
> > > +**/
> > > +STATIC
> > > +EFI_STATUS
> > > +PartitionValidGptTable (
> > > + IN EFI_LBA Lba,
> > > + OUT EFI_PARTITION_TABLE_HEADER *PartHeader
> > > + )
> > > +{
> > > + EFI_STATUS Status;
> > > + UINT32 BlockSize;
> > > + EFI_PARTITION_TABLE_HEADER *PartHdr;
> > > + UINT32 MediaId;
> > > +
> > > + BlockSize = BlockIo->Media->BlockSize;
> > > + MediaId = BlockIo->Media->MediaId;
> > > + PartHdr = AllocateZeroPool (BlockSize);
> > > +
> > > + if (PartHdr == NULL) {
> > > + DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
> > > + return EFI_OUT_OF_RESOURCES;
> > > + }
> > > + //
> > > + // Read the EFI Partition Table Header
> > > + //
> > > + Status = DiskIo->ReadDisk (
> > > + DiskIo,
> > > + MediaId,
> > > + MultU64x32 (Lba, BlockSize),
> > > + BlockSize,
> > > + PartHdr
> > > + );
> > > + if (EFI_ERROR (Status)) {
> > > + FreePool (PartHdr);
> > > + return Status;
> > > + }
> > > +
> > > + if ((PartHdr->Header.Signature != EFI_PTAB_HEADER_ID) ||
> > > + !PartitionCheckCrc (BlockSize, &PartHdr->Header) ||
> > > + PartHdr->MyLBA != Lba ||
> > > + (PartHdr->SizeOfPartitionEntry < sizeof(EFI_PARTITION_ENTRY))
> > > + ) {
> > > + DEBUG ((EFI_D_ERROR, "Invalid efi partition table header\n"));
> > > + FreePool (PartHdr);
> > > + return EFI_VOLUME_CORRUPTED;
> > > + }
> > > +
> > > + //
> > > + // Ensure the NumberOfPartitionEntries * SizeOfPartitionEntry doesn't
> > > overflow.
> > > + //
> > > + if (PartHdr->NumberOfPartitionEntries > DivU64x32 (MAX_UINTN,
> > > PartHdr->SizeOfPartitionEntry)) {
> > > + FreePool (PartHdr);
> > > + return EFI_VOLUME_CORRUPTED;
> > > + }
> > > +
> > > + CopyMem (PartHeader, PartHdr,
> > sizeof(EFI_PARTITION_TABLE_HEADER));
> > > + if (!PartitionCheckGptEntryArrayCRC (PartHeader)) {
> > > + FreePool (PartHdr);
> > > + return EFI_VOLUME_CORRUPTED;
> > > + }
> > > +
> > > + DEBUG ((EFI_D_VERBOSE, " Valid efi partition table header\n"));
> > > + FreePool (PartHdr);
> > > +
> > > + return EFI_SUCCESS;
> > > +}
> > > +
> > > +/**
> > > + Check if the CRC field in the Partition table header is valid
> > > + for Partition entry array.
> > > +
> > > + @param[in] PartHeader Partition table header structure
> > > +
> > > + @retval TRUE the CRC is valid
> > > + @retval FALSE the CRC is invalid
> > > +
> > > +**/
> > > +STATIC
> > > +BOOLEAN
> > > +PartitionCheckGptEntryArrayCRC (
> > > + IN EFI_PARTITION_TABLE_HEADER *PartHeader
> > > + )
> > > +{
> > > + EFI_STATUS Status;
> > > + UINT8 *Ptr;
> > > + UINT32 Crc;
> > > + UINTN Size;
> > > +
> > > + //
> > > + // Read the EFI Partition Entries
> > > + //
> > > + Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries *
> > PartHeader-
> > > >SizeOfPartitionEntry);
> > > + if (Ptr == NULL) {
> > > + DEBUG ((EFI_D_ERROR, " Allocate pool error\n"));
> > > + return FALSE;
> > > + }
> > > +
> > > + Status = DiskIo->ReadDisk (
> > > + DiskIo,
> > > + BlockIo->Media->MediaId,
> > > + MultU64x32 (PartHeader->PartitionEntryLBA, BlockIo->Media-
> > >BlockSize),
> > > + PartHeader->NumberOfPartitionEntries * PartHeader-
> > > >SizeOfPartitionEntry,
> > > + Ptr
> > > + );
> > > + if (EFI_ERROR (Status)) {
> > > + FreePool (Ptr);
> > > + return FALSE;
> > > + }
> > > +
> > > + Size = PartHeader->NumberOfPartitionEntries * PartHeader-
> > > >SizeOfPartitionEntry;
> > > +
> > > + Status = gBS->CalculateCrc32 (Ptr, Size, &Crc);
> > > + if (EFI_ERROR (Status)) {
> > > + DEBUG ((EFI_D_ERROR, "CheckPEntryArrayCRC: Crc calculation
> > failed\n"));
> > > + FreePool (Ptr);
> > > + return FALSE;
> > > + }
> > > +
> > > + FreePool (Ptr);
> > > +
> > > + return (BOOLEAN)(PartHeader->PartitionEntryArrayCRC32 == Crc);
> > > +}
> > > +
> > > +
> > > +/**
> > > + Restore Partition Table to its alternate place
> > > + (Primary -> Backup or Backup -> Primary).
> > > +
> > > + @param[in] PartHeader Partition table header structure.
> > > +
> > > + @retval TRUE Restoring succeeds
> > > + @retval FALSE Restoring failed
> > > +
> > > +**/
> > > +STATIC
> > > +BOOLEAN
> > > +PartitionRestoreGptTable (
> > > + IN EFI_PARTITION_TABLE_HEADER *PartHeader
> > > + )
> > > +{
> > > + EFI_STATUS Status;
> > > + UINTN BlockSize;
> > > + EFI_PARTITION_TABLE_HEADER *PartHdr;
> > > + EFI_LBA PEntryLBA;
> > > + UINT8 *Ptr;
> > > + UINT32 MediaId;
> > > +
> > > + PartHdr = NULL;
> > > + Ptr = NULL;
> > > +
> > > + BlockSize = BlockIo->Media->BlockSize;
> > > + MediaId = BlockIo->Media->MediaId;
> > > +
> > > + PartHdr = AllocateZeroPool (BlockSize);
> > > +
> > > + if (PartHdr == NULL) {
> > > + DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
> > > + return FALSE;
> > > + }
> > > +
> > > + PEntryLBA = (PartHeader->MyLBA == PRIMARY_PART_HEADER_LBA) ?\
> > > + (PartHeader->LastUsableLBA + 1) :\
> > > + (PRIMARY_PART_HEADER_LBA + 1);
> > > +
> > > + CopyMem (PartHdr, PartHeader,
> > sizeof(EFI_PARTITION_TABLE_HEADER));
> > > +
> > > + PartHdr->MyLBA = PartHeader->AlternateLBA;
> > > + PartHdr->AlternateLBA = PartHeader->MyLBA;
> > > + PartHdr->PartitionEntryLBA = PEntryLBA;
> > > + PartitionSetCrc ((EFI_TABLE_HEADER *)PartHdr);
> > > +
> > > + Status = DiskIo->WriteDisk (
> > > + DiskIo,
> > > + MediaId,
> > > + MultU64x32 (PartHdr->MyLBA, (UINT32)BlockSize),
> > > + BlockSize,
> > > + PartHdr
> > > + );
> > > + if (EFI_ERROR (Status)) {
> > > + goto Done;
> > > + }
> > > +
> > > + Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries *
> > PartHeader-
> > > >SizeOfPartitionEntry);
> > > + if (Ptr == NULL) {
> > > + DEBUG ((EFI_D_ERROR, " Allocate pool error\n"));
> > > + Status = EFI_OUT_OF_RESOURCES;
> > > + goto Done;
> > > + }
> > > +
> > > + Status = DiskIo->ReadDisk (
> > > + DiskIo,
> > > + MediaId,
> > > + MultU64x32 (PartHeader->PartitionEntryLBA, (UINT32)BlockSize),
> > > + PartHeader->NumberOfPartitionEntries * PartHeader-
> > > >SizeOfPartitionEntry,
> > > + Ptr
> > > + );
> > > + if (EFI_ERROR (Status)) {
> > > + goto Done;
> > > + }
> > > +
> > > + Status = DiskIo->WriteDisk (
> > > + DiskIo,
> > > + MediaId,
> > > + MultU64x32 (PEntryLBA, (UINT32)BlockSize),
> > > + PartHeader->NumberOfPartitionEntries * PartHeader-
> > > >SizeOfPartitionEntry,
> > > + Ptr
> > > + );
> > > +
> > > + Done:
> > > + FreePool (PartHdr);
> > > +
> > > + if (Ptr != NULL) {
> > > + FreePool (Ptr);
> > > + }
> > > +
> > > + if (EFI_ERROR (Status)) {
> > > + return FALSE;
> > > + }
> > > +
> > > + return TRUE;
> > > +}
> > > +
> > > +/**
> > > + This routine will check GPT partition entry and return entry status.
> > > +
> > > + Caution: This function may receive untrusted input.
> > > + The GPT partition entry is external input, so this routine
> > > + will do basic validation for GPT partition entry and report status.
> > > +
> > > + @param[in] PartHeader Partition table header structure
> > > + @param[in] PartEntry The partition entry array
> > > + @param[out] PEntryStatus the partition entry status array
> > > + recording the status of each partition
> > > +
> > > +**/
> > > +STATIC
> > > +VOID
> > > +PartitionCheckGptEntry (
> > > + IN EFI_PARTITION_TABLE_HEADER *PartHeader,
> > > + IN EFI_PARTITION_ENTRY *PartEntry,
> > > + OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus
> > > + )
> > > +{
> > > + EFI_LBA StartingLBA;
> > > + EFI_LBA EndingLBA;
> > > + EFI_PARTITION_ENTRY *Entry;
> > > + UINTN Index1;
> > > + UINTN Index2;
> > > +
> > > + DEBUG ((EFI_D_VERBOSE, " start check partition entries\n"));
> > > + for (Index1 = 0; Index1 < PartHeader->NumberOfPartitionEntries;
> > > Index1++) {
> > > + Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index1 *
> > > PartHeader->SizeOfPartitionEntry);
> > > + if (CompareGuid (&Entry->PartitionTypeGUID,
> > > &gEfiPartTypeUnusedGuid)) {
> > > + continue;
> > > + }
> > > +
> > > + StartingLBA = Entry->StartingLBA;
> > > + EndingLBA = Entry->EndingLBA;
> > > + if (StartingLBA > EndingLBA ||
> > > + StartingLBA < PartHeader->FirstUsableLBA ||
> > > + StartingLBA > PartHeader->LastUsableLBA ||
> > > + EndingLBA < PartHeader->FirstUsableLBA ||
> > > + EndingLBA > PartHeader->LastUsableLBA
> > > + ) {
> > > + PEntryStatus[Index1].OutOfRange = TRUE;
> > > + continue;
> > > + }
> > > +
> > > + if ((Entry->Attributes & BIT1) != 0) {
> > > + //
> > > + // If Bit 1 is set, this indicate that this is an OS specific GUID partition.
> > > + //
> > > + PEntryStatus[Index1].OsSpecific = TRUE;
> > > + }
> > > +
> > > + for (Index2 = Index1 + 1; Index2 < PartHeader-
> > > >NumberOfPartitionEntries; Index2++) {
> > > + Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index2 *
> > > PartHeader->SizeOfPartitionEntry);
> > > + if (CompareGuid (&Entry->PartitionTypeGUID,
> > > &gEfiPartTypeUnusedGuid)) {
> > > + continue;
> > > + }
> > > +
> > > + if (Entry->EndingLBA >= StartingLBA && Entry->StartingLBA <=
> > EndingLBA)
> > > {
> > > + //
> > > + // This region overlaps with the Index1'th region
> > > + //
> > > + PEntryStatus[Index1].Overlap = TRUE;
> > > + PEntryStatus[Index2].Overlap = TRUE;
> > > + continue;
> > > + }
> > > + }
> > > + }
> > > +
> > > + DEBUG ((EFI_D_VERBOSE, " End check partition entries\n"));
> > > +}
> > > +
> > > +
> > > +/**
> > > + Updates the CRC32 value in the table header.
> > > +
> > > + @param Hdr Table to update
> > > +
> > > +**/
> > > +STATIC
> > > +VOID
> > > +PartitionSetCrc (
> > > + IN OUT EFI_TABLE_HEADER *Hdr
> > > + )
> > > +{
> > > + PartitionSetCrcAltSize (Hdr->HeaderSize, Hdr);
> > > +}
> > > +
> > > +
> > > +/**
> > > + Updates the CRC32 value in the table header.
> > > +
> > > + @param Size The size of the table
> > > + @param Hdr Table to update
> > > +
> > > +**/
> > > +STATIC
> > > +VOID
> > > +PartitionSetCrcAltSize (
> > > + IN UINTN Size,
> > > + IN OUT EFI_TABLE_HEADER *Hdr
> > > + )
> > > +{
> > > + UINT32 Crc;
> > > +
> > > + Hdr->CRC32 = 0;
> > > + gBS->CalculateCrc32 ((UINT8 *)Hdr, Size, &Crc);
> > > + Hdr->CRC32 = Crc;
> > > +}
> > > +
> > > +
> > > +/**
> > > + Checks the CRC32 value in the table header.
> > > +
> > > + @param MaxSize Max Size limit
> > > + @param Hdr Table to check
> > > +
> > > + @return TRUE CRC Valid
> > > + @return FALSE CRC Invalid
> > > +
> > > +**/
> > > +STATIC
> > > +BOOLEAN
> > > +PartitionCheckCrc (
> > > + IN UINTN MaxSize,
> > > + IN OUT EFI_TABLE_HEADER *Hdr
> > > + )
> > > +{
> > > + return PartitionCheckCrcAltSize (MaxSize, Hdr->HeaderSize, Hdr);
> > > +}
> > > +
> > > +
> > > +/**
> > > + Checks the CRC32 value in the table header.
> > > +
> > > + @param MaxSize Max Size limit
> > > + @param Size The size of the table
> > > + @param Hdr Table to check
> > > +
> > > + @return TRUE CRC Valid
> > > + @return FALSE CRC Invalid
> > > +
> > > +**/
> > > +STATIC
> > > +BOOLEAN
> > > +PartitionCheckCrcAltSize (
> > > + IN UINTN MaxSize,
> > > + IN UINTN Size,
> > > + IN OUT EFI_TABLE_HEADER *Hdr
> > > + )
> > > +{
> > > + UINT32 Crc;
> > > + UINT32 OrgCrc;
> > > + EFI_STATUS Status;
> > > +
> > > + Crc = 0;
> > > +
> > > + if (Size == 0) {
> > > + //
> > > + // If header size is 0 CRC will pass so return FALSE here
> > > + //
> > > + return FALSE;
> > > + }
> > > +
> > > + if ((MaxSize != 0) && (Size > MaxSize)) {
> > > + DEBUG ((EFI_D_ERROR, "CheckCrc32: Size > MaxSize\n"));
> > > + return FALSE;
> > > + }
> > > + //
> > > + // clear old crc from header
> > > + //
> > > + OrgCrc = Hdr->CRC32;
> > > + Hdr->CRC32 = 0;
> > > +
> > > + Status = gBS->CalculateCrc32 ((UINT8 *)Hdr, Size, &Crc);
> > > + if (EFI_ERROR (Status)) {
> > > + DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc calculation failed\n"));
> > > + return FALSE;
> > > + }
> > > + //
> > > + // set results
> > > + //
> > > + Hdr->CRC32 = Crc;
> > > +
> > > + //
> > > + // return status
> > > + //
> > > + DEBUG_CODE_BEGIN ();
> > > + if (OrgCrc != Crc) {
> > > + DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc check failed\n"));
> > > + }
> > > + DEBUG_CODE_END ();
> > > +
> > > + return (BOOLEAN)(OrgCrc == Crc);
> > > +}
> > > +
> > > +/**
> > > + Converts a GUID into a unicode string.
> > > +
> > > + @param [in] Guid A GUID to be converted
> > > + @param [out] Buffer A pointer to a buffer receiving the string
> > > + @param [in] BufferSize Size of the buffer
> > > +
> > > + @return EFI_SUCCESS Successful conversion
> > > + @return EFI_INVALID_PARAMETER Conversion failed
> > > +
> > > +**/
> > > +
> > > +STATIC
> > > +EFI_STATUS
> > > +GuidToString (
> > > + IN EFI_GUID *Guid,
> > > + OUT CHAR16 *Buffer,
> > > + IN UINTN BufferSize
> > > + )
> > > +{
> > > + UINTN Size;
> > > + EFI_STATUS Status;
> > > +
> > > + Status = EFI_SUCCESS;
> > > +
> > > + Size = UnicodeSPrint (
> > > + Buffer,
> > > + BufferSize,
> > > + L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
> > > + (UINTN)Guid->Data1,
> > > + (UINTN)Guid->Data2,
> > > + (UINTN)Guid->Data3,
> > > + (UINTN)Guid->Data4[0],
> > > + (UINTN)Guid->Data4[1],
> > > + (UINTN)Guid->Data4[2],
> > > + (UINTN)Guid->Data4[3],
> > > + (UINTN)Guid->Data4[4],
> > > + (UINTN)Guid->Data4[5],
> > > + (UINTN)Guid->Data4[6],
> > > + (UINTN)Guid->Data4[7]
> > > + );
> > > + if (!Size) {
> > > + Status = EFI_INVALID_PARAMETER;
> > > + }
> > > +
> > > + return Status;
> > > +}
> > > +
> > > +/**
> > > + Get a string representation of a known
> > > + partition type GUID. If partition GUID is not
> > > + known, gets a string representation of the GUID
> > > +
> > > + @param GUID Guid to be searched for
> > > + @param PartTypeStr Buffer receiving the string
> > > + @param NoGuidStr Do not convert GUID to string
> > > + for an unknown partition type
> > > +
> > > + @return EFI_SUCCESS GUID type is known
> > > + @return EFI_NOT_FOUND Unknown GUID partition type
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +GetPartitionTypeStr (
> > > + IN EFI_GUID Guid,
> > > + OUT CHAR16 *PartTypeStr,
> > > + IN BOOLEAN NoGuidStr)
> > > +{
> > > + UINTN Index;
> > > + EFI_STATUS Status;
> > > +
> > > + Status = EFI_SUCCESS;
> > > + for (Index = 0; Index < ARRAY_SIZE (PartitionTypes); Index++) {
> > > + if (CompareGuid (&Guid, &PartitionTypes[Index].TypeGuid)) {
> > > + StrnCpy (PartTypeStr, PartitionTypes[Index].TypeName,
> > > MAX_PARTITION_NAME_LENGTH);
> > > + return Status;
> > > + }
> > > + }
> > > + if (!NoGuidStr) {
> > > + GuidToString (&Guid, PartTypeStr, (MAX_PARTITION_NAME_LENGTH +
> > 1)
> > > * sizeof(CHAR16));
> > > + }
> > > + return EFI_NOT_FOUND;
> > > +}
> > > +
> > > +/**
> > > + Lists partitions on a block device.
> > > +
> > > + @return Number of partitions used
> > > +**/
> > > +
> > > +UINTN
> > > +PartitionListGptEntries (VOID)
> > > +{
> > > + UINTN Index;
> > > + EFI_PARTITION_ENTRY *Entry;
> > > + EFI_LBA Length;
> > > + UINTN NumEntries; // Used entries
> > > + UINTN BlockSize;
> > > + BOOLEAN FirstTime;
> > > + UINT64 BlocksOccupied;
> > > +
> > > + NumEntries = 0;
> > > + BlockSize = BlockIo->Media->BlockSize;
> > > + FirstTime = TRUE;
> > > +
> > > + if (!GptValid) {
> > > + return 0;
> > > + }
> > > +
> > > + BlocksOccupied = 0;
> > > +
> > > + for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries;
> > > Index++) {
> > > +
> > > + BOOLEAN Specific;
> > > + CHAR16 PartTypeStr[MAX_PARTITION_NAME_LENGTH + 1];
> > > +
> > > + Specific = FALSE;
> > > +
> > > + Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index *
> > > PrimaryHeader->SizeOfPartitionEntry);
> > > +
> > > + Length = Entry->EndingLBA - Entry->StartingLBA + 1;
> > > +
> > > + if (CompareGuid (&Entry->PartitionTypeGUID,
> > > &gEfiPartTypeUnusedGuid)) {
> > > + continue;
> > > + }
> > > +
> > > + if (FirstTime) {
> > > + Print (L" No \t%-36s\tStart (LBA)\tEnd (LBA)\tSize (MiB)\t Partition
> > > Type\r\n", L"Name");
> > > + Print (L" ---- -------------------------------------- ----------- ----------- ---
> > --
> > > ----- -------------------------------\r\n");
> > > + FirstTime = FALSE;
> > > + }
> > > + NumEntries++;
> > > + if (PEntryStatus[Index].OutOfRange ||
> > > + PEntryStatus[Index].Overlap ||
> > > + PEntryStatus[Index].OsSpecific) {
> > > + Specific = TRUE;
> > > + }
> > > +
> > > + BlocksOccupied += Length;
> > > +
> > > + GetPartitionTypeStr (Entry->PartitionTypeGUID, (CHAR16
> > *)&PartTypeStr,
> > > FALSE);
> > > +
> > > + Print (L"%1s %-3d\t%-36s\t0x%09llx\t0x%09llx\t%06llu\t %s\r\n",
> > > + Specific ? L"S" : L"",
> > > + Index + 1,
> > > + Entry->PartitionName,
> > > + (UINT64)Entry->StartingLBA,
> > > + (UINT64)Entry->EndingLBA,
> > > + (MultU64x32 (Length, BlockSize)) >> 20,
> > > + PartTypeStr);
> > > + }
> > > +
> > > + // This code block is to provide additional info
> > > + {
> > > + UINT64 DiskSizeMiB, SizeOccupiedMiB;
> > > +
> > > + DiskSizeMiB = MultU64x32 (PrimaryHeader->LastUsableLBA -
> > > PrimaryHeader->FirstUsableLBA + 1, BlockIo->Media->BlockSize) >> 20;
> > > + SizeOccupiedMiB = MultU64x32 (BlocksOccupied, BlockIo->Media-
> > > >BlockSize) >> 20;
> > > + Print (L"\r\n%d partition(s) used out of %d\r\n", NumEntries,
> > > PrimaryHeader->NumberOfPartitionEntries);
> > > + Print (L"Total device capacity (minus GPT service blocks): %llu
> > > MiB\r\nPartitioned space: %llu MiB\r\n",
> > > + DiskSizeMiB,
> > > + SizeOccupiedMiB);
> > > + Print (L"Unpartitioned space available: %llu MiB (%d%%)\n",
> > > + DiskSizeMiB - SizeOccupiedMiB,
> > > + (100 * (DiskSizeMiB - SizeOccupiedMiB)) / DiskSizeMiB);
> > > + }
> > > +
> > > + return NumEntries;
> > > +}
> > > +
> > > +/**
> > > + Locate a partition by criteria
> > > +
> > > + @param Name Partition name (or ordinal represented a string)
> > > + @param StartLba StartLba of the partition to search for
> > > + @param EndingLba EndingLba of the partition to search for
> > > + @param SearchType A combination (OR) of search options.
> > > + Options are:
> > > + SRC_BY_NAME = search by partition name
> > > + SRC_BY_LBA = search by Start/Ending lba
> > > + SRC_ANY = returns a first used partition
> > > + SRC_BY_NUM = search by ordinal
> > > +
> > > +
> > > + @return Non-NULL Pointer to th partition found
> > > + @return NULL No partition found
> > > +
> > > +**/
> > > +EFI_PARTITION_ENTRY *
> > > +PartitionFindPartitionByCriteria (
> > > + IN OPTIONAL CONST CHAR16 *Name,
> > > + IN OPTIONAL EFI_LBA StartLba,
> > > + IN OPTIONAL EFI_LBA EndingLba,
> > > + IN SEARCH_TYPE SearchType
> > > + )
> > > +{
> > > + UINTN Index;
> > > + EFI_PARTITION_ENTRY *Entry;
> > > +
> > > + if (!GptValid) {
> > > + return NULL;
> > > + }
> > > +
> > > + if (!Name && (SearchType & SRC_BY_NAME)) {
> > > + return NULL;
> > > + }
> > > +
> > > + for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries;
> > > Index++) {
> > > + Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index *
> > > PrimaryHeader->SizeOfPartitionEntry);
> > > +
> > > + if (CompareGuid (&Entry->PartitionTypeGUID,
> > > &gEfiPartTypeUnusedGuid)) {
> > > + continue;
> > > + }
> > > +
> > > + if (SearchType & SRC_ANY) {
> > > + return Entry;
> > > + }
> > > +
> > > + if (SearchType & SRC_BY_NAME) {
> > > + if (!StrCmp (Name, Entry->PartitionName)) {
> > > + return Entry;
> > > + }
> > > + }
> > > + if (SearchType & SRC_BY_NUM) {
> > > + UINTN Ordinal;
> > > +
> > > + Ordinal = ShellStrToUintn (Name);
> > > + if (Index == (Ordinal - 1)) {
> > > + return Entry;
> > > + }
> > > + }
> > > + if (SearchType & SRC_BY_LBA) {
> > > + if (
> > > + ((StartLba >= Entry->StartingLBA) &&
> > > + (StartLba <= Entry->EndingLBA)
> > > + ) ||
> > > + ((EndingLba >= Entry->StartingLBA) &&
> > > + (EndingLba <= Entry->EndingLBA)
> > > + )
> > > + ) {
> > > + return Entry;
> > > + }
> > > + }
> > > + }
> > > + return NULL;
> > > +}
> > > +
> > > +/**
> > > + Prints information on a given partition.
> > > +
> > > + @param Entry Pointer to the Partition of interest
> > > +**/
> > > +
> > > +VOID
> > > +PartitionPrintGptPartInfo (
> > > + IN EFI_PARTITION_ENTRY *Entry
> > > + )
> > > +{
> > > + CONST CHAR16 PartStr[MAX_PARTITION_NAME_LENGTH + 1] = { L'\0' };
> > > + CONST CHAR16 *StrUnknown = L"Unknown";
> > > + EFI_STATUS Status;
> > > + EFI_LBA Length;
> > > +
> > > + ASSERT (Entry);
> > > +
> > > + Status = GetPartitionTypeStr (Entry->PartitionTypeGUID, (CHAR16
> > > *)&PartStr, TRUE);
> > > + if (EFI_ERROR (Status)) {
> > > + StrCpy ((CHAR16 *)&PartStr, StrUnknown);
> > > + }
> > > +
> > > + Length = Entry->EndingLBA - Entry->StartingLBA + 1;
> > > +
> > > + Print (L"Partition name: %s\r\n", Entry->PartitionName);
> > > + Print (L"Starting LBA : 0x%09llx\r\nEnding LBA : 0x%09llx\r\n",
> > > + (UINT64)Entry->StartingLBA, (UINT64)Entry->EndingLBA);
> > > + Print (L"Partition Size: %llu MiB (0x%llx blocks)\n",
> > > + (MultU64x32 (Length, BlockIo->Media->BlockSize)) >> 20, Length);
> > > + Print (L"Attributes : 0x%09llx\r\n", Entry->Attributes);
> > > + Print (L"Type/GUID : %s/%g\r\n", PartStr, &Entry->PartitionTypeGUID);
> > > + Print (L"Unique GUID : %g\n", &Entry->UniquePartitionGUID);
> > > +}
> > > +
> > > +
> > > +/**
> > > + Writes protective MBR to a block device.
> > > +
> > > + @return EFI_SUCCESS MBR written successfully
> > > + @return other Failed to write an MBR
> > > +
> > > +**/
> > > +
> > > +STATIC
> > > +EFI_STATUS
> > > +WriteProtectiveMbr (
> > > + VOID
> > > + )
> > > +{
> > > + UINT32 BlockSize;
> > > + UINT64 DiskSize;
> > > + EFI_STATUS Status;
> > > + MBR_PARTITION_RECORD *Partition;
> > > + MASTER_BOOT_RECORD *ProtectiveMbr;
> > > +
> > > + BlockSize = BlockIo->Media->BlockSize;
> > > +
> > > + ProtectiveMbr = NULL;
> > > + ProtectiveMbr = AllocateZeroPool (BlockSize);
> > > + if (ProtectiveMbr == NULL) {
> > > + return EFI_OUT_OF_RESOURCES;
> > > + }
> > > +
> > > + DiskSize = BlockIo->Media->LastBlock + 1;
> > > + if (DiskSize > 0xffffffff) {
> > > + DiskSize = 0xffffffff;
> > > + }
> > > +
> > > + CopyMem (ProtectiveMbr, &ProtectiveMbrTemplate,
> > > sizeof(MASTER_BOOT_RECORD));
> > > +
> > > + Partition = &ProtectiveMbr->Partition[0];
> > > +
> > > + Partition->BootIndicator = 0;
> > > + Partition->StartSector = 1;
> > > +
> > > + //
> > > + // We don't actually know this data, so we'll make up
> > > + // something that seems likely.
> > > + //
> > > +
> > > + //
> > > + // Old software is expecting the Partition to start on
> > > + // a Track boundary, so we'll set track to 1 to avoid "overlay"
> > > + // with the MBR
> > > + //
> > > +
> > > + Partition->StartTrack = 1;
> > > +
> > > + Status = DiskIo->WriteDisk (
> > > + DiskIo,
> > > + BlockIo->Media->MediaId,
> > > + 0,
> > > + BlockSize,
> > > + ProtectiveMbr
> > > + );
> > > +
> > > + MbrValid = !EFI_ERROR (Status);
> > > +
> > > + SHELL_FREE_NON_NULL (ProtectiveMbr);
> > > +
> > > + return Status;
> > > +}
> > > +
> > > +/**
> > > + Write GPT tables to the block device.
> > > +
> > > + @return EFI_SUCCESS GPT tables were successfully written/updated
> > > + @return other Failed to write/update GPT tables
> > > +
> > > +**/
> > > +
> > > +STATIC
> > > +EFI_STATUS
> > > +WriteGPT (
> > > + VOID
> > > + )
> > > +/*
> > > + CALLER is expected to fill in:
> > > + FirstUseableLBA
> > > + LastUseableLBA
> > > + EntryCount
> > > + DiskGUID
> > > +
> > > + We fill in the rest, and blast it out.
> > > +
> > > + Returns a status.
> > > +
> > > +*/
> > > +{
> > > + UINT32 BlockSize;
> > > + UINT32 TableSize;
> > > + EFI_STATUS Status = EFI_SUCCESS;
> > > +
> > > + BlockSize = BlockIo->Media->BlockSize;
> > > + TableSize = PrimaryHeader->NumberOfPartitionEntries *
> > > sizeof(EFI_PARTITION_ENTRY);
> > > +
> > > + if (!MbrValid) {
> > > + WriteProtectiveMbr ();
> > > + }
> > > + //
> > > + // Write out the primary header...
> > > + //
> > > + PrimaryHeader->Header.Signature = EFI_PTAB_HEADER_ID;
> > > + PrimaryHeader->Header.Revision = GPT_REVISION_1_0;
> > > + PrimaryHeader->Header.HeaderSize =
> > > sizeof(EFI_PARTITION_TABLE_HEADER);
> > > +
> > > + PrimaryHeader->AlternateLBA = BackupHeader->MyLBA;
> > > +
> > > + PrimaryHeader->SizeOfPartitionEntry = sizeof(EFI_PARTITION_ENTRY);
> > > +
> > > + Status = gBS->CalculateCrc32 ((UINT8 *)PartEntry, TableSize,
> > > &PrimaryHeader->PartitionEntryArrayCRC32);
> > > + if (EFI_ERROR (Status)) {
> > > + return Status;
> > > + }
> > > +
> > > + // Write primary header
> > > + PartitionSetCrc (&PrimaryHeader->Header);
> > > +
> > > + Status = DiskIo->WriteDisk (
> > > + DiskIo,
> > > + BlockIo->Media->MediaId,
> > > + MultU64x32 (PrimaryHeader->MyLBA, (UINT32)BlockSize),
> > > + BlockSize,
> > > + PrimaryHeader
> > > + );
> > > +
> > > +
> > > + if (EFI_ERROR (Status)) {
> > > + return Status;
> > > + }
> > > +
> > > + //
> > > + // Write out the primary table ...
> > > + //
> > > + Status = DiskIo->WriteDisk (
> > > + DiskIo,
> > > + BlockIo->Media->MediaId,
> > > + MultU64x32 (PrimaryHeader->PartitionEntryLBA, (UINT32)BlockSize),
> > > + TableSize,
> > > + PartEntry
> > > + );
> > > +
> > > +
> > > + if (EFI_ERROR (Status)) {
> > > + return Status;
> > > + }
> > > +
> > > + //
> > > + // Write out the secondary header and table by calling restore
> > > + //
> > > +
> > > + if (!PartitionRestoreGptTable (PrimaryHeader)) {
> > > + return EFI_VOLUME_CORRUPTED;
> > > + }
> > > + BlockIo->FlushBlocks (BlockIo);
> > > + GptValid = !EFI_ERROR (Status);
> > > +
> > > + return Status;
> > > +}
> > > +
> > > +/**
> > > + (Re)initialize GPT tables on the block device
> > > +
> > > + @return EFI_SUCCESS Successfully (re)initialized GPT Tables
> > > + @return other Failed to (re)initialize GPT tables
> > > +
> > > +**/
> > > +STATIC
> > > +EFI_STATUS
> > > +TableCreateEmptyGpt (VOID)
> > > +{
> > > + UINTN EntryCount;
> > > + UINTN BlockFit;
> > > + UINTN BlockSize;
> > > + UINTN EntryBlocks;
> > > + UINT64 DiskSize;
> > > + UINTN TableSize;
> > > + EFI_LBA Header1_LBA;
> > > + EFI_LBA Table1_LBA;
> > > + EFI_LBA Header2_LBA;
> > > + EFI_LBA Table2_LBA;
> > > + EFI_LBA FirstUsableLBA;
> > > + EFI_LBA LastUsableLBA;
> > > + EFI_STATUS Status;
> > > +
> > > + EntryCount = ENTRY_DEFAULT;
> > > + BlockSize = BlockIo->Media->BlockSize;
> > > + BlockFit = BlockSize / sizeof(EFI_PARTITION_ENTRY);
> > > +
> > > + if (BlockFit > ENTRY_DEFAULT) {
> > > + EntryCount = BlockFit;
> > > + }
> > > + EntryBlocks = EntryCount / BlockFit;
> > > +
> > > + if ((EntryBlocks * BlockFit) != EntryCount) {
> > > + Status = EFI_VOLUME_CORRUPTED;
> > > + PrintErr (L"Invalid Entry blocks and Entry count combination\n", Status);
> > > + return Status;
> > > + }
> > > +
> > > + DiskSize = BlockIo->Media->LastBlock + 1;
> > > +
> > > + SHELL_FREE_NON_NULL (PrimaryHeader);
> > > + SHELL_FREE_NON_NULL (BackupHeader);
> > > + SHELL_FREE_NON_NULL (PartEntry);
> > > +
> > > + PrimaryHeader = AllocateZeroPool (BlockSize);
> > > + if (PrimaryHeader == NULL) {
> > > + return EFI_OUT_OF_RESOURCES;
> > > + }
> > > +
> > > + BackupHeader = AllocateZeroPool (BlockSize);
> > > + if (BackupHeader == NULL) {
> > > + return EFI_OUT_OF_RESOURCES;
> > > + }
> > > +
> > > + Header1_LBA = 1;
> > > + Table1_LBA = 2;
> > > + FirstUsableLBA = Table1_LBA + EntryBlocks;
> > > +
> > > + Header2_LBA = DiskSize - 1;
> > > + Table2_LBA = Header2_LBA - EntryBlocks;
> > > + LastUsableLBA = Table2_LBA - 1;
> > > +
> > > + TableSize = EntryBlocks * BlockSize;
> > > +
> > > + if (TableSize != (EntryCount * sizeof(EFI_PARTITION_ENTRY))) {
> > > + Status = EFI_VOLUME_CORRUPTED;
> > > + PrintErr (L"Invalid Table size and Entry count combination\n", Status);
> > > + return Status;
> > > + }
> > > +
> > > + if (GPT_DEBUG_LEVEL) {
> > > + Print (L"DiskSize = %lx\n", DiskSize);
> > > + Print (L"BlockSize = %x\n", BlockSize);
> > > + Print (L"Header1_LBA = %lx\n", Header1_LBA);
> > > + Print (L"Table1_LBA = %lx\n", Table1_LBA);
> > > + Print (L"FirstUsableLBA = %lx\n", FirstUsableLBA);
> > > + Print (L"Header2_LBA = %lx\n", Header2_LBA);
> > > + Print (L"Table2_LBA = %lx\n", Table2_LBA);
> > > + Print (L"LastUsableLBA = %lx\n", LastUsableLBA);
> > > + Print (L"EntryCount = %x\n", EntryCount);
> > > + Print (L"EntryBlocks = %x\n", EntryBlocks);
> > > + }
> > > +
> > > + //
> > > + // Since we're making empty tables, we just write zeros...
> > > + //
> > > +
> > > + PartEntry = AllocateZeroPool (TableSize);
> > > + if (PartEntry == NULL) {
> > > + SHELL_FREE_NON_NULL (PrimaryHeader);
> > > + SHELL_FREE_NON_NULL (BackupHeader);
> > > + return EFI_OUT_OF_RESOURCES;
> > > + }
> > > +
> > > + PEntryStatus = AllocateZeroPool (TableSize);
> > > +
> > > + PrimaryHeader->FirstUsableLBA = FirstUsableLBA;
> > > + PrimaryHeader->LastUsableLBA = LastUsableLBA;
> > > + PrimaryHeader->NumberOfPartitionEntries = (UINT32)EntryCount;
> > > + GenerateGuid (&PrimaryHeader->DiskGUID);
> > > +
> > > + PrimaryHeader->MyLBA = Header1_LBA;
> > > + BackupHeader->MyLBA = Header2_LBA;
> > > + PrimaryHeader->PartitionEntryLBA = Table1_LBA;
> > > + BackupHeader->PartitionEntryLBA = Table2_LBA;
> > > +
> > > + Status = WriteGPT ();
> > > +
> > > + return Status;
> > > +}
> > > +
> > > +/**
> > > + Clear GPT partitions.
> > > +
> > > + @return EFI_SUCCESS Cleared successfully
> > > + @return FALSE Failed to clear
> > > +
> > > +**/
> > > +
> > > +EFI_STATUS
> > > +PartitionGptClearAll (VOID)
> > > +{
> > > + GptCleanupGlobals ();
> > > + GptValid = FALSE;
> > > + MbrValid = FALSE;
> > > + return TableCreateEmptyGpt ();
> > > +}
> > > +
> > > +/**
> > > + Create a GPT partition.
> > > +
> > > + @param PartName Partition Name
> > > + @param StartLba Starting LBA of the partition.
> > > + if zero, will be calculated
> > > + @param SizeInMegaBytes Size of the partition in MB
> > > + @param Attributes Partition attributes
> > > + @param PartTypeGuid a Type GUID to be assigned to the partition
> > > (not a partition unique GUID)
> > > +
> > > +
> > > + @return EFI_SUCCESS Partition successfully created
> > > + @return EFI_INVALID_PARAMETER Either partition exists, or wrong
> > > parameters specified
> > > + @return other Failed to create a partition
> > > +**/
> > > +EFI_STATUS
> > > +PartitionGptCreatePartition (
> > > + IN CONST CHAR16 *PartName,
> > > + IN EFI_LBA StartLba,
> > > + IN UINT64 SizeInMegabytes,
> > > + IN UINT64 Attributes,
> > > + IN EFI_GUID PartTypeGuid)
> > > +{
> > > + EFI_GUID Guid, PartitionIdGuid;
> > > + EFI_STATUS Status;
> > > + UINT64 StartBlock;
> > > + UINT64 EndBlock;
> > > + UINT64 SizeInBytes = 0;
> > > + UINT32 BlockSize;
> > > + UINT64 DiskSizeBlocks;
> > > + UINT8 *p;
> > > + BOOLEAN OffsetSpecified = FALSE;
> > > + BOOLEAN AllZeros;
> > > + INTN AllZeroEntry;
> > > + INTN OldFreeEntry;
> > > + UINT64 AvailBlocks;
> > > + UINT64 BlocksToAllocate;
> > > + UINT64 HighSeen;
> > > + UINTN Slot;
> > > + UINT64 LowestAlignedLba;
> > > + UINT32 OptimalTransferBlocks;
> > > + UINTN i, j;
> > > + CHAR16 PartNameUsed[MAX_PARTITION_NAME_LENGTH + 1] =
> > { L'\0' };
> > > + EFI_PARTITION_ENTRY *Entry;
> > > +
> > > + LowestAlignedLba = 0;
> > > + OptimalTransferBlocks = 1;
> > > +
> > > + AllZeroEntry = -1;
> > > + OldFreeEntry = -1;
> > > +
> > > + BlockSize = BlockIo->Media->BlockSize;
> > > + OffsetSpecified = (StartLba != 0);
> > > + CopyMem (&PartNameUsed, PartName, sizeof(CHAR16) * StrSize
> > > (PartName));
> > > +
> > > + GenerateGuid (&Guid);
> > > +
> > > + // Creating a new partition
> > > + if (!GptValid) {
> > > + // Creating a GPT for the first time
> > > + Status = TableCreateEmptyGpt ();
> > > + if (!EFI_ERROR (Status)) {
> > > + // Fill in the structures
> > > + Status = PartitionGetGptTables (DiskIo, BlockIo);
> > > + }
> > > + if (EFI_ERROR (Status)) {
> > > + return Status;
> > > + }
> > > + }
> > > +
> > > + Entry = PartitionFindPartitionByCriteria (PartName, 0, 0, SRC_BY_NAME);
> > > + if (Entry) {
> > > + Status = EFI_INVALID_PARAMETER;
> > > + PrintErr (L"Partition with this name already exists", Status);
> > > + return Status;
> > > + }
> > > + HighSeen = PrimaryHeader->FirstUsableLBA - 1;
> > > +
> > > + if (StartLba) {
> > > + //
> > > + // if offset is specified, compute the start and end blocks
> > > + //
> > > + StartBlock = StartLba;
> > > + //
> > > + // StartBlock should be aligned to OptimalTransferBlocks, the least
> > > common multiple of:
> > > + // a). the physical block boundary, if any
> > > + // b). the optimal transfer length granularity, if any
> > > + //
> > > + if (StartBlock < LowestAlignedLba) {
> > > + StartBlock = LowestAlignedLba;
> > > + } else {
> > > + while (((StartBlock - LowestAlignedLba) % OptimalTransferBlocks) != 0)
> > {
> > > + StartBlock++;
> > > + }
> > > + }
> > > +
> > > + if (StartBlock < PrimaryHeader->FirstUsableLBA ||
> > > + StartBlock > PrimaryHeader->LastUsableLBA) {
> > > + //
> > > + // Offset specified is too large
> > > + //
> > > + Status = EFI_INVALID_PARAMETER;
> > > + PrintErr (L"Specified offset is too large", EFI_INVALID_PARAMETER);
> > > + goto Exit;
> > > + }
> > > +
> > > + SizeInBytes = MultU64x32 (SizeInMegabytes, (1024 * 1024));
> > > + if (SizeInBytes < SizeInMegabytes || SizeInBytes == 0) {
> > > + //
> > > + // If size is not specified or too large,
> > > + // try to make the partition as big as it can be
> > > + //
> > > + BlocksToAllocate = EndBlock = SizeInBytes = 0xffffffffffffffff;
> > > + } else {
> > > + BlocksToAllocate = DivU64x32 (SizeInBytes, BlockSize);
> > > + EndBlock = StartBlock + BlocksToAllocate - 1;
> > > + if (EndBlock > PrimaryHeader->LastUsableLBA) {
> > > + EndBlock = PrimaryHeader->LastUsableLBA;
> > > + BlocksToAllocate = EndBlock - StartBlock + 1;
> > > + }
> > > + }
> > > + }
> > > +
> > > + for (i = 0; i < PrimaryHeader->NumberOfPartitionEntries; i++) {
> > > + Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + i *
> > > PrimaryHeader->SizeOfPartitionEntry);
> > > + if (!CompareGuid (&Entry->PartitionTypeGUID,
> > > &gEfiPartTypeUnusedGuid)) {
> > > +
> > > + //
> > > + // Type not null, so it's allocated
> > > + //
> > > + if (Entry->EndingLBA > HighSeen) {
> > > + HighSeen = Entry->EndingLBA;
> > > + }
> > > + if (OffsetSpecified) {
> > > + //
> > > + // make sure new partition does not overlap with existing partitions
> > > + //
> > > + if (Entry->StartingLBA <= StartBlock &&
> > > + StartBlock <= Entry->EndingLBA) {
> > > + //
> > > + // starting block is inside an existing partition
> > > + //
> > > + Status = EFI_INVALID_PARAMETER;
> > > + PrintErr (L"Starting block is inside an existing partition", Status);
> > > + goto Exit;
> > > + }
> > > + if ((Entry->StartingLBA <= EndBlock &&
> > > + EndBlock <= Entry->EndingLBA) ||
> > > + (StartBlock <= Entry->StartingLBA &&
> > > + Entry->StartingLBA <= EndBlock) ||
> > > + (StartBlock <= Entry->EndingLBA &&
> > > + Entry->EndingLBA <= EndBlock)) {
> > > + //
> > > + // new partition overlaps with an existing partition
> > > + // readjust new partition size to avoid overlapping
> > > + //
> > > + EndBlock = Entry->StartingLBA - 1;
> > > + if (EndBlock < StartBlock) {
> > > + Status = EFI_INVALID_PARAMETER;
> > > + PrintErr (L"Cannot readjust new partition size - overlapping", Status);
> > > + goto Exit;
> > > + } else {
> > > + BlocksToAllocate = EndBlock - StartBlock + 1;
> > > + }
> > > + }
> > > + }
> > > + } else {
> > > + p = (UINT8 *)(Entry);
> > > + AllZeros = TRUE;
> > > + for (j = 0; j < sizeof(EFI_PARTITION_ENTRY); j++) {
> > > + if (p[j] != 0) {
> > > + AllZeros = FALSE;
> > > + }
> > > + }
> > > + if (AllZeros) {
> > > + if (AllZeroEntry == -1) {
> > > + AllZeroEntry = i;
> > > + }
> > > + } else if (OldFreeEntry == -1) {
> > > + OldFreeEntry = i;
> > > + }
> > > + }
> > > + }
> > > +
> > > + //
> > > + // AllZeroEntry - if not -1, is pointer to a never before used entry (free)
> > > + // OldFreeEntry - if not -1, is pointer to some pre-used free entry
> > > + //
> > > + if ((AllZeroEntry == -1) && (OldFreeEntry == -1)) {
> > > + //
> > > + // TABLE IS FULL!!
> > > + //
> > > + Status = EFI_OUT_OF_RESOURCES;
> > > + PrintErr (L"Table is full", Status);
> > > + goto Exit;
> > > + }
> > > +
> > > + if (OffsetSpecified) {
> > > + //
> > > + // the user haven't specified the new partition size and we haven't
> > > + // run into any partition that will limit the size of this new partition.
> > > + // So, use the max it can
> > > + //
> > > + if (BlocksToAllocate == -1) {
> > > + EndBlock = PrimaryHeader->LastUsableLBA;
> > > + BlocksToAllocate = EndBlock - StartBlock + 1;
> > > + }
> > > + } else {
> > > + //
> > > + // Because HighSeen is the last LBA of the used blocks, let HighSeen
> > align
> > > to the least common multiple of:
> > > + // a). the physical block boundary, if any
> > > + // b). the optimal transfer length granularity, if any
> > > + //
> > > + if (HighSeen + 1 < LowestAlignedLba) {
> > > + HighSeen = LowestAlignedLba - 1;
> > > + } else {
> > > + while (((HighSeen + 1 - LowestAlignedLba) % OptimalTransferBlocks) !=
> > 0)
> > > {
> > > + HighSeen++;
> > > + }
> > > + }
> > > +
> > > + if (PrimaryHeader->LastUsableLBA <= HighSeen) {
> > > + Status = EFI_OUT_OF_RESOURCES;
> > > + PrintErr (L"Disk has no free blocks (FULL) cannot create", Status);
> > > + goto Exit;
> > > + }
> > > + //
> > > + // [HighSeen+1 ... LastUsableLBA] is available...
> > > + // avail = (LastUsableLBA - (HighSeen+1)) + 1 => LastUsabbleLBA -
> > > HighSeen
> > > + //
> > > + AvailBlocks = PrimaryHeader->LastUsableLBA - HighSeen;
> > > +
> > > + SizeInBytes = MultU64x32 (SizeInMegabytes, (1024 * 1024));
> > > + if (SizeInBytes < SizeInMegabytes) {
> > > + //
> > > + // overflow, force a very big answer
> > > + //
> > > + SizeInBytes = 0xffffffffffffffff;
> > > + }
> > > +
> > > + if ((SizeInBytes == 0) ||
> > > + (SizeInBytes > (MultU64x32 (AvailBlocks, BlockSize)))) {
> > > + //
> > > + // User asked for zero, or for more than we've got,
> > > + // so give them all that is left
> > > + //
> > > + BlocksToAllocate = AvailBlocks;
> > > +
> > > + } else {
> > > +
> > > + //
> > > + // We would have to have a BlockSize > 1mb for Remainder to
> > > + // not be 0. Since we cannot actually test this case, we
> > > + // ingore it...
> > > + //
> > > + BlocksToAllocate = DivU64x32 (SizeInBytes, BlockSize);
> > > +
> > > + }
> > > + }
> > > +
> > > + //
> > > + // We have a name
> > > + // We have a type guid
> > > + // We have a size in blocks
> > > + // We have an attribute mask
> > > + //
> > > +
> > > + if (BlocksToAllocate < ((1024 * 1024) / BlockSize)) {
> > > + Status = EFI_OUT_OF_RESOURCES;
> > > + PrintErr (L"Partition is too small to be created", Status);
> > > + goto Exit;
> > > + }
> > > +
> > > + if (GPT_DEBUG_LEVEL) {
> > > + Print (L"Requested SizeInMegaBytes = %ld\n", SizeInMegabytes);
> > > + Print (L"Resulting size in Blocks = %ld\n", BlocksToAllocate);
> > > + Print (L"Results size in Bytes = %ld\n", MultU64x32 (BlocksToAllocate,
> > > BlockSize));
> > > + }
> > > +
> > > + if (AllZeroEntry != -1) {
> > > + Slot = AllZeroEntry;
> > > + } else {
> > > + Slot = OldFreeEntry;
> > > + }
> > > +
> > > + GenerateGuid (&PartitionIdGuid);
> > > + Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Slot *
> > > PrimaryHeader->SizeOfPartitionEntry);
> > > +
> > > + CopyMem (&Entry->PartitionTypeGUID, &PartTypeGuid,
> > > sizeof(EFI_GUID));
> > > + CopyMem (&Entry->UniquePartitionGUID, &PartitionIdGuid,
> > > sizeof(EFI_GUID));
> > > + if (OffsetSpecified) {
> > > + PartEntry[Slot].StartingLBA = StartBlock;
> > > + PartEntry[Slot].EndingLBA = EndBlock;
> > > + } else {
> > > + PartEntry[Slot].StartingLBA = HighSeen + 1;
> > > + PartEntry[Slot].EndingLBA = HighSeen + BlocksToAllocate;
> > > + }
> > > +
> > > + if (!(((Entry->EndingLBA - Entry->StartingLBA) + 1) == BlocksToAllocate)) {
> > > + PrintErr (L"Wrong Size for new partiton", EFI_INVALID_PARAMETER);
> > > + goto Exit;
> > > + }
> > > +
> > > + if ((Entry->StartingLBA < PrimaryHeader->FirstUsableLBA) ||
> > > + (Entry->EndingLBA > PrimaryHeader->LastUsableLBA)) {
> > > + PrintErr (L"New Partition out of bounds", EFI_INVALID_PARAMETER);
> > > + goto Exit;
> > > + }
> > > +
> > > + Entry->Attributes = Attributes;
> > > + CopyMem (&(Entry->PartitionName[0]), PartName,
> > > MAX_PARTITION_NAME_LENGTH * sizeof(CHAR16));
> > > +
> > > + DiskSizeBlocks = BlockIo->Media->LastBlock + 1;
> > > + if (DiskSizeBlocks > 0xffffffff) {
> > > + DiskSizeBlocks = 0xffffffff;
> > > + }
> > > +
> > > + Status = WriteGPT ();
> > > +
> > > + if (EFI_ERROR (Status)) {
> > > + PrintErr (L"Attempt to Write out partition table failed", Status);
> > > + }
> > > +
> > > + Exit:
> > > + return Status;
> > > +}
> > > +
> > > +/**
> > > + Modifiy a partition based on parameters.
> > > +
> > > + @param Entry Pointer to an existing partition
> > > + @param Params Parameters to be modified
> > > + @param Flags Which parameter is to be modified
> > > +
> > > + @return EFI_SUCCESS Successfully modified the partition
> > > + @return other Failed to modify a partition
> > > +
> > > +**/
> > > +
> > > +EFI_STATUS
> > > +PartitionGptModifyPartition (
> > > + IN EFI_PARTITION_ENTRY *Entry,
> > > + IN MOD_PARAMS *Params,
> > > + IN MOD_FLAGS Flags
> > > + )
> > > +{
> > > + EFI_STATUS Status;
> > > +
> > > + ASSERT (Entry);
> > > +
> > > + Status = EFI_INVALID_PARAMETER;
> > > +
> > > + switch (Flags) {
> > > + case MOD_DELETE:
> > > + ZeroMem (Entry, sizeof(EFI_PARTITION_ENTRY));
> > > + break;
> > > + case MOD_ATTR:
> > > + Entry->Attributes = Params->Attributes;
> > > + break;
> > > + case MOD_TYPE:
> > > + Entry->PartitionTypeGUID = Params->PartTypeGuid;
> > > + break;
> > > + case MOD_RENAME:
> > > + StrCpy (Entry->PartitionName, Params->NewName);
> > > + break;
> > > + default:
> > > + PrintErr (L"Unknown modification flag(s)", Status);
> > > + return Status;
> > > + }
> > > +
> > > + return WriteGPT ();
> > > +}
> > > +
> > > +EFI_KNOWN_PARTITION_TYPE *PartitionGetKnownType (
> > > + IN UINTN Index,
> > > + IN OUT OPTIONAL UINTN *NumEntries
> > > + )
> > > +{
> > > + if (NumEntries) {
> > > + *NumEntries = ARRAY_SIZE(PartitionTypes);
> > > + }
> > > + if (Index > ARRAY_SIZE(PartitionTypes)) {
> > > + return NULL;
> > > + }
> > > +
> > > + return &PartitionTypes[Index];
> > > +}
> > > +
> > > diff --git a/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> > > b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> > > new file mode 100644
> > > index 000000000000..9efec5cefe94
> > > --- /dev/null
> > > +++ b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> > > @@ -0,0 +1,186 @@
> > > +/*
> > > + * BSD LICENSE
> > > + *
> > > + * Copyright(c) 2016 Broadcom. All rights reserved.
> > > + *
> > > + * Redistribution and use in source and binary forms, with or without
> > > + * modification, are permitted provided that the following conditions
> > > + * are met:
> > > + *
> > > + * * Redistributions of source code must retain the above copyright
> > > + * notice, this list of conditions and the following disclaimer.
> > > + * * Redistributions in binary form must reproduce the above copyright
> > > + * notice, this list of conditions and the following disclaimer in
> > > + * the documentation and/or other materials provided with the
> > > + * distribution.
> > > + * * Neither the name of Broadcom nor the names of its
> > > + * contributors may be used to endorse or promote products derived
> > > + * from this software without specific prior written permission.
> > > + *
> > > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> > > CONTRIBUTORS
> > > + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
> > > NOT
> > > + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
> > > FITNESS FOR
> > > + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
> > > COPYRIGHT
> > > + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> > > INCIDENTAL,
> > > + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> > BUT
> > > NOT
> > > + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
> > LOSS
> > > OF USE,
> > > + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
> > > AND ON ANY
> > > + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> > > TORT
> > > + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
> > OF
> > > THE USE
> > > + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> > > DAMAGE.
> > > + */
> > > +
> > > +/* GPT partitioner header file */
> > > +
> > > +#ifndef _GPTWORKER_H_
> > > +#define _GPTWORKER_H_
> > > +
> > > +#include <Uefi.h>
> > > +#include <ShellBase.h>
> > > +
> > > +#include <Library/BaseLib.h>
> > > +#include <Library/BaseMemoryLib.h>
> > > +#include <Library/DebugLib.h>
> > > +#include <Library/MemoryAllocationLib.h>
> > > +#include <Library/ShellCommandLib.h>
> > > +#include <Library/ShellLib.h>
> > > +#include <Library/UefiLib.h>
> > > +#include <Library/UefiShellLib/UefiShellLib.h>
> > > +#include <Library/UefiBootServicesTableLib.h>
> > > +#include <Library/UefiRuntimeServicesTableLib.h>
> > > +#include <Library/PrintLib.h>
> > > +#include <Library/ShellCEntryLib.h>
> > > +#include <Library/HiiLib.h>
> > > +#include <Library/FileHandleLib.h>
> > > +#include <Protocol/DevicePath.h>
> > > +#include <Library/DevicePathLib.h>
> > > +#include <Protocol/BlockIo.h>
> > > +#include <Protocol/DiskIo.h>
> > > +#include <IndustryStandard/Mbr.h>
> > > +
> > > +typedef enum {
> > > + MOD_NAME = BIT0,
> > > + MOD_ATTR = BIT1,
> > > + MOD_TYPE = BIT2,
> > > + MOD_DELETE = BIT3,
> > > + MOD_RENAME = BIT4
> > > +} MOD_FLAGS;
> > > +
> > > +typedef struct {
> > > + UINTN Attributes;
> > > + EFI_GUID PartTypeGuid;
> > > + CONST CHAR16 *PartName;
> > > + CONST CHAR16 *NewName;
> > > +} MOD_PARAMS;
> > > +
> > > +typedef enum {
> > > + SRC_BY_NAME = BIT0,
> > > + SRC_BY_LBA = BIT1,
> > > + SRC_BY_NUM = BIT2,
> > > + SRC_ANY = BIT3
> > > +} SEARCH_TYPE;
> > > +
> > > +#define MAX_PARTITION_NAME_LENGTH 36
> > > +#define ENTRY_DEFAULT 128
> > > +#define GPT_REVISION_1_0 0x00010000
> > > +
> > > +#define ARRAY_SIZE(x) \
> > > + (sizeof(x) / sizeof((x)[0]))
> > > +
> > > +//
> > > +// Extract INT32 from char array
> > > +//
> > > +#define UNPACK_INT32(a) (INT32)( (((UINT8 *) a)[0] << 0) | \
> > > + (((UINT8 *) a)[1] << 8) | \
> > > + (((UINT8 *) a)[2] << 16) | \
> > > + (((UINT8 *) a)[3] << 24) )
> > > +
> > > +//
> > > +// Extract UINT32 from char array
> > > +//
> > > +#define UNPACK_UINT32(a) (UINT32)( (((UINT8 *) a)[0] << 0) | \
> > > + (((UINT8 *) a)[1] << 8) | \
> > > + (((UINT8 *) a)[2] << 16) | \
> > > + (((UINT8 *) a)[3] << 24) )
> > > +
> > > +
> > > +//
> > > +// GPT Partition Entry Status
> > > +//
> > > +typedef struct {
> > > + BOOLEAN OutOfRange;
> > > + BOOLEAN Overlap;
> > > + BOOLEAN OsSpecific;
> > > +} EFI_PARTITION_ENTRY_STATUS;
> > > +
> > > +typedef struct {
> > > + CONST EFI_GUID TypeGuid;
> > > + CONST CHAR16 *TypeName;
> > > +
> > > +} EFI_KNOWN_PARTITION_TYPE;
> > > +
> > > +EFI_KNOWN_PARTITION_TYPE *PartitionGetKnownType (
> > > + IN UINTN Index,
> > > + IN OUT OPTIONAL UINTN *NumEntries
> > > + );
> > > +
> > > +EFI_STATUS
> > > +PartitionGetGptTables (
> > > + IN EFI_DISK_IO_PROTOCOL *DiskIoProt,
> > > + IN EFI_BLOCK_IO_PROTOCOL *BlockIoProt
> > > + );
> > > +
> > > +UINTN
> > > +PartitionListGptEntries (
> > > + VOID
> > > + );
> > > +
> > > +VOID
> > > +PartitionPrintGptPartInfo (
> > > + IN EFI_PARTITION_ENTRY *Entry
> > > + );
> > > +
> > > +EFI_STATUS
> > > +GetPartitionTypeStr (
> > > + EFI_GUID Guid,
> > > + CHAR16 *PartTypeStr,
> > > + BOOLEAN NoGuidStr
> > > + );
> > > +
> > > +
> > > +EFI_STATUS
> > > +PartitionGptClearAll (
> > > + VOID
> > > + );
> > > +
> > > +EFI_STATUS
> > > +PartitionGptCreatePartition (
> > > + CONST CHAR16 *PartName,
> > > + EFI_LBA StartLba,
> > > + EFI_LBA PartitionSize,
> > > + UINT64 Attributes,
> > > + EFI_GUID PartTypeGuid);
> > > +
> > > +EFI_STATUS
> > > +PartitionGptModifyPartition (
> > > + EFI_PARTITION_ENTRY *Entry,
> > > + MOD_PARAMS *Params,
> > > + MOD_FLAGS Flags
> > > + );
> > > +
> > > +VOID
> > > +GptCleanupGlobals (
> > > + VOID
> > > + );
> > > +
> > > +EFI_PARTITION_ENTRY *
> > > +PartitionFindPartitionByCriteria (
> > > + CONST CHAR16 *Name,
> > > + EFI_LBA StartLba,
> > > + EFI_LBA EndingLba,
> > > + SEARCH_TYPE SearchType);
> > > +
> > > +VOID
> > > +PrintErr (IN CONST CHAR16 *Message, IN EFI_STATUS Status);
> > > +
> > > +#endif //_GPTWORKER_H_
> > > diff --git
> > > a/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> > > b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> > > new file mode 100644
> > > index 000000000000..a9d74a780911
> > > --- /dev/null
> > > +++
> > > b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> > > @@ -0,0 +1,1135 @@
> > >
> > +/*********************************************************
> > > **********************
> > > +Copyright (C) 2016 Marvell International Ltd.
> > > +
> > > +Marvell BSD License Option
> > > +
> > > +If you received this File from Marvell, you may opt to use, redistribute
> > > and/or
> > > +modify this File under the following licensing terms.
> > > +Redistribution and use in source and binary forms, with or without
> > > modification,
> > > +are permitted provided that the following conditions are met:
> > > +
> > > +* Redistributions of source code must retain the above copyright notice,
> > > + this list of conditions and the following disclaimer.
> > > +
> > > +* Redistributions in binary form must reproduce the above copyright
> > > + notice, this list of conditions and the following disclaimer in the
> > > + documentation and/or other materials provided with the distribution.
> > > +
> > > +* Neither the name of Marvell nor the names of its contributors may be
> > > + used to endorse or promote products derived from this software
> > without
> > > + specific prior written permission.
> > > +
> > > +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> > > CONTRIBUTORS "AS IS" AND
> > > +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
> > TO,
> > > THE IMPLIED
> > > +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> > > PURPOSE ARE
> > > +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> > > CONTRIBUTORS BE LIABLE FOR
> > > +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> > > CONSEQUENTIAL DAMAGES
> > > +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
> > GOODS
> > > OR SERVICES;
> > > +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
> > HOWEVER
> > > CAUSED AND ON
> > > +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> > > TORT
> > > +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
> > > THE USE OF THIS
> > > +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> > > +
> > >
> > +*********************************************************
> > > **********************/
> > > +
> > > +/* Portions Copyright (C) 2016 Broadcom */
> > > +
> > > +#include "FatFormat.h"
> > > +#include
> > > <Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.h>
> > > +#include <Library/TimerLib.h>
> > > +
> > > +CONST CHAR16 gShellGptFileName[] = L"ShellCommand";
> > > +STATIC CONST CHAR16 gAppName[] = L"gpt";
> > > +EFI_HANDLE gShellGptHiiHandle = NULL;
> > > +
> > > +STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
> > > + // Partition-related operations
> > > + { L"clear", TypeFlag }, // Clears all partitions
> > > + { L"create", TypeFlag }, // Creates a partition
> > > + { L"delete", TypeFlag }, // Deletes a partition
> > > + { L"list", TypeFlag }, // Lists all partitions
> > > + { L"rename", TypeFlag }, // Renames a partition
> > > + { L"setattr", TypeFlag }, // Set attributes for a partition in partition
> > > table
> > > + { L"settype", TypeFlag },
> > > + { L"sync", TypeFlag }, // Synchronizes either master or
> > alternative
> > > partition table
> > > + { L"typesinfo", TypeFlag }, // Verifies correctness of master and
> > > alternative partition tables
> > > + // BlockIo-related operations
> > > + { L"read", TypeFlag }, // Reads n bytes into memory address
> > from
> > > a partition starting from a certain lba
> > > + { L"readfile", TypeFlag }, // Same as above, but instead of store it
> > in
> > > memory saves into a file system
> > > + { L"write", TypeFlag }, // Writes n bytes from memory into a
> > > partition starting from a certain lba
> > > + { L"writefile", TypeFlag }, // Same as above, but instead of getting
> > > data from memory reads a file
> > > + { L"info", TypeFlag }, // Get information on a certain partition
> > > (startLba, lastLba, attributes)
> > > + { L"fatformat", TypeFlag }, // FAT format of a partition
> > > + { L"-type", TypeValue },
> > > + { L"-yes", TypeFlag },
> > > + { L"-verbose", TypeFlag },
> > > + { NULL, TypeMax }
> > > +};
> > > +
> > > +typedef enum {
> > > + // Not requires presence
> > > + CLEAR = BIT0,
> > > + CREATE = BIT1,
> > > + LIST = BIT2,
> > > + SYNC = BIT3,
> > > + TYPES_INFO = BIT4,
> > > +
> > > + // Requires presence
> > > + DELETE = BIT5,
> > > + INFO = BIT6,
> > > + READ = BIT7,
> > > + READ_FILE = BIT8,
> > > + RENAME = BIT9,
> > > + SETATTR = BIT10,
> > > + SETTYPE = BIT11,
> > > + WRITE = BIT12,
> > > + WRITE_FILE = BIT13,
> > > + FAT_FORMAT = BIT14,
> > > +} Flags;
> > > +
> > > +/**
> > > + Return the file name of the help text file if not using HII.
> > > +
> > > + @return The string pointer to the file name.
> > > +**/
> > > +CONST CHAR16 *
> > > +EFIAPI
> > > +ShellCommandGetManFileNameGpt (
> > > + VOID
> > > + )
> > > +{
> > > +
> > > + return gShellGptFileName;
> > > +}
> > > +
> > > +STATIC
> > > +EFI_STATUS
> > > +OpenAndPrepareFile (
> > > + IN CHAR16 *FilePath,
> > > + OUT SHELL_FILE_HANDLE *FileHandle,
> > > + IN BOOLEAN WriteNeeded
> > > + )
> > > +{
> > > + EFI_STATUS Status;
> > > + UINT64 OpenMode;
> > > +
> > > + OpenMode = EFI_FILE_MODE_READ;
> > > +
> > > + if (WriteNeeded) {
> > > + OpenMode |= EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE;
> > > + }
> > > +
> > > + Status = ShellOpenFileByName (FilePath, FileHandle, OpenMode, 0);
> > > + if (EFI_ERROR (Status)) {
> > > + ShellPrintHiiEx (-1, -1,
> > > + NULL, STRING_TOKEN (STR_GPT_ERROR),
> > > + gShellGptHiiHandle,
> > > + gAppName,
> > > + Status,
> > > + L"Cannot open file"
> > > + );
> > > + return Status;
> > > + }
> > > +
> > > + Status = FileHandleSetPosition (*FileHandle, 0);
> > > +
> > > + if (EFI_ERROR (Status)) {
> > > + ShellPrintHiiEx (-1, -1,
> > > + NULL, STRING_TOKEN (STR_GPT_ERROR),
> > > + gShellGptHiiHandle,
> > > + gAppName,
> > > + Status,
> > > + "Cannot set file position to the first byte"
> > > + );
> > > +
> > > + ShellCloseFile (FileHandle);
> > > + return Status;
> > > + }
> > > +
> > > + return EFI_SUCCESS;
> > > +}
> > > +
> > > +VOID
> > > +PrintErr (
> > > + IN CONST CHAR16 *Message,
> > > + IN EFI_STATUS Status
> > > + )
> > > +{
> > > + ShellPrintHiiEx (-1, -1,
> > > + NULL, STRING_TOKEN (STR_GPT_ERROR),
> > > + gShellGptHiiHandle,
> > > + gAppName,
> > > + Status,
> > > + Message
> > > + );
> > > +}
> > > +
> > > +STATIC
> > > +BOOLEAN
> > > +IsPartitionableDevicePath (
> > > + IN EFI_DEVICE_PATH *DevicePath
> > > + )
> > > +{
> > > + UINTN PathSize;
> > > + EFI_DEVICE_PATH *PathInstance;
> > > + BOOLEAN Partitionable;
> > > +
> > > + Partitionable = TRUE;
> > > + while (DevicePath != NULL) {
> > > + PathInstance = GetNextDevicePathInstance (&DevicePath, &PathSize);
> > > +
> > > + while (!IsDevicePathEnd (PathInstance)) {
> > > + if ((DevicePathType (PathInstance) == MEDIA_DEVICE_PATH)) {
> > > + Partitionable = FALSE;
> > > + }
> > > +
> > > + PathInstance = NextDevicePathNode (PathInstance);
> > > + }
> > > + }
> > > + return Partitionable;
> > > +}
> > > +
> > > +STATIC
> > > +EFI_STATUS
> > > +GptPromptYesNo (
> > > + IN CONST EFI_STRING_ID HiiFormatStringId
> > > + )
> > > +{
> > > + EFI_STATUS Status;
> > > + VOID *Response;
> > > +
> > > + Status = ShellPromptForResponseHii (ShellPromptResponseTypeYesNo,
> > > HiiFormatStringId, gShellGptHiiHandle, &Response);
> > > + if ((EFI_ERROR (Status)) || (*(SHELL_PROMPT_RESPONSE
> > *)Response) !=
> > > ShellPromptResponseYes) {
> > > + return EFI_ABORTED;
> > > + }
> > > +
> > > + return EFI_SUCCESS;
> > > +}
> > > +
> > > +STATIC
> > > +VOID FormatSize(
> > > + UINT64 Size, CHAR16 *Buffer)
> > > +{
> > > +#define MAX_SIZE_BUF_SIZE 32
> > > + UINT64 Base, Frac;
> > > + CHAR16 Metric;
> > > +
> > > + Metric = L'B';
> > > + Frac = 0;
> > > + if (Size < SIZE_1KB) {
> > > + Base = Size;
> > > + } else if (Size < SIZE_1MB) {
> > > + Base = Size / SIZE_1KB;
> > > + Frac = ((Size % SIZE_1KB) * 10) >> 10;
> > > + Metric = L'K';
> > > + } else if (Size < SIZE_1GB) {
> > > + Base = Size / SIZE_1MB;
> > > + Frac = ((Size % SIZE_1MB) * 10) >> 20;
> > > + Metric = L'M';
> > > + } else if (Size < SIZE_1TB) {
> > > + Base = Size / SIZE_1GB;
> > > + Frac = ((Size % SIZE_1GB) * 10) >> 30;
> > > + Metric = L'G';
> > > + } else {
> > > + Base = Size / SIZE_1TB;
> > > + Frac = ((Size % SIZE_1TB) * 10) >> 40;
> > > + Metric = L'T';
> > > + }
> > > + if (Frac) {
> > > + UnicodeSPrint (Buffer, MAX_SIZE_BUF_SIZE, L"%d.%d%c", Base, Frac,
> > > Metric);
> > > + } else {
> > > + UnicodeSPrint (Buffer, MAX_SIZE_BUF_SIZE, L"%d%c", Base, Metric);
> > > + }
> > > +}
> > > +
> > > +STATIC
> > > +EFI_STATUS
> > > +FindAndPrintPartitionableDevices (VOID)
> > > +{
> > > + UINTN Index;
> > > + EFI_HANDLE *HandlePointer;
> > > + UINTN HandleCount;
> > > + UINTN DevCount;
> > > + EFI_STATUS Status;
> > > + BOOLEAN FirstTime;
> > > +
> > > + Status = gBS->LocateHandleBuffer (ByProtocol,
> > &gEfiBlockIoProtocolGuid,
> > > NULL, &HandleCount, &HandlePointer);
> > > + if (EFI_ERROR (Status)) {
> > > + return Status;
> > > + }
> > > +
> > > + DevCount = 0;
> > > + FirstTime = TRUE;
> > > +
> > > + for (Index = 0; Index < HandleCount; Index++) {
> > > + EFI_DEVICE_PATH *DevicePath;
> > > + CONST CHAR16 *MapPath;
> > > + CHAR16 *Match;
> > > + EFI_BLOCK_IO *BlkIo;
> > > + EFI_DISK_IO *DiskIo;
> > > + CHAR16 *BufferForSize;
> > > +
> > > + Status = gBS->HandleProtocol (HandlePointer[Index],
> > > &gEfiBlockIoProtocolGuid, (VOID **)&BlkIo);
> > > + if (EFI_ERROR (Status)) {
> > > + continue;
> > > + }
> > > +
> > > + DevicePath = DevicePathFromHandle (HandlePointer[Index]);
> > > + if (!IsPartitionableDevicePath (DevicePath)) {
> > > + continue;
> > > + }
> > > + MapPath = gEfiShellProtocol->GetMapFromDevicePath (&DevicePath);
> > > + if (MapPath == NULL) {
> > > + continue;
> > > + }
> > > +
> > > + Status = gBS->HandleProtocol (HandlePointer[Index],
> > > &gEfiDiskIoProtocolGuid, (VOID **)&DiskIo);
> > > + if (EFI_ERROR (Status)) {
> > > + continue;
> > > + }
> > > +
> > > + Match = StrStr (MapPath, L";BLK");
> > > + if (Match) {
> > > + MapPath = Match;
> > > + MapPath++;
> > > + }
> > > +
> > > + if (FirstTime) {
> > > + BufferForSize = AllocateZeroPool (MAX_SIZE_BUF_SIZE * sizeof
> > > (CHAR16));
> > > + ASSERT (BufferForSize);
> > > + Print (L" Device\t Size Comments\n");
> > > + Print (L" ------ ------- ------------------------------------------------------------
> > > \n");
> > > + FirstTime = FALSE;
> > > + }
> > > + GptCleanupGlobals ();
> > > + FormatSize (MultU64x32 (BlkIo->Media->LastBlock + 1, BlkIo->Media-
> > > >BlockSize), BufferForSize);
> > > + ShellPrintHiiEx (-1, -1,
> > > + NULL, STRING_TOKEN (STR_GPT_LIST_DEVS),
> > > + gShellGptHiiHandle,
> > > + MapPath,
> > > + BufferForSize);
> > > + if (BlkIo->Media->ReadOnly) {
> > > + Print (L"Read-Only! ");
> > > + }
> > > + if (!BlkIo->Media->MediaPresent) {
> > > + Print (L"No Media! ");
> > > + }
> > > + if (!EFI_ERROR (PartitionGetGptTables (DiskIo, BlkIo))) {
> > > + Print (L"Valid GPT. ");
> > > + }
> > > + if (BlkIo->Media->RemovableMedia) {
> > > + Print (L"Removable device.");
> > > + }
> > > + Print (L"\n");
> > > + DevCount++;
> > > + }
> > > + Print (L"\r\n");
> > > + if (DevCount) {
> > > + Print (L"%d potentially partitionable device(s) found\n", DevCount);
> > > + } else {
> > > + Print (L"No potentially partitionable device(s) found\n");
> > > + }
> > > +
> > > + GptCleanupGlobals ();
> > > + return EFI_SUCCESS;
> > > +}
> > > +
> > > +SHELL_STATUS
> > > +EFIAPI
> > > +ShellCommandRunGpt (
> > > + IN EFI_HANDLE ImageHandle,
> > > + IN EFI_SYSTEM_TABLE *SystemTable
> > > + )
> > > +{
> > > + EFI_STATUS Status;
> > > + LIST_ENTRY *CheckPackage;
> > > + EFI_PHYSICAL_ADDRESS Address = 0, Offset = 0;
> > > + UINT64 PartAttributes = 0;
> > > + EFI_GUID PartTypeGuid = { 0 };
> > > + SHELL_FILE_HANDLE FileHandle = NULL;
> > > + UINT64 ByteCount, FileSize;
> > > + UINTN I;
> > > + UINT8 *Buffer = NULL, *FileBuffer = NULL;
> > > +
> > > + CHAR16 * ProblemParam,*FilePath;
> > > + CONST CHAR16 *AddressStr = NULL, *OffsetStr = NULL;
> > > + CONST CHAR16 *PartName = NULL, *NewPartName = NULL,
> > > *AttrStr = NULL,
> > > + *GuidStr = NULL, *VolumeName = NULL;
> > > + CONST CHAR16 *LengthStr = NULL, *FileStr = NULL;
> > > + BOOLEAN AddrFlag = FALSE, LengthFlag = TRUE, FileFlag =
> FALSE,
> > > GuidFlag = FALSE, OffsetFlag = TRUE;
> > > + BOOLEAN PartNameFlag = TRUE, NewPartNameFlag = FALSE,
> > > AttrFlag = FALSE;
> > > + UINTN Flag = 0, CheckFlag = 0;
> > > + CONST CHAR16 *BlockName;
> > > + EFI_DEVICE_PATH_PROTOCOL *DevPath;
> > > + EFI_BLOCK_IO_PROTOCOL *BlockIo;
> > > + EFI_DISK_IO_PROTOCOL *DiskIo;
> > > + EFI_HANDLE BlockIoHandle;
> > > + MOD_PARAMS ModParams;
> > > + EFI_PARTITION_ENTRY *Entry;
> > > + UINTN NumKnownPartTypesEntries;
> > > + BOOLEAN TableNotEmpty, NoPrompt = FALSE, Quiet = TRUE;
> > > + UINT64 TimeStampB, TimeStampE, SpeedKB, Freq;
> > > +
> > > + // Parse Shell command line
> > > + Status = ShellInitialize ();
> > > + if (EFI_ERROR (Status)) {
> > > + PrintErr (L"Cannot initialize Shell", Status);
> > > + ASSERT_EFI_ERROR (Status);
> > > + return SHELL_ABORTED;
> > > + }
> > > +
> > > + Status = ShellCommandLineParse (ParamList, &CheckPackage,
> > > &ProblemParam, TRUE);
> > > + if (EFI_ERROR (Status)) {
> > > + PrintErr (L"Error while parsing command line", Status);
> > > + return SHELL_ABORTED;
> > > + }
> > > +
> > > + TimeStampB = 0;
> > > + TimeStampE = 0;
> > > +
> > > + NoPrompt = ShellCommandLineGetFlag (CheckPackage, L"-yes");
> > > + Quiet = !ShellCommandLineGetFlag (CheckPackage, L"-verbose");
> > > +
> > > + Freq = GetPerformanceCounterProperties (NULL, NULL);
> > > +
> > > + // Check flags provided by user
> > > + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"clear") << 0);
> > > + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"create") << 1);
> > > + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"list") << 2);
> > > + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"sync") << 3);
> > > + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"typesinfo") << 4);
> > > + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"delete") << 5);
> > > + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"info") << 6);
> > > + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"read") << 7);
> > > + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"readfile") << 8);
> > > + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"rename") << 9);
> > > + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"setattr") << 10);
> > > + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"settype") << 11);
> > > + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"write") << 12);
> > > + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"writefile") << 13);
> > > + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"fatformat") << 14);
> > > +
> > > + PartitionGetKnownType ((UINTN)(-1), &NumKnownPartTypesEntries);
> > > +
> > > + if (Flag & TYPES_INFO) {
> > > + UINTN Index;
> > > +
> > > + Print (L" No\t%-36s\tGUID\r\n", L"Type name");
> > > + Print (L" ---- ---------------------------------- ----------------------------------
> > --
> > > \n");
> > > + for (Index = 0; Index < NumKnownPartTypesEntries; Index++) {
> > > + EFI_KNOWN_PARTITION_TYPE *PartType;
> > > +
> > > + PartType = PartitionGetKnownType (Index, NULL);
> > > + if (PartType == NULL) {
> > > + break;
> > > + }
> > > + Print (L" %3d\t%-36s\t%g\n", Index, PartType->TypeName,
> > &PartType-
> > > >TypeGuid);
> > > + }
> > > + if (Flag == TYPES_INFO) {
> > > + return SHELL_SUCCESS;
> > > + }
> > > + }
> > > + // Start parsing the command.
> > > + // Generally command is:
> > > + // block_name:bootpart_no addr or filename offset
> > > +
> > > + BlockName = ShellCommandLineGetRawValue (CheckPackage, 1);
> > > + if (BlockName == NULL) {
> > > + if (Flag & LIST) {
> > > + Status = FindAndPrintPartitionableDevices ();
> > > + if (EFI_ERROR (Status)) {
> > > + PrintErr (L"Error getting list of partitionable devices", Status);
> > > + Status = SHELL_ABORTED;
> > > + }
> > > + return Status;
> > > + }
> > > + PrintErr (L"Missing block device name", EFI_INVALID_PARAMETER);
> > > + return SHELL_INVALID_PARAMETER;
> > > + }
> > > +
> > > + // Find device handle by mapped name
> > > + if (gEfiShellProtocol->GetDevicePathFromMap (BlockName) == NULL) {
> > > + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
> > > gShellGptHiiHandle, gAppName, BlockName);
> > > + Status = SHELL_INVALID_PARAMETER;
> > > + } else {
> > > + DevPath = (EFI_DEVICE_PATH_PROTOCOL *)gEfiShellProtocol-
> > > >GetDevicePathFromMap (BlockName);
> > > + if (gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &DevPath, NULL)
> > > == EFI_NOT_FOUND) {
> > > + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN
> > > (STR_GEN_MAP_PROTOCOL), gShellGptHiiHandle, gAppName, BlockName,
> > > L"BlockIo");
> > > + Status = SHELL_INVALID_PARAMETER;
> > > + }
> > > + }
> > > +
> > > + if (Status) {
> > > + return SHELL_INVALID_PARAMETER;
> > > + }
> > > +
> > > + BlockIoHandle = 0;
> > > +
> > > + Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid,
> > > (EFI_DEVICE_PATH_PROTOCOL **)&DevPath, &BlockIoHandle);
> > > + if (EFI_ERROR (Status)) {
> > > + goto CleanUp;
> > > + }
> > > +
> > > + Status = gBS->OpenProtocol (BlockIoHandle, &gEfiBlockIoProtocolGuid,
> > > (VOID **)&BlockIo, gImageHandle, NULL,
> > > EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> > > + if (EFI_ERROR (Status)) {
> > > + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN
> > > (STR_GEN_MAP_PROTOCOL), gShellGptHiiHandle, gAppName, BlockName,
> > > L"BlockIo");
> > > + goto CleanUp;
> > > + }
> > > +
> > > + Status = gBS->HandleProtocol (
> > > + BlockIoHandle,
> > > + &gEfiDiskIoProtocolGuid,
> > > + (VOID **)&DiskIo
> > > + );
> > > + if (EFI_ERROR (Status)) {
> > > + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN
> > > (STR_GEN_MAP_PROTOCOL), gShellGptHiiHandle, gAppName, BlockName,
> > > L"DiskIo");
> > > + goto CleanUp;
> > > + }
> > > +
> > > + CheckFlag = Flag;
> > > + for (I = 0; CheckFlag; CheckFlag >>= 1) {
> > > + I += CheckFlag & 1;
> > > + if (I > 1) {
> > > + PrintErr (L"Too many flags", EFI_INVALID_PARAMETER);
> > > + Status = SHELL_INVALID_PARAMETER;
> > > + goto CleanUp;
> > > + }
> > > + }
> > > +
> > > + if (Flag & SYNC) {
> > > + // Let the Partition table driver know that
> > > + // we want to reread the tables
> > > + Status = gBS->ReinstallProtocolInterface (
> > > + BlockIoHandle,
> > > + &gEfiBlockIoProtocolGuid,
> > > + BlockIo,
> > > + BlockIo
> > > + );
> > > + Status = SHELL_SUCCESS;
> > > + goto CleanUp;
> > > + }
> > > +
> > > + if (!IsPartitionableDevicePath (DevicePathFromHandle (BlockIoHandle)))
> > {
> > > + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
> > > gShellGptHiiHandle, gAppName, BlockName);
> > > + Print (L"%s is not a raw block device\n", BlockName);
> > > + Status = SHELL_INVALID_PARAMETER;
> > > + goto CleanUp;
> > > + }
> > > +
> > > + if (!BlockIo->Media->MediaPresent) {
> > > + PrintErr (L"Media is not present!\n", EFI_NO_MEDIA);
> > > + Status = EFI_NO_MEDIA;
> > > + goto CleanUp;
> > > + }
> > > +
> > > + // Preload GPT tables with validation
> > > + Status = PartitionGetGptTables (DiskIo, BlockIo);
> > > + if (EFI_ERROR (Status)) {
> > > + BOOLEAN CanContinue;
> > > +
> > > + CanContinue = (Flag & CREATE) || (Flag & CLEAR) || (Flag &
> > > FAT_FORMAT);
> > > + if (Status != EFI_NOT_FOUND) {
> > > + PrintErr (L"Unexpected error getting GPT tables", Status);
> > > + goto CleanUp;
> > > + } else {
> > > + if (!CanContinue) {
> > > + PrintErr (L"No GPT table found. Create first", Status);
> > > + goto CleanUp;
> > > + }
> > > + }
> > > + }
> > > +
> > > + // Do we have any partitions already?
> > > + TableNotEmpty = (PartitionFindPartitionByCriteria (NULL, 0, 0,
> > SRC_ANY) !=
> > > NULL);
> > > +
> > > + Status = SHELL_INVALID_PARAMETER;
> > > +
> > > + if ((Flag < LIST) ||
> > > + (Flag & DELETE) ||
> > > + (Flag > READ_FILE)
> > > + ) {
> > > + if (BlockIo->Media->ReadOnly) {
> > > + Status = EFI_INVALID_PARAMETER;
> > > + PrintErr (L"Cannot write to a read-only device", Status);
> > > + goto CleanUp;
> > > + }
> > > + }
> > > +
> > > + if (BlockIo->Media->RemovableMedia) {
> > > + Print (L"%s is a removable device. Just a note\n", BlockName);
> > > + }
> > > +
> > > + switch (Flag) {
> > > + case INFO:
> > > + PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
> > > + OffsetFlag = FALSE;
> > > + LengthFlag = FALSE;
> > > + break;
> > > + case LIST:
> > > + {
> > > + UINTN NumEntries;
> > > +
> > > + NumEntries = PartitionListGptEntries ();
> > > + if (NumEntries == 0) {
> > > + Print (L"gpt: GPT is valid on %s, but no partition(s) defined yet. Use
> > > create\n", BlockName);
> > > + }
> > > + Status = SHELL_SUCCESS;
> > > + goto CleanUp;
> > > + break;
> > > + }
> > > + case CLEAR:
> > > + if (TableNotEmpty) {
> > > + // Tell the user what he/she is doing...
> > > + ShellPrintHiiEx (-1, -1,
> > > + NULL, STRING_TOKEN (STR_GPT_NOT_EMPTY),
> > > + gShellGptHiiHandle,
> > > + BlockName
> > > + );
> > > + }
> > > +
> > > + // Even if GPT tables do not exist, there might be something.
> > > + // Warn the user and double sure it is the intention,
> > > + // to prevent a user from bricking a device (JTAG would be needed to
> > > recover)
> > > + // by overwriting an ATF boot device. However with NoPrompt on, the
> > > user is
> > > + // responsible for operation because there is no confirmation
> > (assuming
> > > yes on all queries).
> > > + if ((NoPrompt) || (!GptPromptYesNo (STRING_TOKEN
> > > (STR_GPT_CLEAR_SURE)) &&
> > > + (!GptPromptYesNo (STRING_TOKEN
> > > (STR_GPT_ABSOLUTELY_SURE))))
> > > + ) {
> > > + PartitionGptClearAll ();
> > > + }
> > > + Status = SHELL_SUCCESS;
> > > + goto CleanUp;
> > > + break;
> > > + case CREATE:
> > > + PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
> > > + OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 3);
> > > + LengthStr = ShellCommandLineGetRawValue (CheckPackage, 4);
> > > + AttrStr = ShellCommandLineGetRawValue (CheckPackage, 5);
> > > + GuidStr = ShellCommandLineGetValue (CheckPackage, L"-type");
> > > + GuidFlag = TRUE;
> > > + break;
> > > + case DELETE:
> > > + PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
> > > + LengthFlag = FALSE;
> > > + OffsetFlag = FALSE;
> > > + break;
> > > + case RENAME:
> > > + PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
> > > + NewPartName = ShellCommandLineGetRawValue (CheckPackage, 3);
> > > + NewPartNameFlag = TRUE;
> > > + LengthFlag = FALSE;
> > > + OffsetFlag = FALSE;
> > > + break;
> > > + case SETATTR:
> > > + PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
> > > + AttrStr = ShellCommandLineGetRawValue (CheckPackage, 3);
> > > + AttrFlag = TRUE;
> > > + LengthFlag = FALSE;
> > > + OffsetFlag = FALSE;
> > > + break;
> > > + case SETTYPE:
> > > + PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
> > > + GuidStr = ShellCommandLineGetValue (CheckPackage, L"-type");
> > > + GuidFlag = TRUE;
> > > + LengthFlag = FALSE;
> > > + OffsetFlag = FALSE;
> > > + break;
> > > + case FAT_FORMAT:
> > > + PartName = ShellCommandLineGetRawValue (CheckPackage, 2);
> > > + VolumeName = ShellCommandLineGetRawValue (CheckPackage, 3);
> > > + LengthFlag = FALSE;
> > > + OffsetFlag = FALSE;
> > > + PartNameFlag = (PartName != NULL);
> > > + if (!PartNameFlag && TableNotEmpty) {
> > > + // Tell the user what he/she is doing...
> > > + ShellPrintHiiEx (-1, -1,
> > > + NULL, STRING_TOKEN (STR_GPT_NOT_EMPTY),
> > > + gShellGptHiiHandle,
> > > + BlockName
> > > + );
> > > + }
> > > + break;
> > > + // Fall through
> > > + case READ:
> > > + case WRITE:
> > > + AddressStr = ShellCommandLineGetRawValue (CheckPackage, 2);
> > > + PartName = ShellCommandLineGetRawValue (CheckPackage, 3);
> > > + OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 4);
> > > + LengthStr = ShellCommandLineGetRawValue (CheckPackage, 5);
> > > + AddrFlag = TRUE;
> > > + break;
> > > + case READ_FILE:
> > > + FileStr = ShellCommandLineGetRawValue (CheckPackage, 2);
> > > + PartName = ShellCommandLineGetRawValue (CheckPackage, 3);
> > > + OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 4);
> > > + LengthStr = ShellCommandLineGetRawValue (CheckPackage, 5);
> > > + FileFlag = TRUE;
> > > + break;
> > > + case WRITE_FILE:
> > > + FileStr = ShellCommandLineGetRawValue (CheckPackage, 2);
> > > + PartName = ShellCommandLineGetRawValue (CheckPackage, 3);
> > > + OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 4);
> > > + LengthFlag = FALSE;
> > > + FileFlag = TRUE;
> > > + break;
> > > + default:
> > > + Print (L"%s: Unsupported command. Try \"help %s\"", gAppName);
> > > + Status = SHELL_INVALID_PARAMETER;
> > > + goto CleanUp;
> > > + }
> > > +
> > > + // Read address parameter
> > > + if ((AddressStr == NULL) & AddrFlag) {
> > > + PrintErr (L"No address parameter", EFI_INVALID_PARAMETER);
> > > + goto CleanUp;
> > > + } else if (AddrFlag) {
> > > + Address = ShellHexStrToUintn (AddressStr);
> > > + if (Address == (UINTN)(-1)) {
> > > + PrintErr (L"Wrong address parameter", EFI_INVALID_PARAMETER);
> > > + goto CleanUp;
> > > + }
> > > + }
> > > +
> > > + if ((PartName == NULL) & PartNameFlag) {
> > > + PrintErr (L"Missing partition name", EFI_INVALID_PARAMETER);
> > > + goto CleanUp;
> > > + } else if (PartNameFlag) {
> > > + if (StrSize (PartName) > MAX_PARTITION_NAME_LENGTH) {
> > > + PrintErr (L"Partition name is too long (max 36 chars)",
> > > EFI_INVALID_PARAMETER);
> > > + goto CleanUp;
> > > + }
> > > + }
> > > +
> > > + // Read offset parameter
> > > + if ((OffsetStr == NULL) & OffsetFlag) {
> > > + PrintErr (L"No offset Parameter", EFI_INVALID_PARAMETER);
> > > + goto CleanUp;
> > > + } else if (OffsetFlag) {
> > > + Offset = ShellHexStrToUintn (OffsetStr);
> > > + if (Offset < 0) {
> > > + Print (L"%s: Wrong offset parameter: %s\n", gAppName, OffsetStr);
> > > + goto CleanUp;
> > > + }
> > > + }
> > > +
> > > + // Read length parameter
> > > + if ((LengthStr == NULL) & LengthFlag) {
> > > + PrintErr (L"No length parameter", EFI_INVALID_PARAMETER);
> > > + goto CleanUp;
> > > + } else if (LengthFlag) {
> > > + ByteCount = (UINT64)ShellStrToUintn (LengthStr);
> > > + if (ByteCount < 0) {
> > > + Print (L"%s: Wrong length parameter %s!\n", gAppName, LengthStr);
> > > + goto CleanUp;
> > > + }
> > > + }
> > > +
> > > + if ((NewPartName == NULL) & NewPartNameFlag) {
> > > + PrintErr (L"Missing name to be assigned to partition",
> > > EFI_INVALID_PARAMETER);
> > > + goto CleanUp;
> > > + } else if (NewPartNameFlag) {
> > > + if (StrSize (NewPartName) > MAX_PARTITION_NAME_LENGTH) {
> > > + PrintErr (L"Partition name is too long (max 36 chars)",
> > > EFI_INVALID_PARAMETER);
> > > + goto CleanUp;
> > > + }
> > > + }
> > > +
> > > + if ((AttrStr == NULL) & AttrFlag) {
> > > + PrintErr (L"Missing attributes parameter", EFI_INVALID_PARAMETER);
> > > + goto CleanUp;
> > > + } else if (AttrStr) {
> > > + PartAttributes = (UINT64)ShellStrToUintn (AttrStr);
> > > + }
> > > +
> > > + if ((GuidStr == NULL) & GuidFlag) {
> > > + PrintErr (L"Missing partition type GUID parameter",
> > > EFI_INVALID_PARAMETER);
> > > + goto CleanUp;
> > > + } else if (GuidFlag) {
> > > + Status = SHELL_INVALID_PARAMETER;
> > > + if (InternalShellIsHexOrDecimalNumber (GuidStr, FALSE, TRUE, FALSE)) {
> > > + UINTN Ordinal;
> > > +
> > > + Ordinal = ShellStrToUintn (GuidStr);
> > > + if (Ordinal < NumKnownPartTypesEntries) {
> > > + PartTypeGuid = PartitionGetKnownType (Ordinal, NULL)->TypeGuid;
> > > + Status = SHELL_SUCCESS;
> > > + } else {
> > > + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
> > > gShellGptHiiHandle, gAppName, GuidStr);
> > > + goto CleanUp;
> > > + }
> > > + } else {
> > > + Status = ConvertStringToGuid (GuidStr, &PartTypeGuid);
> > > + if ((EFI_ERROR (Status)) || (IsZeroGuid (&PartTypeGuid))) {
> > > + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
> > > gShellGptHiiHandle, gAppName, GuidStr);
> > > + Status = SHELL_INVALID_PARAMETER;
> > > + goto CleanUp;
> > > + }
> > > + }
> > > + }
> > > +
> > > + if (FileFlag) {
> > > + // Read FilePath parameter
> > > + if (FileStr == NULL) {
> > > + PrintErr (L"No FilePath parameter", EFI_INVALID_PARAMETER);
> > > + goto CleanUp;
> > > + } else {
> > > + FilePath = (CHAR16 *)FileStr;
> > > + Status = ShellIsFile (FilePath);
> > > + // When read file into flash, file doesn't have to exist
> > > + if (EFI_ERROR (Status && !(Flag & READ_FILE))) {
> > > + PrintErr (L"Wrong FilePath parameter", Status);
> > > + Status = SHELL_INVALID_PARAMETER;
> > > + goto CleanUp;
> > > + }
> > > + }
> > > +
> > > + Status = OpenAndPrepareFile (FilePath, &FileHandle, ((Flag &
> > > READ_FILE) != 0));
> > > + if (EFI_ERROR (Status)) {
> > > + Print (L"Error %r while preparing file %s", Status, FilePath);
> > > + Status = SHELL_ABORTED;
> > > + goto CleanUp;
> > > + }
> > > +
> > > + // Get file size in order to check correctness at the end of transfer
> > > + if (Flag & (WRITE_FILE)) {
> > > + Status = FileHandleGetSize (FileHandle, &FileSize);
> > > + if (EFI_ERROR (Status)) {
> > > + PrintErr (L"Cannot get file size", Status);
> > > + Status = SHELL_ABORTED;
> > > + goto CleanUp;
> > > + }
> > > + ByteCount = (UINT64)FileSize;
> > > + }
> > > +
> > > + FileBuffer = AllocateZeroPool ((UINTN)ByteCount);
> > > + if (FileBuffer == NULL) {
> > > + PrintErr (L"Cannot allocate memory", EFI_OUT_OF_RESOURCES);
> > > + Status = SHELL_OUT_OF_RESOURCES;
> > > + goto Error_Close_File;
> > > + }
> > > +
> > > + // Read file content and store it in FileBuffer
> > > + if (Flag & (WRITE_FILE)) {
> > > + if (!Quiet) {
> > > + Print (L"Reading %s...\r", FilePath);
> > > + }
> > > + Status = FileHandleRead (FileHandle, &ByteCount, FileBuffer);
> > > + if (EFI_ERROR (Status)) {
> > > + PrintErr (L"Read from file error", Status);
> > > + Status = SHELL_ABORTED;
> > > + goto Error_Free_Buffer;
> > > + } else if (ByteCount != (UINTN)FileSize) {
> > > + PrintErr (L"Not whole file read. Abort", EFI_DEVICE_ERROR);
> > > + Status = SHELL_DEVICE_ERROR;
> > > + goto Error_Free_Buffer;
> > > + }
> > > + if (!Quiet) {
> > > + Print (L"Writing %s into device %s, partition %s...\n", FilePath,
> > > BlockName, PartName);
> > > + }
> > > + }
> > > + }
> > > +
> > > + Buffer = (UINT8 *)Address;
> > > + if (FileFlag) {
> > > + Buffer = FileBuffer;
> > > + }
> > > +
> > > + if (Flag > TYPES_INFO) {
> > > + Entry = PartitionFindPartitionByCriteria (PartName, 0, 0, SRC_BY_NAME);
> > > + if (!Entry && PartName && (InternalShellIsHexOrDecimalNumber
> > > (PartName, FALSE, TRUE, FALSE))) {
> > > + Entry = PartitionFindPartitionByCriteria (PartName, 0, 0, SRC_BY_NUM);
> > > + }
> > > + if ((!Entry) && (PartNameFlag)) {
> > > + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
> > > gShellGptHiiHandle, gAppName, PartName);
> > > + Print (L"Could not find partition %s (case-sensitive). Make sure the
> > name
> > > is spelled properly\n", PartName);
> > > + Status = SHELL_NOT_FOUND;
> > > + goto CleanUp;
> > > + }
> > > + }
> > > +
> > > + switch (Flag) {
> > > + case CREATE:
> > > + PartitionGptCreatePartition (
> > > + PartName,
> > > + Offset, // Lba. If 0, the next available is assumed
> > > + ByteCount, // in MegaBytes. If 0 the whole remaining space is
> > assumed
> > > + PartAttributes,
> > > + PartTypeGuid);
> > > + break;
> > > + case DELETE:
> > > + ModParams.PartName = PartName;
> > > + ShellPrintHiiEx (-1, -1,
> > > + NULL, STRING_TOKEN (STR_GPT_DELETE_WARNING),
> > > + gShellGptHiiHandle,
> > > + Entry->PartitionName
> > > + );
> > > + if ((NoPrompt) || (!GptPromptYesNo (STRING_TOKEN
> > > (STR_GPT_ABSOLUTELY_SURE)))) {
> > > + Status = PartitionGptModifyPartition (
> > > + Entry, &ModParams, MOD_DELETE);
> > > + if (EFI_ERROR (Status)) {
> > > + PrintErr (L"Error deleting the partition", Status);
> > > + Status = SHELL_ABORTED;
> > > + goto CleanUp;
> > > + }
> > > + Status = SHELL_SUCCESS;
> > > + } else {
> > > + Status = SHELL_ABORTED;
> > > + }
> > > + break;
> > > + case FAT_FORMAT:
> > > + {
> > > + EFI_LBA StartingLBA, EndingLBA;
> > > + CHAR8 LabelName[12];
> > > +
> > > + if (VolumeName) {
> > > + if (StrLen (VolumeName) > 11) {
> > > + Status = EFI_INVALID_PARAMETER;
> > > + PrintErr (L"The volume label is too long", Status);
> > > + Status = SHELL_INVALID_PARAMETER;
> > > + goto CleanUp;
> > > + }
> > > + UnicodeStrToAsciiStr (VolumeName, (CHAR8 *)LabelName);
> > > + }
> > > + ShellPrintHiiEx (-1, -1,
> > > + NULL, STRING_TOKEN (STR_GPT_FORMAT_WARNING),
> > > + gShellGptHiiHandle,
> > > + Entry ? Entry->PartitionName : BlockName
> > > + );
> > > +
> > > + if ((NoPrompt) || (!GptPromptYesNo (STRING_TOKEN
> > > (STR_GPT_FORMAT_SURE)) &&
> > > + (!GptPromptYesNo (STRING_TOKEN
> > > (STR_GPT_ABSOLUTELY_SURE))))
> > > + ) {
> > > + StartingLBA = 0;
> > > + EndingLBA = BlockIo->Media->LastBlock;
> > > + if (Entry) {
> > > + StartingLBA = Entry->StartingLBA;
> > > + EndingLBA = Entry->EndingLBA;
> > > + }
> > > + if (!Quiet) {
> > > + Print (L"Formatting %s to FAT32...\r", PartNameFlag ? Entry-
> > > >PartitionName : BlockName);
> > > + }
> > > + Status = FatFormat (StartingLBA, EndingLBA, BlockIo, DiskIo,
> > > VolumeName ? LabelName : NULL, TRUE);
> > > + if (EFI_ERROR (Status)) {
> > > + PrintErr (L"Error formatting the partition to FAT ", Status);
> > > + Status = SHELL_ABORTED;
> > > + goto CleanUp;
> > > + } else if (!Quiet) {
> > > + Print (L"%s successfully formatted to FAT. Formatted size %llu
> > MiB\n",
> > > + PartNameFlag ? Entry->PartitionName : BlockName,
> > > + MultU64x32 (EndingLBA - StartingLBA + 1, BlockIo->Media-
> > > >BlockSize) >> 20
> > > + );
> > > + }
> > > + } else {
> > > + Status = SHELL_ABORTED;
> > > + }
> > > + }
> > > + break;
> > > + case RENAME:
> > > + ModParams.PartName = PartName;
> > > + ModParams.NewName = NewPartName;
> > > + Status = PartitionGptModifyPartition (
> > > + Entry, &ModParams, MOD_RENAME);
> > > + break;
> > > + case SETATTR:
> > > + ModParams.Attributes = PartAttributes;
> > > + Status = PartitionGptModifyPartition (
> > > + Entry, &ModParams, MOD_ATTR);
> > > + break;
> > > + case SETTYPE:
> > > + ModParams.PartTypeGuid = PartTypeGuid;
> > > + Status = PartitionGptModifyPartition (
> > > + Entry, &ModParams, MOD_TYPE);
> > > + break;
> > > + case INFO:
> > > + PartitionPrintGptPartInfo (Entry);
> > > + Status = SHELL_SUCCESS;
> > > + break;
> > > + case READ:
> > > + case READ_FILE:
> > > + case WRITE:
> > > + case WRITE_FILE:
> > > + {
> > > + UINT64 MaxBytes;
> > > + BOOLEAN OpRead;
> > > +
> > > + OpRead = ((Flag & READ) || (Flag & READ_FILE));
> > > + MaxBytes = MultU64x32 (
> > > + Entry->EndingLBA - Entry->StartingLBA,
> > > + BlockIo->Media->BlockSize) +
> > > + BlockIo->Media->BlockSize -
> > > + MultU64x32 (Offset, BlockIo->Media->BlockSize);
> > > + if (ByteCount > MaxBytes) {
> > > + Status = EFI_INVALID_PARAMETER;
> > > + ShellPrintHiiEx (-1, -1,
> > > + NULL, (OpRead) ?
> > > + STRING_TOKEN (STR_GPT_READ_BOUNDARY) :
> > > + STRING_TOKEN (STR_GPT_WRITE_BOUNDARY),
> > > + gShellGptHiiHandle,
> > > + gAppName,
> > > + Entry->PartitionName,
> > > + MaxBytes,
> > > + ByteCount
> > > + );
> > > + Status = SHELL_INVALID_PARAMETER;
> > > + goto CleanUp;
> > > + }
> > > +
> > > + TimeStampB = GetPerformanceCounter ();
> > > + if (OpRead) {
> > > + Status = DiskIo->ReadDisk (DiskIo,
> > > + BlockIo->Media->MediaId,
> > > + MultU64x32 (Offset + Entry->StartingLBA, BlockIo-
> > > >Media->BlockSize), ByteCount, Buffer);
> > > + } else {
> > > + Status = DiskIo->WriteDisk (DiskIo, BlockIo->Media->MediaId,
> > > + MultU64x32 (Offset + Entry->StartingLBA, BlockIo-
> > > >Media->BlockSize), ByteCount, Buffer);
> > > + }
> > > + }
> > > + break;
> > > + default:
> > > + Status = SHELL_INVALID_PARAMETER;
> > > + PrintErr (L"Unknown command. Try \"help gpt\"",
> > > EFI_INVALID_PARAMETER);
> > > + goto CleanUp;
> > > + }
> > > +
> > > + if (EFI_ERROR (Status)) {
> > > + PrintErr (L"Error while performing transfer\n", Status);
> > > + Status = SHELL_ABORTED;
> > > + goto CleanUp;
> > > + }
> > > +
> > > + TimeStampE = ((GetPerformanceCounter () - TimeStampB) * 1000) /
> > Freq;
> > > + SpeedKB = TimeStampE ? (ByteCount / (TimeStampE / 1000)) >> 10 : 0;
> > > +
> > > + switch (Flag) {
> > > + case WRITE:
> > > + case WRITE_FILE:
> > > + if (!Quiet) {
> > > + ShellPrintHiiEx (-1, -1,
> > > + NULL,
> > > + STRING_TOKEN (STR_GPT_WRITE_OK),
> > > + gShellGptHiiHandle,
> > > + ByteCount,
> > > + Offset,
> > > + Entry->PartitionName,
> > > + TimeStampE,
> > > + SpeedKB
> > > + );
> > > + }
> > > + break;
> > > + case READ:
> > > + if (!Quiet) {
> > > + ShellPrintHiiEx (-1, -1,
> > > + NULL,
> > > + STRING_TOKEN (STR_GPT_READ_OK),
> > > + gShellGptHiiHandle,
> > > + ByteCount,
> > > + Offset,
> > > + Entry->PartitionName,
> > > + TimeStampE,
> > > + SpeedKB
> > > + );
> > > + }
> > > + break;
> > > + case READ_FILE:
> > > + Status = FileHandleWrite (FileHandle, &ByteCount, FileBuffer);
> > > + if (EFI_ERROR (Status)) {
> > > + ShellPrintHiiEx (-1, -1,
> > > + NULL,
> > > + STRING_TOKEN (STR_GPT_FILE_WRITE_FAIL),
> > > + gShellGptHiiHandle,
> > > + gAppName,
> > > + FilePath,
> > > + Status
> > > + );
> > > + Status = SHELL_DEVICE_ERROR;
> > > + goto Error_Free_Buffer;
> > > + }
> > > +
> > > + if (!Quiet) {
> > > + ShellPrintHiiEx (-1, -1,
> > > + NULL,
> > > + STRING_TOKEN (STR_GPT_READFILE_OK),
> > > + gShellGptHiiHandle,
> > > + ByteCount,
> > > + Offset,
> > > + Entry->PartitionName,
> > > + FilePath,
> > > + TimeStampE,
> > > + SpeedKB
> > > + );
> > > + }
> > > + break;
> > > + }
> > > +
> > > + if (FileFlag) {
> > > + SHELL_FREE_NON_NULL (FileBuffer);
> > > + if (FileHandle != NULL) {
> > > + ShellCloseFile (&FileHandle);
> > > + FileHandle = NULL;
> > > + }
> > > + }
> > > +
> > > + Status = SHELL_SUCCESS;
> > > +
> > > + Error_Free_Buffer:
> > > + SHELL_FREE_NON_NULL (FileBuffer);
> > > + Error_Close_File:
> > > + if (FileHandle) {
> > > + ShellCloseFile (&FileHandle);
> > > + }
> > > + CleanUp:
> > > + if (BlockIoHandle) {
> > > + // By UEFI Spec blocks must be flushed
> > > + BlockIo->FlushBlocks (BlockIo);
> > > + gBS->CloseProtocol (BlockIoHandle, &gEfiBlockIoProtocolGuid,
> > > gImageHandle, NULL);
> > > + }
> > > +
> > > + GptCleanupGlobals ();
> > > +
> > > + ShellCommandLineFreeVarList (CheckPackage);
> > > +
> > > + if (EFI_ERROR (Status)) {
> > > + Status = SHELL_ABORTED;
> > > + }
> > > +
> > > + return Status;
> > > +}
> > > +
> > > +EFI_STATUS
> > > +EFIAPI
> > > +ShellGptLibConstructor (
> > > + IN EFI_HANDLE ImageHandle,
> > > + IN EFI_SYSTEM_TABLE *SystemTable
> > > + )
> > > +{
> > > + gShellGptHiiHandle = NULL;
> > > +
> > > + gShellGptHiiHandle = HiiAddPackages (
> > > + &gShellGptHiiGuid, gImageHandle,
> > > + UefiShellGptCommandLibStrings, NULL
> > > + );
> > > + if (gShellGptHiiHandle == NULL) {
> > > + return EFI_DEVICE_ERROR;
> > > + }
> > > +
> > > + ShellCommandRegisterCommandName (
> > > + gAppName, ShellCommandRunGpt,
> > ShellCommandGetManFileNameGpt,
> > > 0,
> > > + gAppName, TRUE, gShellGptHiiHandle, STRING_TOKEN
> > > (STR_GET_HELP_GPT)
> > > + );
> > > +
> > > + return EFI_SUCCESS;
> > > +}
> > > +
> > > +EFI_STATUS
> > > +EFIAPI
> > > +ShellGptLibDestructor (
> > > + IN EFI_HANDLE ImageHandle,
> > > + IN EFI_SYSTEM_TABLE *SystemTable
> > > + )
> > > +{
> > > +
> > > + if (gShellGptHiiHandle != NULL) {
> > > + HiiRemovePackages (gShellGptHiiHandle);
> > > + }
> > > + return EFI_SUCCESS;
> > > +}
> > > diff --git
> > > a/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> > >
> > b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> > > new file mode 100644
> > > index 000000000000..1be4b1ab0f11
> > > --- /dev/null
> > > +++
> > >
> > b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> > > @@ -0,0 +1,79 @@
> > > +#
> > > +# Marvell BSD License Option
> > > +#
> > > +# If you received this File from Marvell, you may opt to use, redistribute
> > > +# and/or modify this File under the following licensing terms.
> > > +# Redistribution and use in source and binary forms, with or without
> > > +# modification, are permitted provided that the following conditions are
> > > met:
> > > +#
> > > +# * Redistributions of source code must retain the above copyright notice,
> > > +# this list of conditions and the following disclaimer.
> > > +#
> > > +# * Redistributions in binary form must reproduce the above copyright
> > > +# notice, this list of conditions and the following disclaimer in the
> > > +# documentation and/or other materials provided with the distribution.
> > > +#
> > > +# * Neither the name of Marvell nor the names of its contributors may be
> > > +# used to endorse or promote products derived from this software
> > without
> > > +# specific prior written permission.
> > > +#
> > > +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> > > CONTRIBUTORS "AS IS"
> > > +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> > > LIMITED TO, THE
> > > +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
> > > PARTICULAR PURPOSE ARE
> > > +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> > > CONTRIBUTORS BE LIABLE
> > > +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> > > CONSEQUENTIAL
> > > +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
> > > SUBSTITUTE GOODS OR
> > > +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> > INTERRUPTION)
> > > HOWEVER
> > > +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
> > > STRICT LIABILITY,
> > > +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
> > WAY
> > > OUT OF THE USE
> > > +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> > > DAMAGE.
> > > +#
> > > +
> > > +#
> > > +# Portions Copyright (C) 2016 Broadcom
> > > +#
> > > +
> > > +[Defines]
> > > + INF_VERSION = 0x00010006
> > > + BASE_NAME = UefiShellGptCommandLib
> > > + FILE_GUID = F62ACF25-0D15-22F5-E642-FFB6515E00D7
> > > + MODULE_TYPE = UEFI_APPLICATION
> > > + VERSION_STRING = 0.1
> > > + LIBRARY_CLASS = NULL|UEFI_APPLICATION UEFI_DRIVER
> > > + CONSTRUCTOR = ShellGptLibConstructor
> > > + DESTRUCTOR = ShellGptLibDestructor
> > > +
> > > +[Sources]
> > > + FatFormat.c
> > > + GptWorker.c
> > > + UefiShellGptCommandLib.c
> > > + UefiShellGptCommandLib.uni
> > > +
> > > +[Packages]
> > > + MdeModulePkg/MdeModulePkg.dec
> > > + MdePkg/MdePkg.dec
> > > + ShellPkg/ShellPkg.dec
> > > +
> > > +[LibraryClasses]
> > > + BaseLib
> > > + BaseMemoryLib
> > > + DebugLib
> > > + DevicePathLib
> > > + FileHandleLib
> > > + HiiLib
> > > + MemoryAllocationLib
> > > + PcdLib
> > > + ShellCommandLib
> > > + ShellLib
> > > + UefiBootServicesTableLib
> > > + UefiRuntimeServicesTableLib
> > > + UefiLib
> > > +
> > > +[Protocols]
> > > + gEfiBlockIoProtocolGuid
> > > + gEfiDevicePathProtocolGuid
> > > + gEfiDiskIoProtocolGuid
> > > +
> > > +[Guids]
> > > + gShellGptHiiGuid
> > > + gEfiPartTypeUnusedGuid ## SOMETIMES_CONSUMES ##
> > GUID
> > > diff --git
> > >
> > a/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
> > >
> > b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
> > > new file mode 100644
> > > index 000000000000..55bcb42cfeb3
> > > --- /dev/null
> > > +++
> > >
> > b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
> > > @@ -0,0 +1,117 @@
> > >
> > +/*********************************************************
> > > **********************
> > > +Copyright (C) 2016 Marvell International Ltd.
> > > +
> > > +Marvell BSD License Option
> > > +
> > > +If you received this File from Marvell, you may opt to use, redistribute
> > > and/or
> > > +modify this File under the following licensing terms.
> > > +Redistribution and use in source and binary forms, with or without
> > > modification,
> > > +are permitted provided that the following conditions are met:
> > > +
> > > + * Redistributions of source code must retain the above copyright
> > notice,
> > > + this list of conditions and the following disclaimer.
> > > +
> > > + * Redistributions in binary form must reproduce the above copyright
> > > + notice, this list of conditions and the following disclaimer in the
> > > + documentation and/or other materials provided with the distribution.
> > > +
> > > + * Neither the name of Marvell nor the names of its contributors may
> > be
> > > + used to endorse or promote products derived from this software
> > > without
> > > + specific prior written permission.
> > > +
> > > +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> > > CONTRIBUTORS "AS IS" AND
> > > +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
> > TO,
> > > THE IMPLIED
> > > +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> > > PURPOSE ARE
> > > +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> > > CONTRIBUTORS BE LIABLE FOR
> > > +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> > > CONSEQUENTIAL DAMAGES
> > > +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
> > GOODS
> > > OR SERVICES;
> > > +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
> > HOWEVER
> > > CAUSED AND ON
> > > +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> > > TORT
> > > +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
> > > THE USE OF THIS
> > > +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> > > +
> > >
> > +*********************************************************
> > > **********************/
> > > +
> > > +/* Portions Copyright (C) 2016 Broadcom */
> > > +/=#
> > > +
> > > +#langdef en-US "english"
> > > +
> > > +#string STR_GEN_PARAM_INV #language en-US "%H%s%N: Invalid
> > > argument - '%H%s%N'\r\n"
> > > +#string STR_GEN_MAP_PROTOCOL #language en-US "%H%s%N:
> > > Mapped device '%B%s%N' does not have protocol %B%s%N\r\n"
> > > +
> > > +#string STR_GPT_ERROR #language en-US "%H%s%N: %r - %s\r\n"
> > > +#string STR_GPT_NOT_EMPTY #language en-US "%H%s%N:
> > WARNING!!!
> > > This device has valid GPT partition tables!\r\n"
> > > +#string STR_GPT_CLEAR_SURE #language en-US "Are you sure you
> > want
> > > to clear the GPT tables on this device? %BY%Nes, %BN%No "
> > > +#string STR_GPT_ABSOLUTELY_SURE #language en-US "\r\nAre you ***
> > > ABSOLUTELY SURE *** you want to perform this
> > > operation ? %BY%Nes, %BN%No "
> > > +#string STR_GPT_FORMAT_WARNING #language en-US "%H%s%N:
> > > WARNING!!! Formatting of this partition will destroy all data on it!\r\n"
> > > +#string STR_GPT_FORMAT_SURE #language en-US "Are you sure you
> > > want to format this partition to FAT32 and destroy all data on
> > > it ? %BY%Nes, %BN%No "
> > > +#string STR_GPT_DELETE_WARNING #language en-US "%H%s%N:
> > Deleting
> > > of this partition will make data on it unreachable!\r\n"
> > > +#string STR_GPT_READ_BOUNDARY #language en-US "%H%s%N:
> > Attempt
> > > to read beyond %H%s%N partition boundary (can read upto %llu bytes
> > from
> > > the given offset, requested %llu bytes)\r\n"
> > > +#string STR_GPT_WRITE_BOUNDARY #language en-US "%H%s%N:
> > > Attempt to write beyond %H%s%N partition boundary (can write upto %llu
> > > bytes from the given offset, requested %llu bytes)\r\n"
> > > +#string STR_GPT_FILE_WRITE_FAIL #language en-US "%H%s%N: Failed to
> > > write to the file %s, error %r\r\n"
> > > +
> > > +#string STR_GPT_WRITE_OK #language en-US "Written %llu bytes at
> > > offset 0x%x, partition %s. Elapsed time %llums (%llu KB/s)\r\n"
> > > +#string STR_GPT_READ_OK #language en-US "Read %llu bytes from
> > > offset 0x%x, partition %s. Elapsed time %llums (%llu KB/s)\r\n"
> > > +#string STR_GPT_READFILE_OK #language en-US "Read %llu bytes from
> > > offset 0x%x, partition %s into file %s. Elapsed time %llums (%llu KB/s)\r\n"
> > > +#string STR_GPT_LIST_DEVS #language en-US " %H%+6s%N %+8s "
> > > +
> > > +#string STR_GET_HELP_GPT #language en-US ""
> > > +".TH gpt 0 "GPT partition manager."\r\n"
> > > +".SH NAME\r\n"
> > > +"Manages GPT partitions on a block device.\r\n"
> > > +".SH SYNOPSIS\r\n"
> > > +" \r\n"
> > > +"gpt [read | readfile | write | writefile | list | info | clear |\r\n"
> > > +" create | delete | rename | setattrs | sync | fatformat | -typesinfo | -
> > yes]
> > > \r\n"
> > > +"This is a complex utility. Please see examples for usage info\r\n"
> > > +".SH OPTIONS\r\n"
> > > +" \r\n"
> > > +" Device - Block device to be used for the operation\r\n"
> > > +" Length - Number of bytes to transfer (for read/write))\r\n"
> > > +" Address - Address in RAM to store/load data\r\n"
> > > +" Offset - Offset (in blocks) from beggining of the specifie partition to
> > > store/load data\r\n"
> > > +" FilePath - Path to file to read data into or write/update data
> > from\r\n"
> > > +" -yes - Assume yes for all queries, do not prompt\r\n\r\n"
> > > +".SH EXAMPLES\r\n"
> > > +" \r\n"
> > > +"EXAMPLES:\r\n"
> > > +"Get the list of available partitionable block device(s)\r\n"
> > > +" gpt %Hlist%N\r\n"
> > > +"Get info on the particular partition with name PartitionName on the
> > block
> > > device blk0:\r\n"
> > > +" gpt %Hinfo%N blk0: PartitionName\r\n"
> > > +"List all available GPT partitions on the block device blk0:\r\n"
> > > +" gpt list blk0:\r\n"
> > > +"Note: the ordinal number shown by this command can be used as a
> > > partition name in any command requiring partition name\r\n"
> > > +"Thus gpt info blk0: 1 is valid if there is a partition with ordinal 1 present in
> > > the output of gpt list command\r\n"
> > > +"Get information on all recognized partition types\r\n"
> > > +" gpt %Htypesinfo%N\r\n"
> > > +"Clear partitions information and install empty GPT tables for a block
> > device
> > > blk0:\r\n"
> > > +" gpt %Hclear%N blk0:\r\n"
> > > +"Create a GPT partition with name PartitionName and type EFI SYSTEM in
> > > the GPT table, using the next available LBA, with size\r\n"
> > > +"64MiB, with system attribute, on block device blk0:\r\n"
> > > +" gpt %Hcreate%N blk0: PartitionName 0 64 1 -type 0\r\n"
> > > +"Same as above, but now the partition type is not known to the gpt utility,
> > > so use some GUID known to a 3rd party\r\n"
> > > +" gpt create blk0: PartitionName 0 64 1 -type 44581A4A-C834-D1A6-2602-
> > > 9D522A8F2307\r\n"
> > > +"Rename the GPT partition PartitionName on blk0: to
> > > NewPartitionName\r\n"
> > > +" gpt %Hrename%N blk0: PartitionName NewPartitionName\r\n"
> > > +"Have the PartitionDxe driver to re-read GPT tables on a block device
> > > blk0:(after they were updated with gpt utility)\r\n"
> > > +" gpt %Hsync%N blk0:\r\n"
> > > +"Read 4K from block offset 0x0e000 in Partition named PartitionName of
> > > the block device at blk0: into RAM at address 0x100000\r\n"
> > > +" gpt %Hread%N blk0: 0x100000 PartitionName 0xe000 4096\r\n"
> > > +"Write 512 bytes from 0x200000 at RAM into the block device at blk0:
> > > partition PartitionName at offset 0x1000\r\n"
> > > +" gpt %Hwrite%N blk0: 0x200000 PartitionName 0x1000 512\r\n"
> > > +"Read 0x3000 bytes from 0x0 offset of Partition PartitionName at the
> > block
> > > device blk0: into file fs2:file.bin\r\n"
> > > +" gpt %Hreadfile%N blk0: fs2:file.bin PartitionName 0x0 0x3000\r\n"
> > > +"Write contents of file fs2:file.bin into partition named PartitionName
> > with
> > > offset (in lba) 0x10 on a block device blk0:\r\n"
> > > +" gpt %Hwritefile%N blk0: fs2:file.bin PartitionName 0x10\r\n"
> > > +"FAT Format the partition PartitionName on block device blk0:\r\n"
> > > +" gpt %Hfatformat%N blk0: PartitionName\r\n"
> > > +"FAT Format the whole device blk0:\r\n"
> > > +" gpt fatformat blk0:\r\n"
> > > +
> > > +".SH RETURNVALUES\r\n"
> > > +" \r\n"
> > > +"RETURN VALUES:\r\n"
> > > +" SHELL_SUCCESS The action was completed as requested.\r\n"
> > > +" Specific Shell error Error while processing command\r\n"
> > > diff --git a/ShellPkg/ShellPkg.dec b/ShellPkg/ShellPkg.dec
> > > index 39f8012b98c1..5374a2a62d5f 100644
> > > --- a/ShellPkg/ShellPkg.dec
> > > +++ b/ShellPkg/ShellPkg.dec
> > > @@ -56,6 +56,7 @@ [Guids]
> > > gShellNetwork2HiiGuid = {0x174b2b5, 0xf505, 0x4b12, {0xaa, 0x60,
> > > 0x59, 0xdf, 0xf8, 0xd6, 0xea, 0x37}}
> > > gShellTftpHiiGuid = {0x738a9314, 0x82c1, 0x4592, {0x8f, 0xf7,
> 0xc1,
> > > 0xbd, 0xf1, 0xb2, 0x0e, 0xd4}}
> > > gShellBcfgHiiGuid = {0x5f5f605d, 0x1583, 0x4a2d, {0xa6, 0xb2,
> 0xeb,
> > > 0x12, 0xda, 0xb4, 0xa2, 0xb6}}
> > > + gShellGptHiiGuid = {0x5a1ed739, 0x5ef1, 0x429a, {0x8d, 0xf8,
> 0x28,
> > > 0xc9, 0x92, 0x64, 0xd7, 0xf8}}
> > >
> > > [Protocols]
> > > gEfiShellProtocolGuid = {0x6302d008, 0x7f9b, 0x4f30, {0x87, 0xac,
> > > 0x60, 0xc9, 0xfe, 0xf5, 0xda, 0x4e}}
> > > diff --git a/ShellPkg/ShellPkg.dsc b/ShellPkg/ShellPkg.dsc
> > > index 809bd4220af2..984c1d0ad48b 100644
> > > --- a/ShellPkg/ShellPkg.dsc
> > > +++ b/ShellPkg/ShellPkg.dsc
> > > @@ -89,6 +89,7 @@ [Components]
> > >
> > >
> > ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib
> > > .inf
> > >
> > >
> > ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib
> > > .inf
> > >
> > >
> > ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsL
> > > ib.inf
> > > +
> > ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> > >
> > >
> > ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLi
> > > b.inf
> > >
> > >
> > ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1Commands
> > > Lib.inf
> > >
> > >
> > ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1Comm
> > > andsLib.inf
> > > @@ -119,6 +120,9 @@ [Components]
> > > !ifdef $(INCLUDE_TFTP_COMMAND)
> > >
> > >
> > NULL|ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib
> > > .inf
> > > !endif #$(INCLUDE_TFTP_COMMAND)
> > > +!ifdef $(INCLUDE_GPT_COMMAND)
> > > +
> > >
> > NULL|ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.
> > > inf
> > > +!endif #$(INCLUDE_GPT_COMMAND)
> > > !endif #$(NO_SHELL_PROFILES)
> > > }
> > >
> > > --
> > > 1.9.1
> >
> > _______________________________________________
> > edk2-devel mailing list
> > edk2-devel@lists.01.org
> > https://lists.01.org/mailman/listinfo/edk2-devel
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] GPT Shell Application/Library
2016-10-17 17:56 ` Carsey, Jaben
@ 2016-10-18 13:59 ` Shah, Tapan
2016-10-18 16:58 ` Vladimir Olovyannikov
0 siblings, 1 reply; 20+ messages in thread
From: Shah, Tapan @ 2016-10-18 13:59 UTC (permalink / raw)
To: Carsey, Jaben, Vladimir Olovyannikov, Michael Zimmermann
Cc: Ni, Ruiyu, Arshi, Shala, edk2-devel@lists.01.org, Laszlo Ersek
Thanks for the contribution Vladimir!
Few comments:
1. It's better to refactor the code now before commit and move GPT related code outside ShellPkg and create a shared library.
2. CLI parameters of this utility are too complex and need to be refactored to make it similar to other existing Shell commands.
Thanks,
Tapan
-----Original Message-----
From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of Carsey, Jaben
Sent: Monday, October 17, 2016 12:56 PM
To: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>; Michael Zimmermann <sigmaepsilon92@gmail.com>
Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Arshi, Shala <shala.arshi@intel.com>; edk2-devel@lists.01.org <edk2-devel@ml01.01.org>; Carsey, Jaben <jaben.carsey@intel.com>; Laszlo Ersek <lersek@redhat.com>
Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
To the old question about license: I asked our people to check and was told that the license is compatible with our BSD and ok by Intel.
To the technical content – I really like this idea of a shared library. That would be a great way to share code and not have as much duplicate.
-Jaben
From: Vladimir Olovyannikov [mailto:vladimir.olovyannikov@broadcom.com]
Sent: Monday, October 17, 2016 10:52 AM
To: Michael Zimmermann <sigmaepsilon92@gmail.com>
Cc: Laszlo Ersek <lersek@redhat.com>; Carsey, Jaben <jaben.carsey@intel.com>; Ni, Ruiyu <ruiyu.ni@intel.com>; edk2-devel@lists.01.org <edk2-devel@ml01.01.org>
Subject: RE: [edk2] [PATCH] GPT Shell Application/Library
Importance: High
Hi Michael,
I am absolutely agree with your proposal.
In the gpt Shell library/application I had to “borrow” some stuff from PartitionDxe.c to not reinvent a wheel.
If the PartitionDxe maintainer agrees to have a separate library available for everybody, I would move all the GPT-related stuff from the GptWorker (and partially from the PartitionDxe itself) to that independent library.
This could be a longer-term task.
Right now I just wanted to share the tool which could be useful for anybody who would wish to manage GPT partitions (and/or do a FAT32 format of either a disk or a GPT partition) from within the Shell. What do you think?
Thank you,
Vladimir
From: Michael Zimmermann [mailto:sigmaepsilon92@gmail.com<mailto:sigmaepsilon92@gmail.com>]
Sent: October-17-16 12:25 AM
To: Vladimir Olovyannikov
Cc: Laszlo Ersek; Jaben Carsey; Ni, Ruiyu; edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
Hi,
wouldn't it be better to make a generic gpt parsing library which is independent of the shell so both the shell and PartitionDxe can use it?
It may also be useful for other applications which need additional information like the gpt partition names.
Thanks
Michael
On Mon, Oct 17, 2016 at 8:49 AM, Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com<mailto:vladimir.olovyannikov@broadcom.com>> wrote:
Thank you Laszlo,
Sorry, I missed the fields; it is my first contribution, I will add the required lines, review the source according to your comments and will resubmit the patch.
So do you think the command should be _gpt instead of gpt? I was following TFTP and SF commands as a template.
Thank you,
Vladimir
On Oct 16, 2016 1:05 PM, "Laszlo Ersek" <lersek@redhat.com<mailto:lersek@redhat.com>> wrote:
>
> On 10/16/16 07:23, Vladimir Olovyannikov wrote:
> > This allows managing (create, delete, modify, fat format) of GPT
> > partitions from within UEFI Shell.
> > Syntax:
> > gpt <command> [device_mapped_name] [parameters...] See usage
> > examples in the .uni file
> > ---
> > .../Library/UefiShellGptCommandLib/FatFormat.c | 611 +++++++
> > .../Library/UefiShellGptCommandLib/FatFormat.h | 111 ++
> > .../Library/UefiShellGptCommandLib/GptWorker.c | 1902
++++++++++++++++++++
> > .../Library/UefiShellGptCommandLib/GptWorker.h | 186 ++
> > .../UefiShellGptCommandLib.c | 1135 ++++++++++++
> > .../UefiShellGptCommandLib.inf | 79 +
> > .../UefiShellGptCommandLib.uni | 117 ++
> > ShellPkg/ShellPkg.dec | 1 +
> > ShellPkg/ShellPkg.dsc | 4 +
> > 9 files changed, 4146 insertions(+) create mode 100644
> > ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> > create mode 100644
> > ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> > create mode 100644
> > ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> > create mode 100644
> > ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> > create mode 100644
ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> > create mode 100644
ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> > create mode 100644
ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
>
> This looks like a supremely welcome, long-awaited addition (latest
> request:
> <https://lists.01.org/pipermail/edk2-devel/2016-October/002667.html>),
> but it really needs your Signed-off-by, and the Contributed-under line
> above it:
>
> ShellPkg/Contributions.txt
>
> I would also suggest (simply based on what I've seen elsewhere in
> edk2) to keep the copyright notices tightly collected in the file headings.
>
> Someone will have to go over all the licenses too -- does the "Marvell
> BSD License Option" for example correspond to the 3-clause BSDL?
>
> On the technical side, I believe that as long as a shell command (or a
> command option) is not standardized (in the shell spec), it usually
> starts with an underscore (_), so as to prevent future name collisions.
> (I could be wrong about this -- I now recall the TFTP command, which
> is also not in the 2.2 spec.)
>
> Just my two cents.
>
> Thanks
> Laszlo
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
https://lists.01.org/mailman/listinfo/edk2-devel
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] GPT Shell Application/Library
2016-10-18 13:59 ` Shah, Tapan
@ 2016-10-18 16:58 ` Vladimir Olovyannikov
2016-10-18 17:04 ` Carsey, Jaben
2016-10-18 17:23 ` Laszlo Ersek
0 siblings, 2 replies; 20+ messages in thread
From: Vladimir Olovyannikov @ 2016-10-18 16:58 UTC (permalink / raw)
To: Shah, Tapan, Carsey, Jaben, Michael Zimmermann
Cc: Ni, Ruiyu, Arshi, Shala, edk2-devel@lists.01.org, Laszlo Ersek
Thank you all for comments,
So to summarize the discussion:
1. I will create a Shell library which would perform all GPT operations.
Part of PartitionDxe will also be in that library so PartitionDxe will
be using it.
The gpt Shell tool will also be using it.
2. Refactor the parameters of the gpt utility to make it similar to other
existing Shell commands.
BTW Is there any document describing Shell utility parameters'
standards?
Please let me know if you have other suggestions.
Thank you,
Vladimir
-----Original Message-----
From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of Shah,
Tapan
Sent: October-18-16 6:59 AM
To: Carsey, Jaben; Vladimir Olovyannikov; Michael Zimmermann
Cc: Ni, Ruiyu; Arshi, Shala; edk2-devel@lists.01.org; Laszlo Ersek
Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
Thanks for the contribution Vladimir!
Few comments:
1. It's better to refactor the code now before commit and move GPT related
code outside ShellPkg and create a shared library.
2. CLI parameters of this utility are too complex and need to be refactored
to make it similar to other existing Shell commands.
Thanks,
Tapan
-----Original Message-----
From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
Carsey, Jaben
Sent: Monday, October 17, 2016 12:56 PM
To: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>; Michael
Zimmermann <sigmaepsilon92@gmail.com>
Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Arshi, Shala <shala.arshi@intel.com>;
edk2-devel@lists.01.org <edk2-devel@ml01.01.org>; Carsey, Jaben
<jaben.carsey@intel.com>; Laszlo Ersek <lersek@redhat.com>
Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
To the old question about license: I asked our people to check and was told
that the license is compatible with our BSD and ok by Intel.
To the technical content – I really like this idea of a shared library.
That would be a great way to share code and not have as much duplicate.
-Jaben
From: Vladimir Olovyannikov [mailto:vladimir.olovyannikov@broadcom.com]
Sent: Monday, October 17, 2016 10:52 AM
To: Michael Zimmermann <sigmaepsilon92@gmail.com>
Cc: Laszlo Ersek <lersek@redhat.com>; Carsey, Jaben
<jaben.carsey@intel.com>; Ni, Ruiyu <ruiyu.ni@intel.com>;
edk2-devel@lists.01.org <edk2-devel@ml01.01.org>
Subject: RE: [edk2] [PATCH] GPT Shell Application/Library
Importance: High
Hi Michael,
I am absolutely agree with your proposal.
In the gpt Shell library/application I had to “borrow” some stuff from
PartitionDxe.c to not reinvent a wheel.
If the PartitionDxe maintainer agrees to have a separate library available
for everybody, I would move all the GPT-related stuff from the GptWorker
(and partially from the PartitionDxe itself) to that independent library.
This could be a longer-term task.
Right now I just wanted to share the tool which could be useful for anybody
who would wish to manage GPT partitions (and/or do a FAT32 format of either
a disk or a GPT partition) from within the Shell. What do you think?
Thank you,
Vladimir
From: Michael Zimmermann
[mailto:sigmaepsilon92@gmail.com<mailto:sigmaepsilon92@gmail.com>]
Sent: October-17-16 12:25 AM
To: Vladimir Olovyannikov
Cc: Laszlo Ersek; Jaben Carsey; Ni, Ruiyu;
edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
Hi,
wouldn't it be better to make a generic gpt parsing library which is
independent of the shell so both the shell and PartitionDxe can use it?
It may also be useful for other applications which need additional
information like the gpt partition names.
Thanks
Michael
On Mon, Oct 17, 2016 at 8:49 AM, Vladimir Olovyannikov
<vladimir.olovyannikov@broadcom.com<mailto:vladimir.olovyannikov@broadcom.com>>
wrote:
Thank you Laszlo,
Sorry, I missed the fields; it is my first contribution, I will add the
required lines, review the source according to your comments and will
resubmit the patch.
So do you think the command should be _gpt instead of gpt? I was following
TFTP and SF commands as a template.
Thank you,
Vladimir
On Oct 16, 2016 1:05 PM, "Laszlo Ersek"
<lersek@redhat.com<mailto:lersek@redhat.com>> wrote:
>
> On 10/16/16 07:23, Vladimir Olovyannikov wrote:
> > This allows managing (create, delete, modify, fat format) of GPT
> > partitions from within UEFI Shell.
> > Syntax:
> > gpt <command> [device_mapped_name] [parameters...] See usage
> > examples in the .uni file
> > ---
> > .../Library/UefiShellGptCommandLib/FatFormat.c | 611 +++++++
> > .../Library/UefiShellGptCommandLib/FatFormat.h | 111 ++
> > .../Library/UefiShellGptCommandLib/GptWorker.c | 1902
++++++++++++++++++++
> > .../Library/UefiShellGptCommandLib/GptWorker.h | 186 ++
> > .../UefiShellGptCommandLib.c | 1135 ++++++++++++
> > .../UefiShellGptCommandLib.inf | 79 +
> > .../UefiShellGptCommandLib.uni | 117 ++
> > ShellPkg/ShellPkg.dec | 1 +
> > ShellPkg/ShellPkg.dsc | 4 +
> > 9 files changed, 4146 insertions(+) create mode 100644
> > ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> > create mode 100644
> > ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> > create mode 100644
> > ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> > create mode 100644
> > ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> > create mode 100644
ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> > create mode 100644
ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> > create mode 100644
ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
>
> This looks like a supremely welcome, long-awaited addition (latest
> request:
> <https://lists.01.org/pipermail/edk2-devel/2016-October/002667.html>),
> but it really needs your Signed-off-by, and the Contributed-under line
> above it:
>
> ShellPkg/Contributions.txt
>
> I would also suggest (simply based on what I've seen elsewhere in
> edk2) to keep the copyright notices tightly collected in the file
> headings.
>
> Someone will have to go over all the licenses too -- does the "Marvell
> BSD License Option" for example correspond to the 3-clause BSDL?
>
> On the technical side, I believe that as long as a shell command (or a
> command option) is not standardized (in the shell spec), it usually
> starts with an underscore (_), so as to prevent future name collisions.
> (I could be wrong about this -- I now recall the TFTP command, which
> is also not in the 2.2 spec.)
>
> Just my two cents.
>
> Thanks
> Laszlo
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
https://lists.01.org/mailman/listinfo/edk2-devel
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] GPT Shell Application/Library
2016-10-18 16:58 ` Vladimir Olovyannikov
@ 2016-10-18 17:04 ` Carsey, Jaben
2016-10-18 18:03 ` Shah, Tapan
2016-10-18 17:23 ` Laszlo Ersek
1 sibling, 1 reply; 20+ messages in thread
From: Carsey, Jaben @ 2016-10-18 17:04 UTC (permalink / raw)
To: Vladimir Olovyannikov, Shah, Tapan, Michael Zimmermann
Cc: Ni, Ruiyu, Arshi, Shala, edk2-devel@lists.01.org, Laszlo Ersek,
Carsey, Jaben
For the standards, I would try to use the UEFI Shell Spec for some parameters. For Example:
-v for verbose
-h for help
-sfo for standard format output
> -----Original Message-----
> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
> Vladimir Olovyannikov
> Sent: Tuesday, October 18, 2016 9:58 AM
> To: Shah, Tapan <tapandshah@hpe.com>; Carsey, Jaben
> <jaben.carsey@intel.com>; Michael Zimmermann
> <sigmaepsilon92@gmail.com>
> Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Arshi, Shala <shala.arshi@intel.com>;
> edk2-devel@lists.01.org <edk2-devel@ml01.01.org>; Laszlo Ersek
> <lersek@redhat.com>
> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> Importance: High
>
> Thank you all for comments,
>
> So to summarize the discussion:
>
> 1. I will create a Shell library which would perform all GPT operations.
> Part of PartitionDxe will also be in that library so PartitionDxe will
> be using it.
> The gpt Shell tool will also be using it.
> 2. Refactor the parameters of the gpt utility to make it similar to other
> existing Shell commands.
> BTW Is there any document describing Shell utility parameters'
> standards?
>
> Please let me know if you have other suggestions.
>
> Thank you,
> Vladimir
>
> -----Original Message-----
> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
> Shah,
> Tapan
> Sent: October-18-16 6:59 AM
> To: Carsey, Jaben; Vladimir Olovyannikov; Michael Zimmermann
> Cc: Ni, Ruiyu; Arshi, Shala; edk2-devel@lists.01.org; Laszlo Ersek
> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
>
> Thanks for the contribution Vladimir!
>
> Few comments:
> 1. It's better to refactor the code now before commit and move GPT related
> code outside ShellPkg and create a shared library.
> 2. CLI parameters of this utility are too complex and need to be refactored
> to make it similar to other existing Shell commands.
>
> Thanks,
> Tapan
>
> -----Original Message-----
> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
> Carsey, Jaben
> Sent: Monday, October 17, 2016 12:56 PM
> To: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>; Michael
> Zimmermann <sigmaepsilon92@gmail.com>
> Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Arshi, Shala <shala.arshi@intel.com>;
> edk2-devel@lists.01.org <edk2-devel@ml01.01.org>; Carsey, Jaben
> <jaben.carsey@intel.com>; Laszlo Ersek <lersek@redhat.com>
> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
>
> To the old question about license: I asked our people to check and was told
> that the license is compatible with our BSD and ok by Intel.
>
> To the technical content – I really like this idea of a shared library.
> That would be a great way to share code and not have as much duplicate.
>
> -Jaben
>
> From: Vladimir Olovyannikov [mailto:vladimir.olovyannikov@broadcom.com]
> Sent: Monday, October 17, 2016 10:52 AM
> To: Michael Zimmermann <sigmaepsilon92@gmail.com>
> Cc: Laszlo Ersek <lersek@redhat.com>; Carsey, Jaben
> <jaben.carsey@intel.com>; Ni, Ruiyu <ruiyu.ni@intel.com>;
> edk2-devel@lists.01.org <edk2-devel@ml01.01.org>
> Subject: RE: [edk2] [PATCH] GPT Shell Application/Library
> Importance: High
>
> Hi Michael,
> I am absolutely agree with your proposal.
>
> In the gpt Shell library/application I had to “borrow” some stuff from
> PartitionDxe.c to not reinvent a wheel.
> If the PartitionDxe maintainer agrees to have a separate library available
> for everybody, I would move all the GPT-related stuff from the GptWorker
> (and partially from the PartitionDxe itself) to that independent library.
> This could be a longer-term task.
> Right now I just wanted to share the tool which could be useful for anybody
> who would wish to manage GPT partitions (and/or do a FAT32 format of
> either
> a disk or a GPT partition) from within the Shell. What do you think?
>
> Thank you,
> Vladimir
> From: Michael Zimmermann
> [mailto:sigmaepsilon92@gmail.com<mailto:sigmaepsilon92@gmail.com>]
> Sent: October-17-16 12:25 AM
> To: Vladimir Olovyannikov
> Cc: Laszlo Ersek; Jaben Carsey; Ni, Ruiyu;
> edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
>
> Hi,
>
> wouldn't it be better to make a generic gpt parsing library which is
> independent of the shell so both the shell and PartitionDxe can use it?
> It may also be useful for other applications which need additional
> information like the gpt partition names.
>
> Thanks
> Michael
>
> On Mon, Oct 17, 2016 at 8:49 AM, Vladimir Olovyannikov
> <vladimir.olovyannikov@broadcom.com<mailto:vladimir.olovyannikov@broa
> dcom.com>>
> wrote:
> Thank you Laszlo,
>
> Sorry, I missed the fields; it is my first contribution, I will add the
> required lines, review the source according to your comments and will
> resubmit the patch.
> So do you think the command should be _gpt instead of gpt? I was following
> TFTP and SF commands as a template.
>
> Thank you,
> Vladimir
>
> On Oct 16, 2016 1:05 PM, "Laszlo Ersek"
> <lersek@redhat.com<mailto:lersek@redhat.com>> wrote:
> >
> > On 10/16/16 07:23, Vladimir Olovyannikov wrote:
> > > This allows managing (create, delete, modify, fat format) of GPT
> > > partitions from within UEFI Shell.
> > > Syntax:
> > > gpt <command> [device_mapped_name] [parameters...] See usage
> > > examples in the .uni file
> > > ---
> > > .../Library/UefiShellGptCommandLib/FatFormat.c | 611 +++++++
> > > .../Library/UefiShellGptCommandLib/FatFormat.h | 111 ++
> > > .../Library/UefiShellGptCommandLib/GptWorker.c | 1902
> ++++++++++++++++++++
> > > .../Library/UefiShellGptCommandLib/GptWorker.h | 186 ++
> > > .../UefiShellGptCommandLib.c | 1135 ++++++++++++
> > > .../UefiShellGptCommandLib.inf | 79 +
> > > .../UefiShellGptCommandLib.uni | 117 ++
> > > ShellPkg/ShellPkg.dec | 1 +
> > > ShellPkg/ShellPkg.dsc | 4 +
> > > 9 files changed, 4146 insertions(+) create mode 100644
> > > ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> > > create mode 100644
> > > ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> > > create mode 100644
> > > ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> > > create mode 100644
> > > ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> > > create mode 100644
> ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> > > create mode 100644
> ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> > > create mode 100644
> ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
> >
> > This looks like a supremely welcome, long-awaited addition (latest
> > request:
> > <https://lists.01.org/pipermail/edk2-devel/2016-October/002667.html>),
> > but it really needs your Signed-off-by, and the Contributed-under line
> > above it:
> >
> > ShellPkg/Contributions.txt
> >
> > I would also suggest (simply based on what I've seen elsewhere in
> > edk2) to keep the copyright notices tightly collected in the file
> > headings.
> >
> > Someone will have to go over all the licenses too -- does the "Marvell
> > BSD License Option" for example correspond to the 3-clause BSDL?
> >
> > On the technical side, I believe that as long as a shell command (or a
> > command option) is not standardized (in the shell spec), it usually
> > starts with an underscore (_), so as to prevent future name collisions.
> > (I could be wrong about this -- I now recall the TFTP command, which
> > is also not in the 2.2 spec.)
> >
> > Just my two cents.
> >
> > Thanks
> > Laszlo
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
> https://lists.01.org/mailman/listinfo/edk2-devel
>
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] GPT Shell Application/Library
2016-10-18 16:58 ` Vladimir Olovyannikov
2016-10-18 17:04 ` Carsey, Jaben
@ 2016-10-18 17:23 ` Laszlo Ersek
2016-10-18 18:03 ` Vladimir Olovyannikov
1 sibling, 1 reply; 20+ messages in thread
From: Laszlo Ersek @ 2016-10-18 17:23 UTC (permalink / raw)
To: Vladimir Olovyannikov, Shah, Tapan, Carsey, Jaben,
Michael Zimmermann
Cc: Ni, Ruiyu, Arshi, Shala, edk2-devel@lists.01.org
On 10/18/16 18:58, Vladimir Olovyannikov wrote:
> Thank you all for comments,
>
> So to summarize the discussion:
>
> 1. I will create a Shell library which would perform all GPT operations.
> Part of PartitionDxe will also be in that library so PartitionDxe will
> be using it.
> The gpt Shell tool will also be using it.
I think you might want to place the library class header file, and the
library instance, under MdeModulePkg. It's okay for the shell
application (or shell libraries) to depend on library classes / library
instances from MdeModulePkg, but -- I think -- it's not okay for a
driver in MdeModulePkg, such as PartitionDxe, to depend on a class +
instance from under ShellPkg.
Thanks!
Laszlo
> 2. Refactor the parameters of the gpt utility to make it similar to other
> existing Shell commands.
> BTW Is there any document describing Shell utility parameters'
> standards?
>
> Please let me know if you have other suggestions.
>
> Thank you,
> Vladimir
>
> -----Original Message-----
> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of Shah,
> Tapan
> Sent: October-18-16 6:59 AM
> To: Carsey, Jaben; Vladimir Olovyannikov; Michael Zimmermann
> Cc: Ni, Ruiyu; Arshi, Shala; edk2-devel@lists.01.org; Laszlo Ersek
> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
>
> Thanks for the contribution Vladimir!
>
> Few comments:
> 1. It's better to refactor the code now before commit and move GPT related
> code outside ShellPkg and create a shared library.
> 2. CLI parameters of this utility are too complex and need to be refactored
> to make it similar to other existing Shell commands.
>
> Thanks,
> Tapan
>
> -----Original Message-----
> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
> Carsey, Jaben
> Sent: Monday, October 17, 2016 12:56 PM
> To: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>; Michael
> Zimmermann <sigmaepsilon92@gmail.com>
> Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Arshi, Shala <shala.arshi@intel.com>;
> edk2-devel@lists.01.org <edk2-devel@ml01.01.org>; Carsey, Jaben
> <jaben.carsey@intel.com>; Laszlo Ersek <lersek@redhat.com>
> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
>
> To the old question about license: I asked our people to check and was told
> that the license is compatible with our BSD and ok by Intel.
>
> To the technical content – I really like this idea of a shared library.
> That would be a great way to share code and not have as much duplicate.
>
> -Jaben
>
> From: Vladimir Olovyannikov [mailto:vladimir.olovyannikov@broadcom.com]
> Sent: Monday, October 17, 2016 10:52 AM
> To: Michael Zimmermann <sigmaepsilon92@gmail.com>
> Cc: Laszlo Ersek <lersek@redhat.com>; Carsey, Jaben
> <jaben.carsey@intel.com>; Ni, Ruiyu <ruiyu.ni@intel.com>;
> edk2-devel@lists.01.org <edk2-devel@ml01.01.org>
> Subject: RE: [edk2] [PATCH] GPT Shell Application/Library
> Importance: High
>
> Hi Michael,
> I am absolutely agree with your proposal.
>
> In the gpt Shell library/application I had to “borrow” some stuff from
> PartitionDxe.c to not reinvent a wheel.
> If the PartitionDxe maintainer agrees to have a separate library available
> for everybody, I would move all the GPT-related stuff from the GptWorker
> (and partially from the PartitionDxe itself) to that independent library.
> This could be a longer-term task.
> Right now I just wanted to share the tool which could be useful for anybody
> who would wish to manage GPT partitions (and/or do a FAT32 format of either
> a disk or a GPT partition) from within the Shell. What do you think?
>
> Thank you,
> Vladimir
> From: Michael Zimmermann
> [mailto:sigmaepsilon92@gmail.com<mailto:sigmaepsilon92@gmail.com>]
> Sent: October-17-16 12:25 AM
> To: Vladimir Olovyannikov
> Cc: Laszlo Ersek; Jaben Carsey; Ni, Ruiyu;
> edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
>
> Hi,
>
> wouldn't it be better to make a generic gpt parsing library which is
> independent of the shell so both the shell and PartitionDxe can use it?
> It may also be useful for other applications which need additional
> information like the gpt partition names.
>
> Thanks
> Michael
>
> On Mon, Oct 17, 2016 at 8:49 AM, Vladimir Olovyannikov
> <vladimir.olovyannikov@broadcom.com<mailto:vladimir.olovyannikov@broadcom.com>>
> wrote:
> Thank you Laszlo,
>
> Sorry, I missed the fields; it is my first contribution, I will add the
> required lines, review the source according to your comments and will
> resubmit the patch.
> So do you think the command should be _gpt instead of gpt? I was following
> TFTP and SF commands as a template.
>
> Thank you,
> Vladimir
>
> On Oct 16, 2016 1:05 PM, "Laszlo Ersek"
> <lersek@redhat.com<mailto:lersek@redhat.com>> wrote:
>>
>> On 10/16/16 07:23, Vladimir Olovyannikov wrote:
>>> This allows managing (create, delete, modify, fat format) of GPT
>>> partitions from within UEFI Shell.
>>> Syntax:
>>> gpt <command> [device_mapped_name] [parameters...] See usage
>>> examples in the .uni file
>>> ---
>>> .../Library/UefiShellGptCommandLib/FatFormat.c | 611 +++++++
>>> .../Library/UefiShellGptCommandLib/FatFormat.h | 111 ++
>>> .../Library/UefiShellGptCommandLib/GptWorker.c | 1902
> ++++++++++++++++++++
>>> .../Library/UefiShellGptCommandLib/GptWorker.h | 186 ++
>>> .../UefiShellGptCommandLib.c | 1135 ++++++++++++
>>> .../UefiShellGptCommandLib.inf | 79 +
>>> .../UefiShellGptCommandLib.uni | 117 ++
>>> ShellPkg/ShellPkg.dec | 1 +
>>> ShellPkg/ShellPkg.dsc | 4 +
>>> 9 files changed, 4146 insertions(+) create mode 100644
>>> ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
>>> create mode 100644
>>> ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
>>> create mode 100644
>>> ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
>>> create mode 100644
>>> ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
>>> create mode 100644
> ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
>>> create mode 100644
> ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
>>> create mode 100644
> ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
>>
>> This looks like a supremely welcome, long-awaited addition (latest
>> request:
>> <https://lists.01.org/pipermail/edk2-devel/2016-October/002667.html>),
>> but it really needs your Signed-off-by, and the Contributed-under line
>> above it:
>>
>> ShellPkg/Contributions.txt
>>
>> I would also suggest (simply based on what I've seen elsewhere in
>> edk2) to keep the copyright notices tightly collected in the file
>> headings.
>>
>> Someone will have to go over all the licenses too -- does the "Marvell
>> BSD License Option" for example correspond to the 3-clause BSDL?
>>
>> On the technical side, I believe that as long as a shell command (or a
>> command option) is not standardized (in the shell spec), it usually
>> starts with an underscore (_), so as to prevent future name collisions.
>> (I could be wrong about this -- I now recall the TFTP command, which
>> is also not in the 2.2 spec.)
>>
>> Just my two cents.
>>
>> Thanks
>> Laszlo
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
> https://lists.01.org/mailman/listinfo/edk2-devel
>
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel
>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] GPT Shell Application/Library
2016-10-18 17:23 ` Laszlo Ersek
@ 2016-10-18 18:03 ` Vladimir Olovyannikov
2016-10-18 18:12 ` Laszlo Ersek
0 siblings, 1 reply; 20+ messages in thread
From: Vladimir Olovyannikov @ 2016-10-18 18:03 UTC (permalink / raw)
To: Laszlo Ersek, Shah, Tapan, Carsey, Jaben, Michael Zimmermann
Cc: Ni, Ruiyu, Arshi, Shala, edk2-devel@lists.01.org
> -----Original Message-----
> From: Laszlo Ersek [mailto:lersek@redhat.com]
> Sent: October-18-16 10:24 AM
> To: Vladimir Olovyannikov; Shah, Tapan; Carsey, Jaben; Michael Zimmermann
> Cc: Ni, Ruiyu; Arshi, Shala; edk2-devel@lists.01.org
> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
>
> On 10/18/16 18:58, Vladimir Olovyannikov wrote:
> > Thank you all for comments,
> >
> > So to summarize the discussion:
> >
> > 1. I will create a Shell library which would perform all GPT operations.
> > Part of PartitionDxe will also be in that library so PartitionDxe
> > will be using it.
> > The gpt Shell tool will also be using it.
>
> I think you might want to place the library class header file, and the
> library
> instance, under MdeModulePkg. It's okay for the shell application (or
> shell
> libraries) to depend on library classes / library instances from
> MdeModulePkg, but -- I think -- it's not okay for a driver in
> MdeModulePkg,
> such as PartitionDxe, to depend on a class + instance from under ShellPkg.
Laszlo,
I think PartitionDxe will depend on the GPT shared library (which will have
nothing to do to the ShellPkg),
as well as gpt tool (Shell library/application) will depend on that shared
library as well to get information regarding partitions and
to perform GPT management.
Thank you,
Vladimir
>
> Thanks!
> Laszlo
>
> > 2. Refactor the parameters of the gpt utility to make it similar to
> > other existing Shell commands.
> > BTW Is there any document describing Shell utility parameters'
> > standards?
> >
> > Please let me know if you have other suggestions.
> >
> > Thank you,
> > Vladimir
> >
> > -----Original Message-----
> > From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
> > Shah, Tapan
> > Sent: October-18-16 6:59 AM
> > To: Carsey, Jaben; Vladimir Olovyannikov; Michael Zimmermann
> > Cc: Ni, Ruiyu; Arshi, Shala; edk2-devel@lists.01.org; Laszlo Ersek
> > Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> >
> > Thanks for the contribution Vladimir!
> >
> > Few comments:
> > 1. It's better to refactor the code now before commit and move GPT
> > related code outside ShellPkg and create a shared library.
> > 2. CLI parameters of this utility are too complex and need to be
> > refactored to make it similar to other existing Shell commands.
> >
> > Thanks,
> > Tapan
> >
> > -----Original Message-----
> > From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
> > Carsey, Jaben
> > Sent: Monday, October 17, 2016 12:56 PM
> > To: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>;
> > Michael Zimmermann <sigmaepsilon92@gmail.com>
> > Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Arshi, Shala
> > <shala.arshi@intel.com>; edk2-devel@lists.01.org
> > <edk2-devel@ml01.01.org>; Carsey, Jaben <jaben.carsey@intel.com>;
> > Laszlo Ersek <lersek@redhat.com>
> > Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> >
> > To the old question about license: I asked our people to check and was
> > told that the license is compatible with our BSD and ok by Intel.
> >
> > To the technical content – I really like this idea of a shared library.
> > That would be a great way to share code and not have as much duplicate.
> >
> > -Jaben
> >
> > From: Vladimir Olovyannikov
> > [mailto:vladimir.olovyannikov@broadcom.com]
> > Sent: Monday, October 17, 2016 10:52 AM
> > To: Michael Zimmermann <sigmaepsilon92@gmail.com>
> > Cc: Laszlo Ersek <lersek@redhat.com>; Carsey, Jaben
> > <jaben.carsey@intel.com>; Ni, Ruiyu <ruiyu.ni@intel.com>;
> > edk2-devel@lists.01.org <edk2-devel@ml01.01.org>
> > Subject: RE: [edk2] [PATCH] GPT Shell Application/Library
> > Importance: High
> >
> > Hi Michael,
> > I am absolutely agree with your proposal.
> >
> > In the gpt Shell library/application I had to “borrow” some stuff from
> > PartitionDxe.c to not reinvent a wheel.
> > If the PartitionDxe maintainer agrees to have a separate library
> > available for everybody, I would move all the GPT-related stuff from
> > the GptWorker (and partially from the PartitionDxe itself) to that
> independent library.
> > This could be a longer-term task.
> > Right now I just wanted to share the tool which could be useful for
> > anybody who would wish to manage GPT partitions (and/or do a FAT32
> > format of either a disk or a GPT partition) from within the Shell. What
> > do
> you think?
> >
> > Thank you,
> > Vladimir
> > From: Michael Zimmermann
> > [mailto:sigmaepsilon92@gmail.com<mailto:sigmaepsilon92@gmail.com>]
> > Sent: October-17-16 12:25 AM
> > To: Vladimir Olovyannikov
> > Cc: Laszlo Ersek; Jaben Carsey; Ni, Ruiyu;
> > edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
> > Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> >
> > Hi,
> >
> > wouldn't it be better to make a generic gpt parsing library which is
> > independent of the shell so both the shell and PartitionDxe can use it?
> > It may also be useful for other applications which need additional
> > information like the gpt partition names.
> >
> > Thanks
> > Michael
> >
> > On Mon, Oct 17, 2016 at 8:49 AM, Vladimir Olovyannikov
> >
> <vladimir.olovyannikov@broadcom.com<mailto:vladimir.olovyannikov@broa
> d
> > com.com>>
> > wrote:
> > Thank you Laszlo,
> >
> > Sorry, I missed the fields; it is my first contribution, I will add
> > the required lines, review the source according to your comments and
> > will resubmit the patch.
> > So do you think the command should be _gpt instead of gpt? I was
> > following TFTP and SF commands as a template.
> >
> > Thank you,
> > Vladimir
> >
> > On Oct 16, 2016 1:05 PM, "Laszlo Ersek"
> > <lersek@redhat.com<mailto:lersek@redhat.com>> wrote:
> >>
> >> On 10/16/16 07:23, Vladimir Olovyannikov wrote:
> >>> This allows managing (create, delete, modify, fat format) of GPT
> >>> partitions from within UEFI Shell.
> >>> Syntax:
> >>> gpt <command> [device_mapped_name] [parameters...] See usage
> >>> examples in the .uni file
> >>> ---
> >>> .../Library/UefiShellGptCommandLib/FatFormat.c | 611 +++++++
> >>> .../Library/UefiShellGptCommandLib/FatFormat.h | 111 ++
> >>> .../Library/UefiShellGptCommandLib/GptWorker.c | 1902
> > ++++++++++++++++++++
> >>> .../Library/UefiShellGptCommandLib/GptWorker.h | 186 ++
> >>> .../UefiShellGptCommandLib.c | 1135
> >>> ++++++++++++
> >>> .../UefiShellGptCommandLib.inf | 79 +
> >>> .../UefiShellGptCommandLib.uni | 117 ++
> >>> ShellPkg/ShellPkg.dec | 1 +
> >>> ShellPkg/ShellPkg.dsc | 4 +
> >>> 9 files changed, 4146 insertions(+) create mode 100644
> >>> ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> >>> create mode 100644
> >>> ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> >>> create mode 100644
> >>> ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> >>> create mode 100644
> >>> ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> >>> create mode 100644
> > ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> >>> create mode 100644
> > ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> >>> create mode 100644
> > ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
> >>
> >> This looks like a supremely welcome, long-awaited addition (latest
> >> request:
> >> <https://lists.01.org/pipermail/edk2-devel/2016-October/002667.html>)
> >> , but it really needs your Signed-off-by, and the Contributed-under
> >> line above it:
> >>
> >> ShellPkg/Contributions.txt
> >>
> >> I would also suggest (simply based on what I've seen elsewhere in
> >> edk2) to keep the copyright notices tightly collected in the file
> >> headings.
> >>
> >> Someone will have to go over all the licenses too -- does the
> >> "Marvell BSD License Option" for example correspond to the 3-clause
> BSDL?
> >>
> >> On the technical side, I believe that as long as a shell command (or
> >> a command option) is not standardized (in the shell spec), it usually
> >> starts with an underscore (_), so as to prevent future name collisions.
> >> (I could be wrong about this -- I now recall the TFTP command, which
> >> is also not in the 2.2 spec.)
> >>
> >> Just my two cents.
> >>
> >> Thanks
> >> Laszlo
> > _______________________________________________
> > edk2-devel mailing list
> > edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
> > https://lists.01.org/mailman/listinfo/edk2-devel
> >
> > _______________________________________________
> > edk2-devel mailing list
> > edk2-devel@lists.01.org
> > https://lists.01.org/mailman/listinfo/edk2-devel
> > _______________________________________________
> > edk2-devel mailing list
> > edk2-devel@lists.01.org
> > https://lists.01.org/mailman/listinfo/edk2-devel
> >
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] GPT Shell Application/Library
2016-10-18 17:04 ` Carsey, Jaben
@ 2016-10-18 18:03 ` Shah, Tapan
2016-10-18 19:09 ` Vladimir Olovyannikov
0 siblings, 1 reply; 20+ messages in thread
From: Shah, Tapan @ 2016-10-18 18:03 UTC (permalink / raw)
To: Carsey, Jaben, Vladimir Olovyannikov, Michael Zimmermann
Cc: Ni, Ruiyu, Arshi, Shala, edk2-devel@lists.01.org, Laszlo Ersek
1. Create this new shared library in MdeModulePkg.
2. For parameters: Other than standard parameters defined in Shell specification I would suggest to follow single character flag where it makes sense (example: -d to delete, -l to list, -c to create etc.) and if more than one operation can be tied with one flag, then add individual value as a flag value. There are plenty of ShellPkg commands you can use as a reference.
-----Original Message-----
From: Carsey, Jaben [mailto:jaben.carsey@intel.com]
Sent: Tuesday, October 18, 2016 12:04 PM
To: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>; Shah, Tapan <tapandshah@hpe.com>; Michael Zimmermann <sigmaepsilon92@gmail.com>
Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Arshi, Shala <shala.arshi@intel.com>; edk2-devel@lists.01.org <edk2-devel@ml01.01.org>; Laszlo Ersek <lersek@redhat.com>; Carsey, Jaben <jaben.carsey@intel.com>
Subject: RE: [edk2] [PATCH] GPT Shell Application/Library
For the standards, I would try to use the UEFI Shell Spec for some parameters. For Example:
-v for verbose
-h for help
-sfo for standard format output
> -----Original Message-----
> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
> Vladimir Olovyannikov
> Sent: Tuesday, October 18, 2016 9:58 AM
> To: Shah, Tapan <tapandshah@hpe.com>; Carsey, Jaben
> <jaben.carsey@intel.com>; Michael Zimmermann
> <sigmaepsilon92@gmail.com>
> Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Arshi, Shala
> <shala.arshi@intel.com>; edk2-devel@lists.01.org
> <edk2-devel@ml01.01.org>; Laszlo Ersek <lersek@redhat.com>
> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> Importance: High
>
> Thank you all for comments,
>
> So to summarize the discussion:
>
> 1. I will create a Shell library which would perform all GPT operations.
> Part of PartitionDxe will also be in that library so PartitionDxe
> will be using it.
> The gpt Shell tool will also be using it.
> 2. Refactor the parameters of the gpt utility to make it similar to
> other existing Shell commands.
> BTW Is there any document describing Shell utility parameters'
> standards?
>
> Please let me know if you have other suggestions.
>
> Thank you,
> Vladimir
>
> -----Original Message-----
> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
> Shah, Tapan
> Sent: October-18-16 6:59 AM
> To: Carsey, Jaben; Vladimir Olovyannikov; Michael Zimmermann
> Cc: Ni, Ruiyu; Arshi, Shala; edk2-devel@lists.01.org; Laszlo Ersek
> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
>
> Thanks for the contribution Vladimir!
>
> Few comments:
> 1. It's better to refactor the code now before commit and move GPT
> related code outside ShellPkg and create a shared library.
> 2. CLI parameters of this utility are too complex and need to be
> refactored to make it similar to other existing Shell commands.
>
> Thanks,
> Tapan
>
> -----Original Message-----
> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
> Carsey, Jaben
> Sent: Monday, October 17, 2016 12:56 PM
> To: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>;
> Michael Zimmermann <sigmaepsilon92@gmail.com>
> Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Arshi, Shala
> <shala.arshi@intel.com>; edk2-devel@lists.01.org
> <edk2-devel@ml01.01.org>; Carsey, Jaben <jaben.carsey@intel.com>;
> Laszlo Ersek <lersek@redhat.com>
> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
>
> To the old question about license: I asked our people to check and was
> told that the license is compatible with our BSD and ok by Intel.
>
> To the technical content – I really like this idea of a shared library.
> That would be a great way to share code and not have as much duplicate.
>
> -Jaben
>
> From: Vladimir Olovyannikov
> [mailto:vladimir.olovyannikov@broadcom.com]
> Sent: Monday, October 17, 2016 10:52 AM
> To: Michael Zimmermann <sigmaepsilon92@gmail.com>
> Cc: Laszlo Ersek <lersek@redhat.com>; Carsey, Jaben
> <jaben.carsey@intel.com>; Ni, Ruiyu <ruiyu.ni@intel.com>;
> edk2-devel@lists.01.org <edk2-devel@ml01.01.org>
> Subject: RE: [edk2] [PATCH] GPT Shell Application/Library
> Importance: High
>
> Hi Michael,
> I am absolutely agree with your proposal.
>
> In the gpt Shell library/application I had to “borrow” some stuff from
> PartitionDxe.c to not reinvent a wheel.
> If the PartitionDxe maintainer agrees to have a separate library
> available for everybody, I would move all the GPT-related stuff from
> the GptWorker (and partially from the PartitionDxe itself) to that independent library.
> This could be a longer-term task.
> Right now I just wanted to share the tool which could be useful for
> anybody who would wish to manage GPT partitions (and/or do a FAT32
> format of either a disk or a GPT partition) from within the Shell.
> What do you think?
>
> Thank you,
> Vladimir
> From: Michael Zimmermann
> [mailto:sigmaepsilon92@gmail.com<mailto:sigmaepsilon92@gmail.com>]
> Sent: October-17-16 12:25 AM
> To: Vladimir Olovyannikov
> Cc: Laszlo Ersek; Jaben Carsey; Ni, Ruiyu;
> edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
>
> Hi,
>
> wouldn't it be better to make a generic gpt parsing library which is
> independent of the shell so both the shell and PartitionDxe can use it?
> It may also be useful for other applications which need additional
> information like the gpt partition names.
>
> Thanks
> Michael
>
> On Mon, Oct 17, 2016 at 8:49 AM, Vladimir Olovyannikov
> <vladimir.olovyannikov@broadcom.com<mailto:vladimir.olovyannikov@broa
> dcom.com>>
> wrote:
> Thank you Laszlo,
>
> Sorry, I missed the fields; it is my first contribution, I will add
> the required lines, review the source according to your comments and
> will resubmit the patch.
> So do you think the command should be _gpt instead of gpt? I was
> following TFTP and SF commands as a template.
>
> Thank you,
> Vladimir
>
> On Oct 16, 2016 1:05 PM, "Laszlo Ersek"
> <lersek@redhat.com<mailto:lersek@redhat.com>> wrote:
> >
> > On 10/16/16 07:23, Vladimir Olovyannikov wrote:
> > > This allows managing (create, delete, modify, fat format) of GPT
> > > partitions from within UEFI Shell.
> > > Syntax:
> > > gpt <command> [device_mapped_name] [parameters...] See usage
> > > examples in the .uni file
> > > ---
> > > .../Library/UefiShellGptCommandLib/FatFormat.c | 611 +++++++
> > > .../Library/UefiShellGptCommandLib/FatFormat.h | 111 ++
> > > .../Library/UefiShellGptCommandLib/GptWorker.c | 1902
> ++++++++++++++++++++
> > > .../Library/UefiShellGptCommandLib/GptWorker.h | 186 ++
> > > .../UefiShellGptCommandLib.c | 1135 ++++++++++++
> > > .../UefiShellGptCommandLib.inf | 79 +
> > > .../UefiShellGptCommandLib.uni | 117 ++
> > > ShellPkg/ShellPkg.dec | 1 +
> > > ShellPkg/ShellPkg.dsc | 4 +
> > > 9 files changed, 4146 insertions(+) create mode 100644
> > > ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> > > create mode 100644
> > > ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> > > create mode 100644
> > > ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> > > create mode 100644
> > > ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> > > create mode 100644
> ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> > > create mode 100644
> ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> > > create mode 100644
> ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
> >
> > This looks like a supremely welcome, long-awaited addition (latest
> > request:
> > <https://lists.01.org/pipermail/edk2-devel/2016-October/002667.html>
> > ), but it really needs your Signed-off-by, and the Contributed-under
> > line above it:
> >
> > ShellPkg/Contributions.txt
> >
> > I would also suggest (simply based on what I've seen elsewhere in
> > edk2) to keep the copyright notices tightly collected in the file
> > headings.
> >
> > Someone will have to go over all the licenses too -- does the
> > "Marvell BSD License Option" for example correspond to the 3-clause BSDL?
> >
> > On the technical side, I believe that as long as a shell command (or
> > a command option) is not standardized (in the shell spec), it
> > usually starts with an underscore (_), so as to prevent future name collisions.
> > (I could be wrong about this -- I now recall the TFTP command, which
> > is also not in the 2.2 spec.)
> >
> > Just my two cents.
> >
> > Thanks
> > Laszlo
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
> https://lists.01.org/mailman/listinfo/edk2-devel
>
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] GPT Shell Application/Library
2016-10-18 18:03 ` Vladimir Olovyannikov
@ 2016-10-18 18:12 ` Laszlo Ersek
0 siblings, 0 replies; 20+ messages in thread
From: Laszlo Ersek @ 2016-10-18 18:12 UTC (permalink / raw)
To: Vladimir Olovyannikov, Shah, Tapan, Carsey, Jaben,
Michael Zimmermann
Cc: Ni, Ruiyu, Arshi, Shala, edk2-devel@lists.01.org
On 10/18/16 20:03, Vladimir Olovyannikov wrote:
>> -----Original Message-----
>> From: Laszlo Ersek [mailto:lersek@redhat.com]
>> Sent: October-18-16 10:24 AM
>> To: Vladimir Olovyannikov; Shah, Tapan; Carsey, Jaben; Michael Zimmermann
>> Cc: Ni, Ruiyu; Arshi, Shala; edk2-devel@lists.01.org
>> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
>>
>> On 10/18/16 18:58, Vladimir Olovyannikov wrote:
>>> Thank you all for comments,
>>>
>>> So to summarize the discussion:
>>>
>>> 1. I will create a Shell library which would perform all GPT operations.
>>> Part of PartitionDxe will also be in that library so PartitionDxe
>>> will be using it.
>>> The gpt Shell tool will also be using it.
>>
>> I think you might want to place the library class header file, and the
>> library
>> instance, under MdeModulePkg. It's okay for the shell application (or
>> shell
>> libraries) to depend on library classes / library instances from
>> MdeModulePkg, but -- I think -- it's not okay for a driver in
>> MdeModulePkg,
>> such as PartitionDxe, to depend on a class + instance from under ShellPkg.
> Laszlo,
> I think PartitionDxe will depend on the GPT shared library (which will have
> nothing to do to the ShellPkg),
> as well as gpt tool (Shell library/application) will depend on that shared
> library as well to get information regarding partitions and
> to perform GPT management.
I understood that, yes. My point was the location of the new common
library (class header and instance both). You wrote
"I will create a Shell library ..."
which made me think you wanted to place the files under:
ShellPkg/Include/Library/...
ShellPkg/Library/...
which is not right in this instance. I suggested to place those files under
MdeModulePkg/Include/Library/...
MdeModulePkg/Library/...
Thanks!
Laszlo
>
> Thank you,
> Vladimir
>>
>> Thanks!
>> Laszlo
>>
>>> 2. Refactor the parameters of the gpt utility to make it similar to
>>> other existing Shell commands.
>>> BTW Is there any document describing Shell utility parameters'
>>> standards?
>>>
>>> Please let me know if you have other suggestions.
>>>
>>> Thank you,
>>> Vladimir
>>>
>>> -----Original Message-----
>>> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
>>> Shah, Tapan
>>> Sent: October-18-16 6:59 AM
>>> To: Carsey, Jaben; Vladimir Olovyannikov; Michael Zimmermann
>>> Cc: Ni, Ruiyu; Arshi, Shala; edk2-devel@lists.01.org; Laszlo Ersek
>>> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
>>>
>>> Thanks for the contribution Vladimir!
>>>
>>> Few comments:
>>> 1. It's better to refactor the code now before commit and move GPT
>>> related code outside ShellPkg and create a shared library.
>>> 2. CLI parameters of this utility are too complex and need to be
>>> refactored to make it similar to other existing Shell commands.
>>>
>>> Thanks,
>>> Tapan
>>>
>>> -----Original Message-----
>>> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
>>> Carsey, Jaben
>>> Sent: Monday, October 17, 2016 12:56 PM
>>> To: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>;
>>> Michael Zimmermann <sigmaepsilon92@gmail.com>
>>> Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Arshi, Shala
>>> <shala.arshi@intel.com>; edk2-devel@lists.01.org
>>> <edk2-devel@ml01.01.org>; Carsey, Jaben <jaben.carsey@intel.com>;
>>> Laszlo Ersek <lersek@redhat.com>
>>> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
>>>
>>> To the old question about license: I asked our people to check and was
>>> told that the license is compatible with our BSD and ok by Intel.
>>>
>>> To the technical content – I really like this idea of a shared library.
>>> That would be a great way to share code and not have as much duplicate.
>>>
>>> -Jaben
>>>
>>> From: Vladimir Olovyannikov
>>> [mailto:vladimir.olovyannikov@broadcom.com]
>>> Sent: Monday, October 17, 2016 10:52 AM
>>> To: Michael Zimmermann <sigmaepsilon92@gmail.com>
>>> Cc: Laszlo Ersek <lersek@redhat.com>; Carsey, Jaben
>>> <jaben.carsey@intel.com>; Ni, Ruiyu <ruiyu.ni@intel.com>;
>>> edk2-devel@lists.01.org <edk2-devel@ml01.01.org>
>>> Subject: RE: [edk2] [PATCH] GPT Shell Application/Library
>>> Importance: High
>>>
>>> Hi Michael,
>>> I am absolutely agree with your proposal.
>>>
>>> In the gpt Shell library/application I had to “borrow” some stuff from
>>> PartitionDxe.c to not reinvent a wheel.
>>> If the PartitionDxe maintainer agrees to have a separate library
>>> available for everybody, I would move all the GPT-related stuff from
>>> the GptWorker (and partially from the PartitionDxe itself) to that
>> independent library.
>>> This could be a longer-term task.
>>> Right now I just wanted to share the tool which could be useful for
>>> anybody who would wish to manage GPT partitions (and/or do a FAT32
>>> format of either a disk or a GPT partition) from within the Shell. What
>>> do
>> you think?
>>>
>>> Thank you,
>>> Vladimir
>>> From: Michael Zimmermann
>>> [mailto:sigmaepsilon92@gmail.com<mailto:sigmaepsilon92@gmail.com>]
>>> Sent: October-17-16 12:25 AM
>>> To: Vladimir Olovyannikov
>>> Cc: Laszlo Ersek; Jaben Carsey; Ni, Ruiyu;
>>> edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
>>> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
>>>
>>> Hi,
>>>
>>> wouldn't it be better to make a generic gpt parsing library which is
>>> independent of the shell so both the shell and PartitionDxe can use it?
>>> It may also be useful for other applications which need additional
>>> information like the gpt partition names.
>>>
>>> Thanks
>>> Michael
>>>
>>> On Mon, Oct 17, 2016 at 8:49 AM, Vladimir Olovyannikov
>>>
>> <vladimir.olovyannikov@broadcom.com<mailto:vladimir.olovyannikov@broa
>> d
>>> com.com>>
>>> wrote:
>>> Thank you Laszlo,
>>>
>>> Sorry, I missed the fields; it is my first contribution, I will add
>>> the required lines, review the source according to your comments and
>>> will resubmit the patch.
>>> So do you think the command should be _gpt instead of gpt? I was
>>> following TFTP and SF commands as a template.
>>>
>>> Thank you,
>>> Vladimir
>>>
>>> On Oct 16, 2016 1:05 PM, "Laszlo Ersek"
>>> <lersek@redhat.com<mailto:lersek@redhat.com>> wrote:
>>>>
>>>> On 10/16/16 07:23, Vladimir Olovyannikov wrote:
>>>>> This allows managing (create, delete, modify, fat format) of GPT
>>>>> partitions from within UEFI Shell.
>>>>> Syntax:
>>>>> gpt <command> [device_mapped_name] [parameters...] See usage
>>>>> examples in the .uni file
>>>>> ---
>>>>> .../Library/UefiShellGptCommandLib/FatFormat.c | 611 +++++++
>>>>> .../Library/UefiShellGptCommandLib/FatFormat.h | 111 ++
>>>>> .../Library/UefiShellGptCommandLib/GptWorker.c | 1902
>>> ++++++++++++++++++++
>>>>> .../Library/UefiShellGptCommandLib/GptWorker.h | 186 ++
>>>>> .../UefiShellGptCommandLib.c | 1135
>>>>> ++++++++++++
>>>>> .../UefiShellGptCommandLib.inf | 79 +
>>>>> .../UefiShellGptCommandLib.uni | 117 ++
>>>>> ShellPkg/ShellPkg.dec | 1 +
>>>>> ShellPkg/ShellPkg.dsc | 4 +
>>>>> 9 files changed, 4146 insertions(+) create mode 100644
>>>>> ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
>>>>> create mode 100644
>>>>> ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
>>>>> create mode 100644
>>>>> ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
>>>>> create mode 100644
>>>>> ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
>>>>> create mode 100644
>>> ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
>>>>> create mode 100644
>>> ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
>>>>> create mode 100644
>>> ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
>>>>
>>>> This looks like a supremely welcome, long-awaited addition (latest
>>>> request:
>>>> <https://lists.01.org/pipermail/edk2-devel/2016-October/002667.html>)
>>>> , but it really needs your Signed-off-by, and the Contributed-under
>>>> line above it:
>>>>
>>>> ShellPkg/Contributions.txt
>>>>
>>>> I would also suggest (simply based on what I've seen elsewhere in
>>>> edk2) to keep the copyright notices tightly collected in the file
>>>> headings.
>>>>
>>>> Someone will have to go over all the licenses too -- does the
>>>> "Marvell BSD License Option" for example correspond to the 3-clause
>> BSDL?
>>>>
>>>> On the technical side, I believe that as long as a shell command (or
>>>> a command option) is not standardized (in the shell spec), it usually
>>>> starts with an underscore (_), so as to prevent future name collisions.
>>>> (I could be wrong about this -- I now recall the TFTP command, which
>>>> is also not in the 2.2 spec.)
>>>>
>>>> Just my two cents.
>>>>
>>>> Thanks
>>>> Laszlo
>>> _______________________________________________
>>> edk2-devel mailing list
>>> edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
>>> https://lists.01.org/mailman/listinfo/edk2-devel
>>>
>>> _______________________________________________
>>> edk2-devel mailing list
>>> edk2-devel@lists.01.org
>>> https://lists.01.org/mailman/listinfo/edk2-devel
>>> _______________________________________________
>>> edk2-devel mailing list
>>> edk2-devel@lists.01.org
>>> https://lists.01.org/mailman/listinfo/edk2-devel
>>>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] GPT Shell Application/Library
2016-10-18 18:03 ` Shah, Tapan
@ 2016-10-18 19:09 ` Vladimir Olovyannikov
0 siblings, 0 replies; 20+ messages in thread
From: Vladimir Olovyannikov @ 2016-10-18 19:09 UTC (permalink / raw)
To: Shah, Tapan, Carsey, Jaben, Michael Zimmermann
Cc: Ni, Ruiyu, Arshi, Shala, edk2-devel@lists.01.org, Laszlo Ersek
OK,
Thank you for advice.
> -----Original Message-----
> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
> Shah, Tapan
> Sent: October-18-16 11:04 AM
> To: Carsey, Jaben; Vladimir Olovyannikov; Michael Zimmermann
> Cc: Ni, Ruiyu; Arshi, Shala; edk2-devel@lists.01.org; Laszlo Ersek
> Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
>
> 1. Create this new shared library in MdeModulePkg.
> 2. For parameters: Other than standard parameters defined in Shell
> specification I would suggest to follow single character flag where it
> makes
> sense (example: -d to delete, -l to list, -c to create etc.) and if more
> than one
> operation can be tied with one flag, then add individual value as a flag
> value.
> There are plenty of ShellPkg commands you can use as a reference.
>
> -----Original Message-----
> From: Carsey, Jaben [mailto:jaben.carsey@intel.com]
> Sent: Tuesday, October 18, 2016 12:04 PM
> To: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>; Shah,
> Tapan <tapandshah@hpe.com>; Michael Zimmermann
> <sigmaepsilon92@gmail.com>
> Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Arshi, Shala <shala.arshi@intel.com>;
> edk2-devel@lists.01.org <edk2-devel@ml01.01.org>; Laszlo Ersek
> <lersek@redhat.com>; Carsey, Jaben <jaben.carsey@intel.com>
> Subject: RE: [edk2] [PATCH] GPT Shell Application/Library
>
> For the standards, I would try to use the UEFI Shell Spec for some
> parameters. For Example:
> -v for verbose
> -h for help
> -sfo for standard format output
>
> > -----Original Message-----
> > From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
> > Vladimir Olovyannikov
> > Sent: Tuesday, October 18, 2016 9:58 AM
> > To: Shah, Tapan <tapandshah@hpe.com>; Carsey, Jaben
> > <jaben.carsey@intel.com>; Michael Zimmermann
> > <sigmaepsilon92@gmail.com>
> > Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Arshi, Shala
> > <shala.arshi@intel.com>; edk2-devel@lists.01.org
> > <edk2-devel@ml01.01.org>; Laszlo Ersek <lersek@redhat.com>
> > Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> > Importance: High
> >
> > Thank you all for comments,
> >
> > So to summarize the discussion:
> >
> > 1. I will create a Shell library which would perform all GPT operations.
> > Part of PartitionDxe will also be in that library so PartitionDxe
> > will be using it.
> > The gpt Shell tool will also be using it.
> > 2. Refactor the parameters of the gpt utility to make it similar to
> > other existing Shell commands.
> > BTW Is there any document describing Shell utility parameters'
> > standards?
> >
> > Please let me know if you have other suggestions.
> >
> > Thank you,
> > Vladimir
> >
> > -----Original Message-----
> > From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
> > Shah, Tapan
> > Sent: October-18-16 6:59 AM
> > To: Carsey, Jaben; Vladimir Olovyannikov; Michael Zimmermann
> > Cc: Ni, Ruiyu; Arshi, Shala; edk2-devel@lists.01.org; Laszlo Ersek
> > Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> >
> > Thanks for the contribution Vladimir!
> >
> > Few comments:
> > 1. It's better to refactor the code now before commit and move GPT
> > related code outside ShellPkg and create a shared library.
> > 2. CLI parameters of this utility are too complex and need to be
> > refactored to make it similar to other existing Shell commands.
> >
> > Thanks,
> > Tapan
> >
> > -----Original Message-----
> > From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
> > Carsey, Jaben
> > Sent: Monday, October 17, 2016 12:56 PM
> > To: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>;
> > Michael Zimmermann <sigmaepsilon92@gmail.com>
> > Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Arshi, Shala
> > <shala.arshi@intel.com>; edk2-devel@lists.01.org
> > <edk2-devel@ml01.01.org>; Carsey, Jaben <jaben.carsey@intel.com>;
> > Laszlo Ersek <lersek@redhat.com>
> > Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> >
> > To the old question about license: I asked our people to check and was
> > told that the license is compatible with our BSD and ok by Intel.
> >
> > To the technical content – I really like this idea of a shared library.
> > That would be a great way to share code and not have as much duplicate.
> >
> > -Jaben
> >
> > From: Vladimir Olovyannikov
> > [mailto:vladimir.olovyannikov@broadcom.com]
> > Sent: Monday, October 17, 2016 10:52 AM
> > To: Michael Zimmermann <sigmaepsilon92@gmail.com>
> > Cc: Laszlo Ersek <lersek@redhat.com>; Carsey, Jaben
> > <jaben.carsey@intel.com>; Ni, Ruiyu <ruiyu.ni@intel.com>;
> > edk2-devel@lists.01.org <edk2-devel@ml01.01.org>
> > Subject: RE: [edk2] [PATCH] GPT Shell Application/Library
> > Importance: High
> >
> > Hi Michael,
> > I am absolutely agree with your proposal.
> >
> > In the gpt Shell library/application I had to “borrow” some stuff from
> > PartitionDxe.c to not reinvent a wheel.
> > If the PartitionDxe maintainer agrees to have a separate library
> > available for everybody, I would move all the GPT-related stuff from
> > the GptWorker (and partially from the PartitionDxe itself) to that
> independent library.
> > This could be a longer-term task.
> > Right now I just wanted to share the tool which could be useful for
> > anybody who would wish to manage GPT partitions (and/or do a FAT32
> > format of either a disk or a GPT partition) from within the Shell.
> > What do you think?
> >
> > Thank you,
> > Vladimir
> > From: Michael Zimmermann
> > [mailto:sigmaepsilon92@gmail.com<mailto:sigmaepsilon92@gmail.com>]
> > Sent: October-17-16 12:25 AM
> > To: Vladimir Olovyannikov
> > Cc: Laszlo Ersek; Jaben Carsey; Ni, Ruiyu;
> > edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
> > Subject: Re: [edk2] [PATCH] GPT Shell Application/Library
> >
> > Hi,
> >
> > wouldn't it be better to make a generic gpt parsing library which is
> > independent of the shell so both the shell and PartitionDxe can use it?
> > It may also be useful for other applications which need additional
> > information like the gpt partition names.
> >
> > Thanks
> > Michael
> >
> > On Mon, Oct 17, 2016 at 8:49 AM, Vladimir Olovyannikov
> >
> <vladimir.olovyannikov@broadcom.com<mailto:vladimir.olovyannikov@broa
> > dcom.com>>
> > wrote:
> > Thank you Laszlo,
> >
> > Sorry, I missed the fields; it is my first contribution, I will add
> > the required lines, review the source according to your comments and
> > will resubmit the patch.
> > So do you think the command should be _gpt instead of gpt? I was
> > following TFTP and SF commands as a template.
> >
> > Thank you,
> > Vladimir
> >
> > On Oct 16, 2016 1:05 PM, "Laszlo Ersek"
> > <lersek@redhat.com<mailto:lersek@redhat.com>> wrote:
> > >
> > > On 10/16/16 07:23, Vladimir Olovyannikov wrote:
> > > > This allows managing (create, delete, modify, fat format) of GPT
> > > > partitions from within UEFI Shell.
> > > > Syntax:
> > > > gpt <command> [device_mapped_name] [parameters...] See usage
> > > > examples in the .uni file
> > > > ---
> > > > .../Library/UefiShellGptCommandLib/FatFormat.c | 611 +++++++
> > > > .../Library/UefiShellGptCommandLib/FatFormat.h | 111 ++
> > > > .../Library/UefiShellGptCommandLib/GptWorker.c | 1902
> > ++++++++++++++++++++
> > > > .../Library/UefiShellGptCommandLib/GptWorker.h | 186 ++
> > > > .../UefiShellGptCommandLib.c | 1135
> > > > ++++++++++++
> > > > .../UefiShellGptCommandLib.inf | 79 +
> > > > .../UefiShellGptCommandLib.uni | 117 ++
> > > > ShellPkg/ShellPkg.dec | 1 +
> > > > ShellPkg/ShellPkg.dsc | 4 +
> > > > 9 files changed, 4146 insertions(+) create mode 100644
> > > > ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c
> > > > create mode 100644
> > > > ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h
> > > > create mode 100644
> > > > ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c
> > > > create mode 100644
> > > > ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h
> > > > create mode 100644
> > ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c
> > > > create mode 100644
> > ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf
> > > > create mode 100644
> > ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni
> > >
> > > This looks like a supremely welcome, long-awaited addition (latest
> > > request:
> > > <https://lists.01.org/pipermail/edk2-devel/2016-October/002667.html>
> > > ), but it really needs your Signed-off-by, and the Contributed-under
> > > line above it:
> > >
> > > ShellPkg/Contributions.txt
> > >
> > > I would also suggest (simply based on what I've seen elsewhere in
> > > edk2) to keep the copyright notices tightly collected in the file
> > > headings.
> > >
> > > Someone will have to go over all the licenses too -- does the
> > > "Marvell BSD License Option" for example correspond to the 3-clause
> BSDL?
> > >
> > > On the technical side, I believe that as long as a shell command (or
> > > a command option) is not standardized (in the shell spec), it
> > > usually starts with an underscore (_), so as to prevent future name
> collisions.
> > > (I could be wrong about this -- I now recall the TFTP command, which
> > > is also not in the 2.2 spec.)
> > >
> > > Just my two cents.
> > >
> > > Thanks
> > > Laszlo
> > _______________________________________________
> > edk2-devel mailing list
> > edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
> > https://lists.01.org/mailman/listinfo/edk2-devel
> >
> > _______________________________________________
> > edk2-devel mailing list
> > edk2-devel@lists.01.org
> > https://lists.01.org/mailman/listinfo/edk2-devel
> > _______________________________________________
> > edk2-devel mailing list
> > edk2-devel@lists.01.org
> > https://lists.01.org/mailman/listinfo/edk2-devel
> > _______________________________________________
> > edk2-devel mailing list
> > edk2-devel@lists.01.org
> > https://lists.01.org/mailman/listinfo/edk2-devel
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel
^ permalink raw reply [flat|nested] 20+ messages in thread
end of thread, other threads:[~2016-10-18 19:09 UTC | newest]
Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-10-16 5:23 [PATCH] GPT Shell Application/Library Vladimir Olovyannikov
2016-10-16 20:05 ` Laszlo Ersek
[not found] ` <CACmgjazi_K4Qo5=TeO_tCGK2cB26d0rqOEZh6TthP1UYbo6J6w@mail.gmail.com>
[not found] ` <CACmgjaziUEF2EsSn73HY5JvL2rmRWrXS+rHMtOQ1HaRwPpXS+g@mail.gmail.com>
2016-10-17 6:49 ` Vladimir Olovyannikov
2016-10-17 7:24 ` Michael Zimmermann
2016-10-17 17:52 ` Vladimir Olovyannikov
2016-10-17 17:56 ` Carsey, Jaben
2016-10-18 13:59 ` Shah, Tapan
2016-10-18 16:58 ` Vladimir Olovyannikov
2016-10-18 17:04 ` Carsey, Jaben
2016-10-18 18:03 ` Shah, Tapan
2016-10-18 19:09 ` Vladimir Olovyannikov
2016-10-18 17:23 ` Laszlo Ersek
2016-10-18 18:03 ` Vladimir Olovyannikov
2016-10-18 18:12 ` Laszlo Ersek
2016-10-17 9:43 ` Laszlo Ersek
2016-10-17 16:35 ` Carsey, Jaben
2016-10-18 1:45 ` Ni, Ruiyu
2016-10-18 1:48 ` Tim Lewis
2016-10-18 1:55 ` Ni, Ruiyu
2016-10-18 2:59 ` Carsey, Jaben
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox