From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) (using TLSv1 with cipher CAMELLIA256-SHA (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 344DC1A1E31 for ; Thu, 20 Oct 2016 13:48:52 -0700 (PDT) Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga101.fm.intel.com with ESMTP; 20 Oct 2016 13:48:51 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.31,372,1473145200"; d="scan'208";a="182055446" Received: from fmsmsx108.amr.corp.intel.com ([10.18.124.206]) by fmsmga004.fm.intel.com with ESMTP; 20 Oct 2016 13:48:51 -0700 Received: from fmsmsx119.amr.corp.intel.com (10.18.124.207) by FMSMSX108.amr.corp.intel.com (10.18.124.206) with Microsoft SMTP Server (TLS) id 14.3.248.2; Thu, 20 Oct 2016 13:48:51 -0700 Received: from fmsmsx103.amr.corp.intel.com ([169.254.2.170]) by FMSMSX119.amr.corp.intel.com ([169.254.14.3]) with mapi id 14.03.0248.002; Thu, 20 Oct 2016 13:48:51 -0700 From: "Carsey, Jaben" To: Vladimir Olovyannikov , "edk2-devel@lists.01.org" , "Shah, Tapan (tapandshah@hpe.com)" , "Ni, Ruiyu" CC: "Ni, Ruiyu" , "Carsey, Jaben" Thread-Topic: [edk2] [PATCH] ShellPkg: Added GPT Shell Application/Library Thread-Index: AQHSKnHFLDOueW7XaEuKLyjpEYPBR6Cx0axw Date: Thu, 20 Oct 2016 20:48:50 +0000 Message-ID: References: <1476927117-4521-1-git-send-email-vladimir.olovyannikov@broadcom.com> In-Reply-To: <1476927117-4521-1-git-send-email-vladimir.olovyannikov@broadcom.com> Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-titus-metadata-40: eyJDYXRlZ29yeUxhYmVscyI6IiIsIk1ldGFkYXRhIjp7Im5zIjoiaHR0cDpcL1wvd3d3LnRpdHVzLmNvbVwvbnNcL0ludGVsMyIsImlkIjoiZDgyMjJhMDItMjdkYy00YTA4LTlhODYtYzQyNzdhOWM1Zjc5IiwicHJvcHMiOlt7Im4iOiJDVFBDbGFzc2lmaWNhdGlvbiIsInZhbHMiOlt7InZhbHVlIjoiQ1RQX0lDIn1dfV19LCJTdWJqZWN0TGFiZWxzIjpbXSwiVE1DVmVyc2lvbiI6IjE1LjkuNi42IiwiVHJ1c3RlZExhYmVsSGFzaCI6InpXeFBSelU3NFlWZzVkUENkNGl1cUlyN1BhNW9CeEEzb2ErXC90QUdUWW84PSJ9 x-ctpclassification: CTP_IC x-originating-ip: [10.1.200.107] MIME-Version: 1.0 Subject: Re: [PATCH] ShellPkg: Added GPT Shell Application/Library X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 20 Oct 2016 20:48:52 -0000 Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Tapan & Ray, Any thoughts on this? Reviewed-by: Jaben Carsey > -----Original Message----- > From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of > Vladimir Olovyannikov > Sent: Wednesday, October 19, 2016 6:32 PM > To: edk2-devel@lists.01.org > Cc: Carsey, Jaben ; Ni, Ruiyu > ; Vladimir Olovyannikov > > Subject: [edk2] [PATCH] ShellPkg: Added GPT Shell Application/Library > Importance: High >=20 > Contributed-under: TianoCore Contribution Agreement 1.0 > Signed-off-by: Vladimir Olovyannikov > >=20 > This tool allows managing (create, delete, modify, fat format) of GPT > partitions from within UEFI Shell. See usage examples in the .uni file >=20 > Hope that this tool can be useful for anybody wishing to manipulate GPT > partitions from within the UEFI Shell. > I am planning to create a shared library for GPT-related activities. > But because of time shortage this could happen much later than planned. >=20 > This is the final version of the tool which we are going to use. > If anybody wants to use this tool and create a separate library please > by all means go ahead. > --- > .../Library/UefiShellGptCommandLib/FatFormat.c | 693 +++++++ > .../Library/UefiShellGptCommandLib/FatFormat.h | 115 ++ > .../Library/UefiShellGptCommandLib/GptWorker.c | 1922 > ++++++++++++++++++++ > .../Library/UefiShellGptCommandLib/GptWorker.h | 188 ++ > .../UefiShellGptCommandLib.c | 1267 +++++++++++++ > .../UefiShellGptCommandLib.inf | 74 + > .../UefiShellGptCommandLib.uni | 113 ++ > ShellPkg/ShellPkg.dec | 1 + > ShellPkg/ShellPkg.dsc | 4 + > 9 files changed, 4377 insertions(+) > create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c > create mode 100644 > ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h > create mode 100644 > ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c > create mode 100644 > ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h > create mode 100644 > ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c > create mode 100644 > ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf > create mode 100644 > ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni >=20 > diff --git a/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c > b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c > new file mode 100644 > index 000000000000..dea8505c49ff > --- /dev/null > +++ b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c > @@ -0,0 +1,693 @@ > +/** @file > + > + Copyright (c) 2003 - 2012, Rob Riglar, Ultra-Embedded.com. All rights > reserved
> + Copyright (c) 2016, Broadcom. All rights reserved
> + > + This program and the accompanying materials > + are licensed and made available under the terms and conditions of the = BSD > License > + which accompanies this distribution. The full text of the license may= be > found at > + http://opensource.org/licenses/bsd-license.php > + > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" > BASIS, > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER > EXPRESS OR IMPLIED. > + > +**/ > + > +#include "FatFormat.h" > + > +//----------------------------------------------------------------------= ------- > +// Tables > +//----------------------------------------------------------------------= ------- > +typedef struct > +{ > + UINT64 Sectors; > + UINT8 SectorsPerCluster; > +} SectorsPerClusterTable; > + > +STATIC SectorsPerClusterTable ClusterSizeTable16[] =3D > +{ > + { 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[] =3D > +{ > + { 532480, 1 }, // 260MB - 512b > + { 16777216, 8 }, // 8GB - 4K > + { 33554432, 16 }, // 16GB - 8K > + { 67108864, 32 }, // 32GB - 16K > + { 0xFFFFFFFF, 64 }, // >32GB - 32K > + { 0, 0 } // Invalid > +}; > + > +/** > + Calculates LBA corresponding to the cluster number. > + > + @param FS Pointer to the FAT_FS structure > + @param ClusterNumber Cluster number to get LBA for > + > + @return EFI_LBA LBA corresponding to the given cluster number > +**/ > +STATIC > +EFI_LBA LbaOfCluster ( > + IN FATFS *Fs, > + IN UINT64 ClusterNumber > + ) > +{ > + if (Fs->FatType =3D=3D FAT_TYPE_16) > + return (Fs->ClusterBeginLba + > + (Fs->RootEntryCount * 32 / FAT_SECTOR_SIZE) + > + ((ClusterNumber - 2) * Fs->SectorsPerCluster)); > + else > + return ((Fs->ClusterBeginLba + > + ((ClusterNumber - 2) * Fs->SectorsPerCluster))); > +} > + > +/** > + Calculates the cluster size to be used. > + > + @param Sectors Requested number of sectors > + @param IsFat32 Whether FAT32 is to be used > + > + @return UINT8 Cluster size from the table > + > +**/ > +STATIC > +UINT8 CalcClusterSize ( > + IN UINTN Sectors, > + IN BOOLEAN IsFat32) > +{ > + UINTN Index; > + > + if (!IsFat32) { > + for (Index =3D 0; ClusterSizeTable16[Index].SectorsPerCluster !=3D 0= ; Index++) > + if (Sectors <=3D ClusterSizeTable16[Index].Sectors) > + return ClusterSizeTable16[Index].SectorsPerCluster; > + } else { > + for (Index =3D 0; ClusterSizeTable32[Index].SectorsPerCluster !=3D 0= ; Index++) > + if (Sectors <=3D ClusterSizeTable32[Index].Sectors) > + return ClusterSizeTable32[Index].SectorsPerCluster; > + } > + > + return 0; > +} > + > +/** > + Erase a number of sectors. > + > + @param FS Pointer to the FAT_FS structure > + @param LBA LBA to erase sectors in > + @param Count Number of sectors to be erased > + > + @return EFI_SUCCESS Operation succeeded > + @return other Failed to erase fat sectors > + > +**/ > +STATIC > +EFI_STATUS > +EraseSectors ( > + IN FATFS *Fs, > + IN EFI_LBA Lba, > + IN UINTN Count > + ) > +{ > + UINTN Index; > + EFI_STATUS Status; > + > + // Zero Sector first > + ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE); > + > + for (Index =3D 0; Index < Count; Index++) > + Status =3D Fs->DiskIo->WriteDisk ( > + Fs->DiskIo, Fs->BlockIo->Media->MediaId, > + MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) + > + MultU64x32 ((Lba + Index), FAT_SECTOR_SIZE), > + FAT_SECTOR_SIZE, Fs->CurrentSector.Sector); > + > + return Status; > +} > + > +/** > + Create the boot sector. > + > + @param Fs Pointer to the FAT_FS structure > + @param BootSectorLba LBA of the boot sector > + @param VolSectors Number of sectors in the volume > + @param Name Volume label > + @param IsFat32 Whether it is a FAT32 boot sector > + > + @return EFI_SUCCESS Boot sector was created successfully > + @return other Failed to create the boot sector > + > +**/ > +STATIC > +EFI_STATUS > +CreateBootSector ( > + IN FATFS *Fs, > + IN EFI_LBA BootSectorLba, > + IN UINT64 VolSectors, > + IN CONST CHAR8 *Name, > + IN BOOLEAN IsFat32 > + ) > +{ > + UINTN TotalClusters; > + UINTN Index; > + EFI_STATUS Status; > + > + // Zero Sector initially > + ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE); > + > + // OEM Name & Jump Code > + Fs->CurrentSector.Sector[0] =3D 0xEB; > + Fs->CurrentSector.Sector[1] =3D 0x3C; > + Fs->CurrentSector.Sector[2] =3D 0x90; > + Fs->CurrentSector.Sector[3] =3D 0x4D; > + Fs->CurrentSector.Sector[4] =3D 0x53; > + Fs->CurrentSector.Sector[5] =3D 0x44; > + Fs->CurrentSector.Sector[6] =3D 0x4F; > + Fs->CurrentSector.Sector[7] =3D 0x53; > + Fs->CurrentSector.Sector[8] =3D 0x35; > + Fs->CurrentSector.Sector[9] =3D 0x2E; > + Fs->CurrentSector.Sector[10] =3D 0x30; > + > + // Bytes per Sector > + Fs->CurrentSector.Sector[11] =3D (FAT_SECTOR_SIZE >> 0) & 0xFF; > + Fs->CurrentSector.Sector[12] =3D (FAT_SECTOR_SIZE >> 8) & 0xFF; > + > + // Get sectors per cluster size for the disk > + Fs->SectorsPerCluster =3D CalcClusterSize (VolSectors, IsFat32); > + if (!Fs->SectorsPerCluster) > + return 0; // Invalid disk size > + > + // Sectors per cluster > + Fs->CurrentSector.Sector[13] =3D Fs->SectorsPerCluster; > + > + // Reserved Sectors > + if (!IsFat32) > + Fs->ReservedSectors =3D 8; > + else > + Fs->ReservedSectors =3D 32; > + Fs->CurrentSector.Sector[14] =3D (Fs->ReservedSectors >> 0) & 0xFF; > + Fs->CurrentSector.Sector[15] =3D (Fs->ReservedSectors >> 8) & 0xFF; > + > + // Number of FATS > + Fs->NumOfFats =3D 2; > + Fs->CurrentSector.Sector[16] =3D Fs->NumOfFats; > + > + // Max entries in root dir (FAT16 only) > + if (!IsFat32) { > + Fs->RootEntryCount =3D 512; > + Fs->CurrentSector.Sector[17] =3D (Fs->RootEntryCount >> 0) & 0xFF; > + Fs->CurrentSector.Sector[18] =3D (Fs->RootEntryCount >> 8) & 0xFF; > + } else { > + Fs->RootEntryCount =3D 0; > + Fs->CurrentSector.Sector[17] =3D 0; > + Fs->CurrentSector.Sector[18] =3D 0; > + } > + > + // [FAT16] Total sectors (use FAT32 count instead) > + Fs->CurrentSector.Sector[19] =3D 0x00; > + Fs->CurrentSector.Sector[20] =3D 0x00; > + > + // Media type > + Fs->CurrentSector.Sector[21] =3D 0xF8; > + > + > + // FAT16 BS Details > + if (!IsFat32) { > + // Count of sectors used by the FAT table (FAT16 only) > + TotalClusters =3D (VolSectors / Fs->SectorsPerCluster) + 1; > + Fs->FatSectors =3D (TotalClusters / (FAT_SECTOR_SIZE / 2)) + 1; > + Fs->CurrentSector.Sector[22] =3D (UINT8)((Fs->FatSectors >> 0) & 0xF= F); > + Fs->CurrentSector.Sector[23] =3D (UINT8)((Fs->FatSectors >> 8) & 0xF= F); > + > + // Sectors per track > + Fs->CurrentSector.Sector[24] =3D 0x00; > + Fs->CurrentSector.Sector[25] =3D 0x00; > + > + // Heads > + Fs->CurrentSector.Sector[26] =3D 0x00; > + Fs->CurrentSector.Sector[27] =3D 0x00; > + > + // Hidden sectors > + Fs->CurrentSector.Sector[28] =3D 0x20; > + Fs->CurrentSector.Sector[29] =3D 0x00; > + Fs->CurrentSector.Sector[30] =3D 0x00; > + Fs->CurrentSector.Sector[31] =3D 0x00; > + > + // Total sectors for this volume > + Fs->CurrentSector.Sector[32] =3D (UINT8)((VolSectors >> 0) & 0xFF); > + Fs->CurrentSector.Sector[33] =3D (UINT8)((VolSectors >> 8) & 0xFF); > + Fs->CurrentSector.Sector[34] =3D (UINT8)((VolSectors >> 16) & 0xFF); > + Fs->CurrentSector.Sector[35] =3D (UINT8)((VolSectors >> 24) & 0xFF); > + > + // Drive number > + Fs->CurrentSector.Sector[36] =3D 0x00; > + > + // Reserved > + Fs->CurrentSector.Sector[37] =3D 0x00; > + > + // Boot signature > + Fs->CurrentSector.Sector[38] =3D 0x29; > + > + // Volume ID > + Fs->CurrentSector.Sector[39] =3D 0x12; > + Fs->CurrentSector.Sector[40] =3D 0x34; > + Fs->CurrentSector.Sector[41] =3D 0x56; > + Fs->CurrentSector.Sector[42] =3D 0x78; > + > + // Volume name > + for (Index =3D 0; Index < 11; Index++) { > + if (Index < AsciiStrLen (Name)) > + Fs->CurrentSector.Sector[Index + 43] =3D Name[Index]; > + else > + Fs->CurrentSector.Sector[Index + 43] =3D ' '; > + } > + > + // File sys type > + Fs->CurrentSector.Sector[54] =3D 'F'; > + Fs->CurrentSector.Sector[55] =3D 'A'; > + Fs->CurrentSector.Sector[56] =3D 'T'; > + Fs->CurrentSector.Sector[57] =3D '1'; > + Fs->CurrentSector.Sector[58] =3D '6'; > + Fs->CurrentSector.Sector[59] =3D ' '; > + Fs->CurrentSector.Sector[60] =3D ' '; > + Fs->CurrentSector.Sector[61] =3D ' '; > + > + // Signature > + Fs->CurrentSector.Sector[510] =3D 0x55; > + Fs->CurrentSector.Sector[511] =3D 0xAA; > + } > + // FAT32 BS Details > + else { > + // Count of sectors used by the FAT table (FAT16 only) > + Fs->CurrentSector.Sector[22] =3D 0; > + Fs->CurrentSector.Sector[23] =3D 0; > + > + // Sectors per track (default) > + Fs->CurrentSector.Sector[24] =3D 0x3F; > + Fs->CurrentSector.Sector[25] =3D 0x00; > + > + // Heads (default) > + Fs->CurrentSector.Sector[26] =3D 0xFF; > + Fs->CurrentSector.Sector[27] =3D 0x00; > + > + // Hidden sectors > + Fs->CurrentSector.Sector[28] =3D 0x00; > + Fs->CurrentSector.Sector[29] =3D 0x00; > + Fs->CurrentSector.Sector[30] =3D 0x00; > + Fs->CurrentSector.Sector[31] =3D 0x00; > + > + // Total sectors for this volume > + Fs->CurrentSector.Sector[32] =3D (UINT8)((VolSectors >> 0) & 0xFF); > + Fs->CurrentSector.Sector[33] =3D (UINT8)((VolSectors >> 8) & 0xFF); > + Fs->CurrentSector.Sector[34] =3D (UINT8)((VolSectors >> 16) & 0xFF); > + Fs->CurrentSector.Sector[35] =3D (UINT8)((VolSectors >> 24) & 0xFF); > + > + TotalClusters =3D (VolSectors / Fs->SectorsPerCluster) + 1; > + Fs->FatSectors =3D (TotalClusters / (FAT_SECTOR_SIZE / 4)) + 1; > + > + // BPB_FATSz32 > + Fs->CurrentSector.Sector[36] =3D (UINT8)((Fs->FatSectors >> 0) & 0xF= F); > + Fs->CurrentSector.Sector[37] =3D (UINT8)((Fs->FatSectors >> 8) & 0xF= F); > + Fs->CurrentSector.Sector[38] =3D (UINT8)((Fs->FatSectors >> 16) & 0x= FF); > + Fs->CurrentSector.Sector[39] =3D (UINT8)((Fs->FatSectors >> 24) & 0x= FF); > + > + // BPB_ExtFlags > + Fs->CurrentSector.Sector[40] =3D 0; > + Fs->CurrentSector.Sector[41] =3D 0; > + > + // BPB_FSVer > + Fs->CurrentSector.Sector[42] =3D 0; > + Fs->CurrentSector.Sector[43] =3D 0; > + > + // BPB_RootClus > + Fs->CurrentSector.Sector[44] =3D (UINT8)((Fs->RootdirFirstCluster >>= 0) & > 0xFF); > + Fs->CurrentSector.Sector[45] =3D (UINT8)((Fs->RootdirFirstCluster >>= 8) & > 0xFF); > + Fs->CurrentSector.Sector[46] =3D (UINT8)((Fs->RootdirFirstCluster >>= 16) & > 0xFF); > + Fs->CurrentSector.Sector[47] =3D (UINT8)((Fs->RootdirFirstCluster >>= 24) & > 0xFF); > + > + // BPB_FSInfo > + Fs->CurrentSector.Sector[48] =3D (UINT8)((Fs->FsInfoSector >> 0) & 0= xFF); > + Fs->CurrentSector.Sector[49] =3D (UINT8)((Fs->FsInfoSector >> 8) & 0= xFF); > + > + // BPB_BkBootSec > + Fs->CurrentSector.Sector[50] =3D 6; > + Fs->CurrentSector.Sector[51] =3D 0; > + > + // Drive number > + Fs->CurrentSector.Sector[64] =3D 0x00; > + > + // Boot signature > + Fs->CurrentSector.Sector[66] =3D 0x29; > + > + // Volume ID > + Fs->CurrentSector.Sector[67] =3D 0x12; > + Fs->CurrentSector.Sector[68] =3D 0x34; > + Fs->CurrentSector.Sector[69] =3D 0x56; > + Fs->CurrentSector.Sector[70] =3D 0x78; > + > + // Volume name > + for (Index =3D 0; Index < 11; Index++) { > + if (Index < (int)AsciiStrLen (Name)) > + Fs->CurrentSector.Sector[Index + 71] =3D Name[Index]; > + else > + Fs->CurrentSector.Sector[Index + 71] =3D ' '; > + } > + > + // File sys type > + Fs->CurrentSector.Sector[82] =3D 'F'; > + Fs->CurrentSector.Sector[83] =3D 'A'; > + Fs->CurrentSector.Sector[84] =3D 'T'; > + Fs->CurrentSector.Sector[85] =3D '3'; > + Fs->CurrentSector.Sector[86] =3D '2'; > + Fs->CurrentSector.Sector[87] =3D ' '; > + Fs->CurrentSector.Sector[88] =3D ' '; > + Fs->CurrentSector.Sector[89] =3D ' '; > + > + // Signature > + Fs->CurrentSector.Sector[510] =3D 0x55; > + Fs->CurrentSector.Sector[511] =3D 0xAA; > + } > + > + Status =3D Fs->DiskIo->WriteDisk ( > + Fs->DiskIo, Fs->BlockIo->Media->MediaId, > + MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) + > + MultU64x32 (Fs->FatBeginLba, FAT_SECTOR_SIZE), > + FAT_SECTOR_SIZE, > + Fs->CurrentSector.Sector); > + > + return Status; > +} > +/** > + Create the FSinfo sector for FAT32 > + > + @param Fs Pointer to the FAT_FS structure > + @param SectorLba LBA of the FSInfo sector > + > + @return EFI_SUCCESS FAT32 FSInfo sector successfully created > + @return other Failed to create the FAT32 FSInfo sector > + > +**/ > +STATIC > +EFI_STATUS > +CreateFsinfoSector ( > + IN FATFS *Fs, > + IN EFI_LBA SectorLba > + ) > +{ > + EFI_STATUS Status; > + > + // Zero Sector initially > + ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE); > + > + // FSI_LeadSig > + Fs->CurrentSector.Sector[0] =3D 0x52; > + Fs->CurrentSector.Sector[1] =3D 0x52; > + Fs->CurrentSector.Sector[2] =3D 0x61; > + Fs->CurrentSector.Sector[3] =3D 0x41; > + > + // FSI_StrucSig > + Fs->CurrentSector.Sector[484] =3D 0x72; > + Fs->CurrentSector.Sector[485] =3D 0x72; > + Fs->CurrentSector.Sector[486] =3D 0x41; > + Fs->CurrentSector.Sector[487] =3D 0x61; > + > + // FSI_Free_Count > + Fs->CurrentSector.Sector[488] =3D 0xFF; > + Fs->CurrentSector.Sector[489] =3D 0xFF; > + Fs->CurrentSector.Sector[490] =3D 0xFF; > + Fs->CurrentSector.Sector[491] =3D 0xFF; > + > + // FSI_Nxt_Free > + Fs->CurrentSector.Sector[492] =3D 0xFF; > + Fs->CurrentSector.Sector[493] =3D 0xFF; > + Fs->CurrentSector.Sector[494] =3D 0xFF; > + Fs->CurrentSector.Sector[495] =3D 0xFF; > + > + // Signature > + Fs->CurrentSector.Sector[510] =3D 0x55; > + Fs->CurrentSector.Sector[511] =3D 0xAA; > + > + Status =3D Fs->DiskIo->WriteDisk ( > + Fs->DiskIo, Fs->BlockIo->Media->MediaId, > + MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) + > + MultU64x32 (SectorLba, FAT_SECTOR_SIZE), > + FAT_SECTOR_SIZE, > + Fs->CurrentSector.Sector); > + > + return Status; > +} > + > +/** > + Erase FAT table > + > + @param Fs Pointer to the FAT_FS structure > + @param IsFat32 Whether FAT32 is to be used > + > + @return EFI_SUCCESS Successfully erased FAT > + @return other Failed to erase FAT > + > +**/ > +STATIC > +EFI_STATUS > +EraseFat ( > + IN FATFS *Fs, > + IN BOOLEAN IsFat32) > +{ > + UINTN Index; > + EFI_STATUS Status; > + > + // Zero Sector initially > + ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE); > + > + // Initialise default allocate / reserved clusters > + if (!IsFat32) { > + SET_16BIT_WORD (Fs->CurrentSector.Sector, 0, 0xFFF8); > + SET_16BIT_WORD (Fs->CurrentSector.Sector, 2, 0xFFFF); > + } else { > + SET_32BIT_WORD (Fs->CurrentSector.Sector, 0, 0x0FFFFFF8); > + SET_32BIT_WORD (Fs->CurrentSector.Sector, 4, 0xFFFFFFFF); > + SET_32BIT_WORD (Fs->CurrentSector.Sector, 8, 0x0FFFFFFF); > + } > + > + Status =3D 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 =3D 1; Index < Fs->FatSectors * Fs->NumOfFats; Index++) { > + Status =3D Fs->DiskIo->WriteDisk ( > + Fs->DiskIo, > + Fs->BlockIo->Media->MediaId, > + MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) + > + MultU64x32 ((Fs->FatBeginLba + Index), FAT_SECTOR_SIZE), > + FAT_SECTOR_SIZE, > + Fs->CurrentSector.Sector); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + } > + return Status; > +} > + > +/** > + Format a FAT16 partition > + > + @param Fs Pointer to FAT_FS structure > + @param VolumeSectors Number of sectors in the volume > + @param Name Volume label > + > + @return EFI_SUCCESS FAT16 partition was formatted successfully > + @return other Failed to format FAT16 partition > + > +**/ > +STATIC > +EFI_STATUS > +FormatFat16 ( > + IN FATFS *Fs, > + IN UINT64 VolumeSectors, > + IN CONST CHAR8 *Name > + ) > +{ > + EFI_STATUS Status; > + > + Fs->CurrentSector.Address =3D FAT32_INVALID_CLUSTER; > + Fs->CurrentSector.Dirty =3D 0; > + > + Fs->NextFreeCluster =3D 0; // Invalid > + > + // Volume is FAT16 > + Fs->FatType =3D FAT_TYPE_16; > + > + // Not valid for FAT16 > + Fs->FsInfoSector =3D 0; > + Fs->RootdirFirstCluster =3D 0; > + > + Fs->LbaBegin =3D 0; > + Status =3D 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 =3D Fs->ReservedSectors + (Fs->NumOfFats * Fs- > >FatSectors); > + Fs->RootdirSectors =3D ((Fs->RootEntryCount * 32) + > + (FAT_SECTOR_SIZE - 1)) / FAT_SECTOR_SIZE; > + > + // First FAT LBA Address > + Fs->FatBeginLba =3D Fs->LbaBegin + Fs->ReservedSectors; > + > + // The Address of the first data cluster on this volume > + Fs->ClusterBeginLba =3D Fs->FatBeginLba + > + (Fs->NumOfFats * Fs->FatSectors); > + > + // Initialise FAT sectors > + Status =3D EraseFat (Fs, 0); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + // Erase Root directory > + Status =3D EraseSectors ( > + Fs, > + Fs->LbaBegin + Fs->RootdirFirstSector, > + Fs->RootdirSectors); > + > + return Status; > +} > + > +/** > + Format a FAT32 partition > + > + @param Fs Pointer to FAT_FS structure > + @param VolumeSectors Number of sectors in the volume > + @param Name Volume label > + > + @return EFI_SUCCESS FAT32 partition was formatted successfully > + @return other Failed to format FAT32 partition > + > +**/ > +STATIC > +EFI_STATUS > +FormatFat32 ( > + IN FATFS *Fs, > + IN UINTN VolumeSectors, > + IN CONST CHAR8 *Name > + ) > +{ > + EFI_STATUS Status; > + > + Fs->CurrentSector.Address =3D FAT32_INVALID_CLUSTER; > + Fs->CurrentSector.Dirty =3D 0; > + > + Fs->NextFreeCluster =3D 0; // Invalid > + > + // Volume is FAT32 > + Fs->FatType =3D FAT_TYPE_32; > + > + // Basic defaults for normal FAT32 partitions > + Fs->FsInfoSector =3D 1; > + Fs->RootdirFirstCluster =3D 2; > + > + // Sector 0: Boot Sector > + // NOTE: We don't need an MBR, it is a waste of a good Sector! > + Fs->LbaBegin =3D 0; > + Status =3D CreateBootSector (Fs, Fs->LbaBegin, VolumeSectors, Name, 1)= ; > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + // First FAT LBA address > + Fs->FatBeginLba =3D Fs->LbaBegin + Fs->ReservedSectors; > + > + // The address of the first data cluster on this volume > + Fs->ClusterBeginLba =3D Fs->FatBeginLba + (Fs->NumOfFats * Fs- > >FatSectors); > + > + // Initialise FSInfo sector > + Status =3D CreateFsinfoSector (Fs, Fs->FsInfoSector); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + // Initialise FAT sectors > + Status =3D EraseFat (Fs, 1); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + // Erase Root directory > + Status =3D EraseSectors ( > + Fs, > + LbaOfCluster (Fs, Fs->RootdirFirstCluster), > + Fs->SectorsPerCluster); > + > + return Status; > +} > + > +/** > + Format a partition either to FAT16, or FAT32 > + > + @param StartingLBA Starting LBA of the partition > + @param EndingLBA Ending LBA of the partition > + @param BlockIo Pointer to the BlockIo protocol > + @param DiskIo Pointer to the DiskIo protocol > + @param ForceFat32 Force FAT32 format (even if device can be > formatted as FAT16) > + > + @return EFI_SUCCESS Format succeeded > + @return other Format failed > + > +**/ > +EFI_STATUS > +FatFormat ( > + IN EFI_LBA StartingLBA, > + IN EFI_LBA EndingLBA, > + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, > + IN EFI_DISK_IO_PROTOCOL *DiskIo, > + IN CHAR8 *VolumeName, > + IN BOOLEAN ForceFat32 > + ) > +{ > + FATFS Fs; > + UINT64 VolumeSectors; > + > + if ((StartingLBA > EndingLBA) || > + (BlockIo =3D=3D NULL) || (DiskIo =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + VolumeSectors =3D DivU64x32 ( > + MultU64x32 ( > + EndingLBA - StartingLBA + 1, BlockIo->Media->BlockSize), > + FAT_SECTOR_SIZE); > + > + if (VolumeName =3D=3D NULL) { > + VolumeName =3D DEFAULT_FAT_LABEL_NAME; > + } > + > + ZeroMem (&Fs, sizeof (Fs)); > + > + Fs.StartingLBA =3D StartingLBA; > + Fs.EndingLBA =3D EndingLBA; > + Fs.BlockIo =3D BlockIo; > + Fs.DiskIo =3D DiskIo; > + // 2GB - 32K limit for safe behaviour for FAT16 > + if ((VolumeSectors <=3D FAT16_MAX_SECTORS) && (!ForceFat32)) { > + return FormatFat16 (&Fs, VolumeSectors, VolumeName); > + } else { > + return FormatFat32 (&Fs, VolumeSectors, VolumeName); > + } > +} > diff --git a/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h > b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h > new file mode 100644 > index 000000000000..213ab4df8ebc > --- /dev/null > +++ b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h > @@ -0,0 +1,115 @@ > +/** @file > + > + Copyright (c) 2003 - 2012, Rob Riglar, Ultra-Embedded.com. All rights > reserved
> + Copyright (c) 2016, Broadcom. All rights reserved
> + > + This program and the accompanying materials > + are licensed and made available under the terms and conditions of the = BSD > License > + which accompanies this distribution. The full text of the license may= be > found at > + http://opensource.org/licenses/bsd-license.php > + > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" > BASIS, > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER > EXPRESS OR IMPLIED. > + > +**/ > + > +#ifndef __FAT_FORMAT_H__ > +#define __FAT_FORMAT_H__ > + > +#include "GptWorker.h" > + > +#define FAT_SECTOR_SIZE 512 > +#define FAT_BUFFER_SECTORS 1 > +#define FAT16_MAX_SECTORS 4194304 > +#define FAT32_LAST_CLUSTER 0xFFFFFFFF > +#define FAT32_INVALID_CLUSTER 0xFFFFFFFF > +#define FAT_DIR_ENTRY_SIZE 32 > +#define FAT_BUFFERS 1 > +#define DEFAULT_FAT_LABEL_NAME "EFIVOL" > +#define FAT_LABEL_LENGTH 11 > + > +#define FAT32_FORMAT L"FAT32" > +#define FAT16_FORMAT L"FAT16" > + > +#define GET_32BIT_WORD(Buffer, Location) ( > ((UINT32)Buffer[Location + 3] << 24) + \ > + ((UINT32)Buffer[Locati= on + 2] <<16 ) + \ > + ((UINT32)Buffer[Locati= on + 1] << 8) + \ > + (UINT32)Buffer[Locatio= n+0] ) > + > +#define GET_16BIT_WORD(Buffer, Location) ( > ((UINT16)Buffer[Location + 1] << 8) + \ > + (UINT16)Buffer[Locatio= n+0]) > + > +#define SET_32BIT_WORD(Buffer, Location, Value) { Buffer[Location + 0]= =3D > (UINT8)((Value) & 0xFF); \ > + Buffer[Location + 1] = =3D (UINT8)((Value >> 8) & > 0xFF); \ > + Buffer[Location + 2] = =3D (UINT8)((Value >> 16) & > 0xFF); \ > + Buffer[Location + 3] = =3D (UINT8)((Value >> 24) & > 0xFF); } > + > +#define SET_16BIT_WORD(Buffer, Location, Value) { Buffer[Location + 0]= =3D > (UINT8)((Value) & 0xFF); \ > + Buffer[Location + 1] = =3D (UINT8)((Value >> 8) & > 0xFF); } > + > +typedef enum eFatType > +{ > + FAT_TYPE_16, > + FAT_TYPE_32 > +} FAT_FS_TYPE; > + > + > +// Forward declaration > +typedef struct _FAT_BUFFER FAT_BUFFER; > + > +struct _FAT_BUFFER { > + UINT8 Sector[FAT_SECTOR_SIZE * FAT_BUFFER_SECTORS]; > + UINTN Address; > + BOOLEAN Dirty; > + UINT8 *Ptr; > + > + // Next in chain of sector buffers > + struct FAT_BUFFER *NextBuf; > +}; > + > +typedef struct > +{ > + // Filesystem globals > + UINT8 SectorsPerCluster; > + EFI_LBA ClusterBeginLba; > + UINTN RootdirFirstCluster; > + UINTN RootdirFirstSector; > + UINTN RootdirSectors; > + EFI_LBA FatBeginLba; > + UINT16 FsInfoSector; > + EFI_LBA LbaBegin; > + UINTN FatSectors; > + UINTN NextFreeCluster; > + UINT16 RootEntryCount; > + UINT16 ReservedSectors; > + UINT8 NumOfFats; > + FAT_FS_TYPE FatType; > + > + // Working buffer > + FAT_BUFFER CurrentSector; > + // FAT Buffer > + FAT_BUFFER *FatBufferHead; > + FAT_BUFFER FatBuffers[FAT_BUFFERS]; > + EFI_LBA StartingLBA; > + EFI_LBA EndingLBA; > + EFI_BLOCK_IO_PROTOCOL *BlockIo; > + EFI_DISK_IO_PROTOCOL *DiskIo; > + > +} FATFS; > + > + > + > +//----------------------------------------------------------------------= ------- > +// Prototypes > +//----------------------------------------------------------------------= ------- > +EFI_STATUS > +FatFormat ( > + IN EFI_LBA StartingLBA, > + IN EFI_LBA EndingLBA, > + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, > + IN EFI_DISK_IO_PROTOCOL *DiskIo, > + IN CHAR8 *VolumeName, > + IN BOOLEAN ForceFat32 > + ); > + > +#endif > diff --git a/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c > b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c > new file mode 100644 > index 000000000000..31581b3d6172 > --- /dev/null > +++ b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c > @@ -0,0 +1,1922 @@ > +/** @file > +Copyright (c) 1999 - 2013, Intel Corporation. All rights reserved.
> +Copyright (c) 2016, Broadcom. All rights reserved.
> + > +This program and the accompanying materials > +are licensed and made available under the terms and conditions of the BS= D > License > +which accompanies this distribution. The full text of the license may b= e > 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 =3D NULL; > +STATIC EFI_PARTITION_TABLE_HEADER *BackupHeader =3D NULL; > +STATIC EFI_PARTITION_ENTRY *PartEntry =3D NULL; > +STATIC EFI_PARTITION_ENTRY_STATUS *PEntryStatus =3D 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[] =3D > +{ > + // 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 =3D { > + { 0 }, // BoostStrapC= ode [440] > + { 0 }, // UniqueMbrSi= gnature[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 partit= ions > + }, > + > + MBR_SIGNATURE // Signature > +}; > + > +STATIC UINT32 CurRand =3D 1; > + > +/** > + Get random seed based on the RTC > + > +**/ > + > +STATIC > +VOID > +Srand (VOID) > +{ > + EFI_TIME Time; > + UINT32 Seed; > + UINT64 MonotonicCount; > + > + gRT->GetTime (&Time, NULL); > + Seed =3D (~Time.Hour << 24 | Time.Day << 16 | Time.Minute << 8 | > Time.Second); > + Seed ^=3D Time.Nanosecond; > + Seed ^=3D Time.Year << 7; > + > + gBS->GetNextMonotonicCount (&MonotonicCount); > + Seed +=3D (UINT32)MonotonicCount; > + > + /* Store this seed */ > + CurRand =3D (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 =3D 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 =3D 0; Index < sizeof (GUID); Index++) { > + UINTN V; > + > + V =3D Rand () >> 7; > + Buffer[Index] =3D (UINT16)V; > + } > + /* set variant 10x and version 4 as required by RFC 4122 */ > + Buffer[8] =3D 0x80 | (Buffer[8] & 0x3f); > + Buffer[6] =3D 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 =3D FALSE; > + MbrValid =3D 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 =3D FALSE; > + GptValid =3D FALSE; > + > + ProtectiveMbr =3D NULL; > + > + BlockIo =3D BlockIoProt; > + DiskIo =3D DiskIoProt; > + > + if (CurRand =3D=3D 1) { > + Srand (); > + } > + > + BlockSize =3D BlockIo->Media->BlockSize; > + LastBlock =3D BlockIo->Media->LastBlock; > + MediaId =3D BlockIo->Media->MediaId; > + > + DEBUG ((EFI_D_VERBOSE, " BlockSize : %d \n", BlockSize)); > + DEBUG ((EFI_D_VERBOSE, " LastBlock : %lx \n", LastBlock)); > + > + GptValidStatus =3D EFI_NOT_FOUND; > + GptValid =3D FALSE; > + MbrValid =3D FALSE; > + > + // > + // Allocate a buffer for the Protective MBR > + // > + ProtectiveMbr =3D AllocatePool (BlockSize); > + if (ProtectiveMbr =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + // > + // Read the Protective MBR from LBA #0 > + // > + Status =3D DiskIo->ReadDisk ( > + DiskIo, > + MediaId, > + 0, > + BlockSize, > + ProtectiveMbr > + ); > + if (EFI_ERROR (Status)) { > + GptValidStatus =3D Status; > + goto Done; > + } > + > + // > + // Verify that the Protective MBR is valid > + // > + for (Index =3D 0; Index < MAX_MBR_PARTITIONS; Index++) { > + if (ProtectiveMbr->Partition[Index].BootIndicator =3D=3D 0x00 && > + ProtectiveMbr->Partition[Index].OSIndicator =3D=3D > PMBR_GPT_PARTITION && > + UNPACK_UINT32 (ProtectiveMbr->Partition[Index].StartingLBA) =3D= =3D 1 > + ) { > + break; > + } > + } > + if (Index =3D=3D MAX_MBR_PARTITIONS) { > + goto Done; > + } > + > + MbrValid =3D TRUE; > + > + // > + // Allocate the GPT structures > + // > + PrimaryHeader =3D AllocateZeroPool (sizeof > (EFI_PARTITION_TABLE_HEADER)); > + if (PrimaryHeader =3D=3D NULL) { > + goto Done; > + } > + > + BackupHeader =3D AllocateZeroPool (sizeof > (EFI_PARTITION_TABLE_HEADER)); > + if (BackupHeader =3D=3D NULL) { > + goto Done; > + } > + > + // > + // Check primary and backup partition tables > + // > + Status =3D PartitionValidGptTable (PRIMARY_PART_HEADER_LBA, > PrimaryHeader); > + if (EFI_ERROR (Status)) { > + DEBUG ((EFI_D_INFO, " Not Valid primary partition table\n")); > + > + Status =3D 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 =3D 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 =3D 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 =3D AllocatePool (PrimaryHeader->NumberOfPartitionEntries * > PrimaryHeader->SizeOfPartitionEntry); > + if (PartEntry =3D=3D NULL) { > + DEBUG ((EFI_D_ERROR, "Allocate pool error\n")); > + goto Done; > + } > + > + Status =3D DiskIo->ReadDisk ( > + DiskIo, > + MediaId, > + MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockSize), > + PrimaryHeader->NumberOfPartitionEntries * (PrimaryHeader- > >SizeOfPartitionEntry), > + PartEntry > + ); > + if (EFI_ERROR (Status)) { > + GptValidStatus =3D 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 =3D AllocateZeroPool (PrimaryHeader- > >NumberOfPartitionEntries * sizeof (EFI_PARTITION_ENTRY_STATUS)); > + if (PEntryStatus =3D=3D 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 shoul= d return > true > + // > + GptValidStatus =3D 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 =3D 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 =3D BlockIo->Media->BlockSize; > + MediaId =3D BlockIo->Media->MediaId; > + PartHdr =3D AllocateZeroPool (BlockSize); > + > + if (PartHdr =3D=3D NULL) { > + DEBUG ((EFI_D_ERROR, "Allocate pool error\n")); > + return EFI_OUT_OF_RESOURCES; > + } > + // > + // Read the EFI Partition Table Header > + // > + Status =3D DiskIo->ReadDisk ( > + DiskIo, > + MediaId, > + MultU64x32 (Lba, BlockSize), > + BlockSize, > + PartHdr > + ); > + if (EFI_ERROR (Status)) { > + FreePool (PartHdr); > + return Status; > + } > + > + if ((PartHdr->Header.Signature !=3D EFI_PTAB_HEADER_ID) || > + !PartitionCheckCrc (BlockSize, &PartHdr->Header) || > + PartHdr->MyLBA !=3D 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 =3D AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeade= r- > >SizeOfPartitionEntry); > + if (Ptr =3D=3D NULL) { > + DEBUG ((EFI_D_ERROR, " Allocate pool error\n")); > + return FALSE; > + } > + > + Status =3D 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 =3D PartHeader->NumberOfPartitionEntries * PartHeader- > >SizeOfPartitionEntry; > + > + Status =3D 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 =3D=3D 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 =3D NULL; > + Ptr =3D NULL; > + > + BlockSize =3D BlockIo->Media->BlockSize; > + MediaId =3D BlockIo->Media->MediaId; > + > + PartHdr =3D AllocateZeroPool (BlockSize); > + > + if (PartHdr =3D=3D NULL) { > + DEBUG ((EFI_D_ERROR, "Allocate pool error\n")); > + return FALSE; > + } > + > + PEntryLBA =3D (PartHeader->MyLBA =3D=3D PRIMARY_PART_HEADER_LBA) ?\ > + (PartHeader->LastUsableLBA + 1) :\ > + (PRIMARY_PART_HEADER_LBA + 1); > + > + CopyMem (PartHdr, PartHeader, sizeof (EFI_PARTITION_TABLE_HEADER)); > + > + PartHdr->MyLBA =3D PartHeader->AlternateLBA; > + PartHdr->AlternateLBA =3D PartHeader->MyLBA; > + PartHdr->PartitionEntryLBA =3D PEntryLBA; > + PartitionSetCrc ((EFI_TABLE_HEADER *)PartHdr); > + > + Status =3D DiskIo->WriteDisk ( > + DiskIo, > + MediaId, > + MultU64x32 (PartHdr->MyLBA, (UINT32)BlockSize), > + BlockSize, > + PartHdr > + ); > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > + Ptr =3D AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeade= r- > >SizeOfPartitionEntry); > + if (Ptr =3D=3D NULL) { > + DEBUG ((EFI_D_ERROR, " Allocate pool error\n")); > + Status =3D EFI_OUT_OF_RESOURCES; > + goto Done; > + } > + > + Status =3D DiskIo->ReadDisk ( > + DiskIo, > + MediaId, > + MultU64x32 (PartHeader->PartitionEntryLBA, (UINT32)BlockSize), > + PartHeader->NumberOfPartitionEntries * PartHeader- > >SizeOfPartitionEntry, > + Ptr > + ); > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > + Status =3D DiskIo->WriteDisk ( > + DiskIo, > + MediaId, > + MultU64x32 (PEntryLBA, (UINT32)BlockSize), > + PartHeader->NumberOfPartitionEntries * PartHeader- > >SizeOfPartitionEntry, > + Ptr > + ); > + > + Done: > + FreePool (PartHdr); > + > + if (Ptr !=3D 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 =3D 0; Index1 < PartHeader->NumberOfPartitionEntries; > Index1++) { > + Entry =3D (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index1 * > PartHeader->SizeOfPartitionEntry); > + if (CompareGuid (&Entry->PartitionTypeGUID, > &gEfiPartTypeUnusedGuid)) { > + continue; > + } > + > + StartingLBA =3D Entry->StartingLBA; > + EndingLBA =3D Entry->EndingLBA; > + if (StartingLBA > EndingLBA || > + StartingLBA < PartHeader->FirstUsableLBA || > + StartingLBA > PartHeader->LastUsableLBA || > + EndingLBA < PartHeader->FirstUsableLBA || > + EndingLBA > PartHeader->LastUsableLBA > + ) { > + PEntryStatus[Index1].OutOfRange =3D TRUE; > + continue; > + } > + > + if ((Entry->Attributes & BIT1) !=3D 0) { > + // > + // If Bit 1 is set, this indicate that this is an OS specific GUID= partition. > + // > + PEntryStatus[Index1].OsSpecific =3D TRUE; > + } > + > + for (Index2 =3D Index1 + 1; Index2 < PartHeader- > >NumberOfPartitionEntries; Index2++) { > + Entry =3D (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index2 * > PartHeader->SizeOfPartitionEntry); > + if (CompareGuid (&Entry->PartitionTypeGUID, > &gEfiPartTypeUnusedGuid)) { > + continue; > + } > + > + if (Entry->EndingLBA >=3D StartingLBA && Entry->StartingLBA <=3D > EndingLBA) { > + // > + // This region overlaps with the Index1'th region > + // > + PEntryStatus[Index1].Overlap =3D TRUE; > + PEntryStatus[Index2].Overlap =3D 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 =3D 0; > + gBS->CalculateCrc32 ((UINT8 *)Hdr, Size, &Crc); > + Hdr->CRC32 =3D 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 =3D 0; > + > + if (Size =3D=3D 0) { > + // > + // If header size is 0 CRC will pass so return FALSE here > + // > + return FALSE; > + } > + > + if ((MaxSize !=3D 0) && (Size > MaxSize)) { > + DEBUG ((EFI_D_ERROR, "CheckCrc32: Size > MaxSize\n")); > + return FALSE; > + } > + // > + // clear old crc from header > + // > + OrgCrc =3D Hdr->CRC32; > + Hdr->CRC32 =3D 0; > + > + Status =3D 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 =3D Crc; > + > + // > + // return status > + // > + DEBUG_CODE_BEGIN (); > + if (OrgCrc !=3D Crc) { > + DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc check failed\n")); > + } > + DEBUG_CODE_END (); > + > + return (BOOLEAN)(OrgCrc =3D=3D 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 stri= ng > + @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 =3D EFI_SUCCESS; > + > + Size =3D 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 =3D 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 =3D EFI_SUCCESS; > + for (Index =3D 0; Index < ARRAY_SIZE (PartitionTypes); Index++) { > + if (CompareGuid (&Guid, &PartitionTypes[Index].TypeGuid)) { > + StrnCpy (PartTypeStr, PartitionTypes[Index].TypeName, > MAX_PARTITION_NAME_LENGTH); > + return Status; > + } > + } > + if (!NoGuidStr) { > + GuidToString (&Guid, PartTypeStr, (MAX_PARTITION_NAME_LENGTH + > 1) * sizeof (CHAR16)); > + } > + return EFI_NOT_FOUND; > +} > + > +/** > + Lists partitions on a block device. > + > + @return Number of partitions used > +**/ > + > +UINTN > +PartitionListGptEntries (VOID) > +{ > + IN UINTN Index; > + IN EFI_PARTITION_ENTRY *Entry; > + IN EFI_LBA Length; > + IN UINTN NumEntries; // Used entries > + IN UINTN BlockSize; > + IN BOOLEAN FirstTime; > + IN UINT64 BlocksOccupied; > + > + NumEntries =3D 0; > + BlockSize =3D BlockIo->Media->BlockSize; > + FirstTime =3D TRUE; > + > + if (!GptValid) { > + return 0; > + } > + > + BlocksOccupied =3D 0; > + > + for (Index =3D 0; Index < PrimaryHeader->NumberOfPartitionEntries; > Index++) { > + > + BOOLEAN Specific; > + CHAR16 PartTypeStr[MAX_PARTITION_NAME_LENGTH + 1]; > + > + Specific =3D FALSE; > + > + Entry =3D (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index * > PrimaryHeader->SizeOfPartitionEntry); > + > + Length =3D 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 Partit= ion > Type\r\n", L"Name"); > + Print (L" ---- -------------------------------------- ---------= -- ----------- ----- > ----- -------------------------------\r\n"); > + FirstTime =3D FALSE; > + } > + NumEntries++; > + if (PEntryStatus[Index].OutOfRange || > + PEntryStatus[Index].Overlap || > + PEntryStatus[Index].OsSpecific) { > + Specific =3D TRUE; > + } > + > + BlocksOccupied +=3D Length; > + > + GetPartitionTypeStr (Entry->PartitionTypeGUID, (CHAR16 > *)&PartTypeStr, FALSE); > + > + Print (L"%1s %-3d\t%-36s\t0x%09llx\t0x%09llx\t%06llu\t %s\r\= n", > + Specific ? L"S" : L"", > + Index + 1, > + Entry->PartitionName, > + (UINT64)Entry->StartingLBA, > + (UINT64)Entry->EndingLBA, > + (MultU64x32 (Length, BlockSize)) >> 20, > + PartTypeStr); > + } > + > + // This code block is to provide additional info > + { > + UINT64 DiskSizeMiB; > + UINT64 SizeOccupiedMiB; > + > + DiskSizeMiB =3D MultU64x32 (PrimaryHeader->LastUsableLBA - > PrimaryHeader->FirstUsableLBA + 1, BlockIo->Media->BlockSize) >> 20; > + SizeOccupiedMiB =3D 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 =3D search by partition name > + SRC_BY_LBA =3D search by Start/Ending lba > + SRC_ANY =3D returns a first used partitio= n > + SRC_BY_NUM =3D search by ordinal > + > + > + @return Non-NULL Pointer to the partition found > + @return NULL No partition found > + > +**/ > +EFI_PARTITION_ENTRY * > +PartitionFindPartitionByCriteria ( > + IN OPTIONAL CONST CHAR16 *Name, > + IN OPTIONAL EFI_LBA StartLba, > + IN OPTIONAL EFI_LBA EndingLba, > + IN SEARCH_TYPE SearchType > + ) > +{ > + UINTN Index; > + EFI_PARTITION_ENTRY *Entry; > + > + if (!GptValid) { > + return NULL; > + } > + > + if (!Name && (SearchType & SRC_BY_NAME)) { > + return NULL; > + } > + > + for (Index =3D 0; Index < PrimaryHeader->NumberOfPartitionEntries; > Index++) { > + Entry =3D (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 =3D ShellStrToUintn (Name); > + if (Index =3D=3D (Ordinal - 1)) { > + return Entry; > + } > + } > + if (SearchType & SRC_BY_LBA) { > + if ( > + ((StartLba >=3D Entry->StartingLBA) && > + (StartLba <=3D Entry->EndingLBA) > + ) || > + ((EndingLba >=3D Entry->StartingLBA) && > + (EndingLba <=3D Entry->EndingLBA) > + ) > + ) { > + return Entry; > + } > + } > + } > + return NULL; > +} > + > +/** > + Prints information on a given partition. > + > + @param Entry Pointer to the Partition of interest > +**/ > + > +VOID > +PartitionPrintGptPartInfo ( > + IN EFI_PARTITION_ENTRY *Entry > + ) > +{ > + CONST CHAR16 PartStr[MAX_PARTITION_NAME_LENGTH + 1]; > + CONST CHAR16 *StrUnknown; > + EFI_STATUS Status; > + EFI_LBA Length; > + > + ASSERT (Entry); > + > + ZeroMem ((VOID *)PartStr, sizeof (PartStr)); > + StrUnknown =3D GPT_PART_UNKNOWN_STR; > + > + Status =3D GetPartitionTypeStr (Entry->PartitionTypeGUID, (CHAR16 > *)&PartStr, TRUE); > + if (EFI_ERROR (Status)) { > + StrCpy ((CHAR16 *)&PartStr, StrUnknown); > + } > + > + Length =3D 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->PartitionTypeGUI= D); > + 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 =3D BlockIo->Media->BlockSize; > + > + ProtectiveMbr =3D NULL; > + ProtectiveMbr =3D AllocateZeroPool (BlockSize); > + if (ProtectiveMbr =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + DiskSize =3D BlockIo->Media->LastBlock + 1; > + if (DiskSize > 0xffffffff) { > + DiskSize =3D 0xffffffff; > + } > + > + CopyMem (ProtectiveMbr, &ProtectiveMbrTemplate, sizeof > (MASTER_BOOT_RECORD)); > + > + Partition =3D &ProtectiveMbr->Partition[0]; > + > + Partition->BootIndicator =3D 0; > + Partition->StartSector =3D 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 =3D 1; > + > + Status =3D DiskIo->WriteDisk ( > + DiskIo, > + BlockIo->Media->MediaId, > + 0, > + BlockSize, > + ProtectiveMbr > + ); > + > + MbrValid =3D !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 =3D EFI_SUCCESS; > + > + BlockSize =3D BlockIo->Media->BlockSize; > + TableSize =3D PrimaryHeader->NumberOfPartitionEntries * sizeof > (EFI_PARTITION_ENTRY); > + > + if (!MbrValid) { > + WriteProtectiveMbr (); > + } > + // > + // Write out the primary header... > + // > + PrimaryHeader->Header.Signature =3D EFI_PTAB_HEADER_ID; > + PrimaryHeader->Header.Revision =3D GPT_REVISION_1_0; > + PrimaryHeader->Header.HeaderSize =3D sizeof > (EFI_PARTITION_TABLE_HEADER); > + > + PrimaryHeader->AlternateLBA =3D BackupHeader->MyLBA; > + > + PrimaryHeader->SizeOfPartitionEntry =3D sizeof (EFI_PARTITION_ENTRY); > + > + Status =3D gBS->CalculateCrc32 ((UINT8 *)PartEntry, TableSize, > &PrimaryHeader->PartitionEntryArrayCRC32); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + // Write primary header > + PartitionSetCrc (&PrimaryHeader->Header); > + > + Status =3D 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 =3D 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 =3D !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 =3D ENTRY_DEFAULT; > + BlockSize =3D BlockIo->Media->BlockSize; > + BlockFit =3D BlockSize / sizeof (EFI_PARTITION_ENTRY); > + > + if (BlockFit > ENTRY_DEFAULT) { > + EntryCount =3D BlockFit; > + } > + EntryBlocks =3D EntryCount / BlockFit; > + > + if ((EntryBlocks * BlockFit) !=3D EntryCount) { > + Status =3D EFI_VOLUME_CORRUPTED; > + PrintErr (L"Invalid Entry blocks and Entry count combination\n", Sta= tus); > + return Status; > + } > + > + DiskSize =3D BlockIo->Media->LastBlock + 1; > + > + SHELL_FREE_NON_NULL (PrimaryHeader); > + SHELL_FREE_NON_NULL (BackupHeader); > + SHELL_FREE_NON_NULL (PartEntry); > + > + PrimaryHeader =3D AllocateZeroPool (BlockSize); > + if (PrimaryHeader =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + BackupHeader =3D AllocateZeroPool (BlockSize); > + if (BackupHeader =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + Header1_LBA =3D 1; > + Table1_LBA =3D 2; > + FirstUsableLBA =3D Table1_LBA + EntryBlocks; > + > + Header2_LBA =3D DiskSize - 1; > + Table2_LBA =3D Header2_LBA - EntryBlocks; > + LastUsableLBA =3D Table2_LBA - 1; > + > + TableSize =3D EntryBlocks * BlockSize; > + > + if (TableSize !=3D (EntryCount * sizeof (EFI_PARTITION_ENTRY))) { > + Status =3D EFI_VOLUME_CORRUPTED; > + PrintErr (L"Invalid Table size and Entry count combination\n", Statu= s); > + return Status; > + } > + > + if (GPT_DEBUG_LEVEL) { > + Print (L"DiskSize =3D %lx\n", DiskSize); > + Print (L"BlockSize =3D %x\n", BlockSize); > + Print (L"Header1_LBA =3D %lx\n", Header1_LBA); > + Print (L"Table1_LBA =3D %lx\n", Table1_LBA); > + Print (L"FirstUsableLBA =3D %lx\n", FirstUsableLBA); > + Print (L"Header2_LBA =3D %lx\n", Header2_LBA); > + Print (L"Table2_LBA =3D %lx\n", Table2_LBA); > + Print (L"LastUsableLBA =3D %lx\n", LastUsableLBA); > + Print (L"EntryCount =3D %x\n", EntryCount); > + Print (L"EntryBlocks =3D %x\n", EntryBlocks); > + } > + > + // > + // Since we're making empty tables, we just write zeros... > + // > + > + PartEntry =3D AllocateZeroPool (TableSize); > + if (PartEntry =3D=3D NULL) { > + SHELL_FREE_NON_NULL (PrimaryHeader); > + SHELL_FREE_NON_NULL (BackupHeader); > + return EFI_OUT_OF_RESOURCES; > + } > + > + PEntryStatus =3D AllocateZeroPool (TableSize); > + > + PrimaryHeader->FirstUsableLBA =3D FirstUsableLBA; > + PrimaryHeader->LastUsableLBA =3D LastUsableLBA; > + PrimaryHeader->NumberOfPartitionEntries =3D (UINT32)EntryCount; > + GenerateGuid (&PrimaryHeader->DiskGUID); > + > + PrimaryHeader->MyLBA =3D Header1_LBA; > + BackupHeader->MyLBA =3D Header2_LBA; > + PrimaryHeader->PartitionEntryLBA =3D Table1_LBA; > + BackupHeader->PartitionEntryLBA =3D Table2_LBA; > + > + Status =3D WriteGPT (); > + > + return Status; > +} > + > +/** > + Clear GPT partitions. > + > + @return EFI_SUCCESS Cleared successfully > + @return FALSE Failed to clear > + > +**/ > + > +EFI_STATUS > +PartitionGptClearAll ( > + VOID > + ) > +{ > + GptCleanupGlobals (); > + GptValid =3D FALSE; > + MbrValid =3D 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 partit= ion > (not a partition unique GUID) > + > + > + @return EFI_SUCCESS Partition successfully created > + @return EFI_INVALID_PARAMETER Either partition exists, or wrong > parameters specified > + @return other Failed to create a partition > +**/ > +EFI_STATUS > +PartitionGptCreatePartition ( > + IN CONST CHAR16 *PartName, > + IN EFI_LBA StartLba, > + IN UINT64 SizeInMegabytes, > + IN UINT64 Attributes, > + IN EFI_GUID PartTypeGuid > + ) > +{ > + EFI_GUID Guid; > + EFI_GUID PartitionIdGuid; > + EFI_STATUS Status; > + UINT64 StartBlock; > + UINT64 EndBlock; > + UINT64 SizeInBytes; > + UINT32 BlockSize; > + UINT64 DiskSizeBlocks; > + UINT8 *p; > + BOOLEAN OffsetSpecified; > + BOOLEAN AllZeros; > + INTN AllZeroEntry; > + INTN OldFreeEntry; > + UINT64 AvailBlocks; > + UINT64 BlocksToAllocate; > + UINT64 HighSeen; > + UINTN Slot; > + UINT64 LowestAlignedLba; > + UINT32 OptimalTransferBlocks; > + UINTN i; > + UINTN j; > + CHAR16 PartNameUsed[MAX_PARTITION_NAME_LENGTH + 1]; > + EFI_PARTITION_ENTRY *Entry; > + > + SizeInBytes =3D 0; > + OffsetSpecified =3D FALSE; > + ZeroMem (PartNameUsed, sizeof (PartNameUsed)); > + LowestAlignedLba =3D 0; > + OptimalTransferBlocks =3D 1; > + > + AllZeroEntry =3D -1; > + OldFreeEntry =3D -1; > + > + BlockSize =3D BlockIo->Media->BlockSize; > + OffsetSpecified =3D (StartLba !=3D 0); > + CopyMem (&PartNameUsed, PartName, sizeof (CHAR16) * StrSize > (PartName)); > + > + GenerateGuid (&Guid); > + > + // Creating a new partition > + if (!GptValid) { > + // Creating a GPT for the first time > + Status =3D TableCreateEmptyGpt (); > + if (!EFI_ERROR (Status)) { > + // Fill in the structures > + Status =3D PartitionGetGptTables (DiskIo, BlockIo); > + } > + if (EFI_ERROR (Status)) { > + return Status; > + } > + } > + > + Entry =3D PartitionFindPartitionByCriteria (PartName, 0, 0, SRC_BY_NAM= E); > + if (Entry) { > + Status =3D EFI_INVALID_PARAMETER; > + PrintErr (L"Partition with this name already exists", Status); > + return Status; > + } > + HighSeen =3D PrimaryHeader->FirstUsableLBA - 1; > + > + if (StartLba) { > + // > + // if offset is specified, compute the start and end blocks > + // > + StartBlock =3D 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 =3D LowestAlignedLba; > + } else { > + while (((StartBlock - LowestAlignedLba) % OptimalTransferBlocks) != =3D 0) { > + StartBlock++; > + } > + } > + > + if (StartBlock < PrimaryHeader->FirstUsableLBA || > + StartBlock > PrimaryHeader->LastUsableLBA) { > + // > + // Offset specified is too large > + // > + Status =3D EFI_INVALID_PARAMETER; > + PrintErr (L"Specified offset is too large", EFI_INVALID_PARAMETER)= ; > + goto Exit; > + } > + > + SizeInBytes =3D MultU64x32 (SizeInMegabytes, (1024 * 1024)); > + if (SizeInBytes < SizeInMegabytes || SizeInBytes =3D=3D 0) { > + // > + // If size is not specified or too large, > + // try to make the partition as big as it can be > + // > + BlocksToAllocate =3D EndBlock =3D SizeInBytes =3D 0xffffffffffffff= ff; > + } else { > + BlocksToAllocate =3D DivU64x32 (SizeInBytes, BlockSize); > + EndBlock =3D StartBlock + BlocksToAllocate - 1; > + if (EndBlock > PrimaryHeader->LastUsableLBA) { > + EndBlock =3D PrimaryHeader->LastUsableLBA; > + BlocksToAllocate =3D EndBlock - StartBlock + 1; > + } > + } > + } > + > + for (i =3D 0; i < PrimaryHeader->NumberOfPartitionEntries; i++) { > + Entry =3D (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 =3D Entry->EndingLBA; > + } > + if (OffsetSpecified) { > + // > + // make sure new partition does not overlap with existing partit= ions > + // > + if (Entry->StartingLBA <=3D StartBlock && > + StartBlock <=3D Entry->EndingLBA) { > + // > + // starting block is inside an existing partition > + // > + Status =3D EFI_INVALID_PARAMETER; > + PrintErr (L"Starting block is inside an existing partition", S= tatus); > + goto Exit; > + } > + if ((Entry->StartingLBA <=3D EndBlock && > + EndBlock <=3D Entry->EndingLBA) || > + (StartBlock <=3D Entry->StartingLBA && > + Entry->StartingLBA <=3D EndBlock) || > + (StartBlock <=3D Entry->EndingLBA && > + Entry->EndingLBA <=3D EndBlock)) { > + // > + // new partition overlaps with an existing partition > + // readjust new partition size to avoid overlapping > + // > + EndBlock =3D Entry->StartingLBA - 1; > + if (EndBlock < StartBlock) { > + Status =3D EFI_INVALID_PARAMETER; > + PrintErr (L"Cannot readjust new partition size - overlapping= ", Status); > + goto Exit; > + } else { > + BlocksToAllocate =3D EndBlock - StartBlock + 1; > + } > + } > + } > + } else { > + p =3D (UINT8 *)(Entry); > + AllZeros =3D TRUE; > + for (j =3D 0; j < sizeof (EFI_PARTITION_ENTRY); j++) { > + if (p[j] !=3D 0) { > + AllZeros =3D FALSE; > + } > + } > + if (AllZeros) { > + if (AllZeroEntry =3D=3D -1) { > + AllZeroEntry =3D i; > + } > + } else if (OldFreeEntry =3D=3D -1) { > + OldFreeEntry =3D 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 =3D=3D -1) && (OldFreeEntry =3D=3D -1)) { > + // > + // TABLE IS FULL!! > + // > + Status =3D 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 parti= tion. > + // So, use the max it can > + // > + if (BlocksToAllocate =3D=3D -1) { > + EndBlock =3D PrimaryHeader->LastUsableLBA; > + BlocksToAllocate =3D 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 =3D LowestAlignedLba - 1; > + } else { > + while (((HighSeen + 1 - LowestAlignedLba) % OptimalTransferBlocks)= !=3D > 0) { > + HighSeen++; > + } > + } > + > + if (PrimaryHeader->LastUsableLBA <=3D HighSeen) { > + Status =3D EFI_OUT_OF_RESOURCES; > + PrintErr (L"Disk has no free blocks (FULL) cannot create", Status)= ; > + goto Exit; > + } > + // > + // [HighSeen+1 ... LastUsableLBA] is available... > + // avail =3D (LastUsableLBA - (HighSeen+1)) + 1 =3D> LastUsabbleLBA = - > HighSeen > + // > + AvailBlocks =3D PrimaryHeader->LastUsableLBA - HighSeen; > + > + SizeInBytes =3D MultU64x32 (SizeInMegabytes, (1024 * 1024)); > + if (SizeInBytes < SizeInMegabytes) { > + // > + // overflow, force a very big answer > + // > + SizeInBytes =3D 0xffffffffffffffff; > + } > + > + if ((SizeInBytes =3D=3D 0) || > + (SizeInBytes > (MultU64x32 (AvailBlocks, BlockSize)))) { > + // > + // User asked for zero, or for more than we've got, > + // so give them all that is left > + // > + BlocksToAllocate =3D 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 =3D 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 =3D EFI_OUT_OF_RESOURCES; > + PrintErr (L"Partition is too small to be created", Status); > + goto Exit; > + } > + > + if (GPT_DEBUG_LEVEL) { > + Print (L"Requested SizeInMegaBytes =3D %ld\n", SizeInMegabytes); > + Print (L"Resulting size in Blocks =3D %ld\n", BlocksToAllocate); > + Print (L"Results size in Bytes =3D %ld\n", MultU64x32 (BlocksToAlloc= ate, > BlockSize)); > + } > + > + if (AllZeroEntry !=3D -1) { > + Slot =3D AllZeroEntry; > + } else { > + Slot =3D OldFreeEntry; > + } > + > + GenerateGuid (&PartitionIdGuid); > + Entry =3D (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 =3D StartBlock; > + PartEntry[Slot].EndingLBA =3D EndBlock; > + } else { > + PartEntry[Slot].StartingLBA =3D HighSeen + 1; > + PartEntry[Slot].EndingLBA =3D HighSeen + BlocksToAllocate; > + } > + > + if (!(((Entry->EndingLBA - Entry->StartingLBA) + 1) =3D=3D BlocksToAll= ocate)) { > + 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 =3D Attributes; > + CopyMem (&(Entry->PartitionName[0]), PartName, > MAX_PARTITION_NAME_LENGTH * sizeof (CHAR16)); > + > + DiskSizeBlocks =3D BlockIo->Media->LastBlock + 1; > + if (DiskSizeBlocks > 0xffffffff) { > + DiskSizeBlocks =3D 0xffffffff; > + } > + > + Status =3D 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 =3D EFI_INVALID_PARAMETER; > + > + switch (Flags) { > + case MOD_DELETE: > + ZeroMem (Entry, sizeof (EFI_PARTITION_ENTRY)); > + break; > + case MOD_ATTR: > + Entry->Attributes =3D Params->Attributes; > + break; > + case MOD_TYPE: > + Entry->PartitionTypeGUID =3D 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 =3D ARRAY_SIZE (PartitionTypes); > + } > + if (Index > ARRAY_SIZE (PartitionTypes)) { > + return NULL; > + } > + > + return &PartitionTypes[Index]; > +} > + > diff --git a/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h > b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h > new file mode 100644 > index 000000000000..048377d883e7 > --- /dev/null > +++ b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h > @@ -0,0 +1,188 @@ > +/* > + * BSD LICENSE > + * > + * Copyright(c) 2016 Broadcom. All rights reserved. > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * > + * * Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * * Redistributions in binary form must reproduce the above copyrigh= t > + * 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 > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +typedef enum { > + MOD_NAME =3D BIT0, > + MOD_ATTR =3D BIT1, > + MOD_TYPE =3D BIT2, > + MOD_DELETE =3D BIT3, > + MOD_RENAME =3D BIT4 > +} MOD_FLAGS; > + > +typedef struct { > + UINTN Attributes; > + EFI_GUID PartTypeGuid; > + CONST CHAR16 *PartName; > + CONST CHAR16 *NewName; > +} MOD_PARAMS; > + > +typedef enum { > + SRC_BY_NAME =3D BIT0, > + SRC_BY_LBA =3D BIT1, > + SRC_BY_NUM =3D BIT2, > + SRC_ANY =3D BIT3 > +} SEARCH_TYPE; > + > +#define MAX_PARTITION_NAME_LENGTH 36 > +#define ENTRY_DEFAULT 128 > +#define GPT_REVISION_1_0 0x00010000 > + > +#define ARRAY_SIZE(x) \ > + (sizeof(x) / sizeof((x)[0])) > + > +// > +// Extract INT32 from char array > +// > +#define UNPACK_INT32(a) (INT32)( (((UINT8 *) a)[0] << 0) | \ > + (((UINT8 *) a)[1] << 8) | \ > + (((UINT8 *) a)[2] << 16) | \ > + (((UINT8 *) a)[3] << 24) ) > + > +// > +// Extract UINT32 from char array > +// > +#define UNPACK_UINT32(a) (UINT32)( (((UINT8 *) a)[0] << 0) | \ > + (((UINT8 *) a)[1] << 8) | \ > + (((UINT8 *) a)[2] << 16) | \ > + (((UINT8 *) a)[3] << 24) ) > +#define GPT_PART_UNKNOWN_STR L"Unknown"; > + > +// > +// GPT Partition Entry Status > +// > +typedef struct { > + BOOLEAN OutOfRange; > + BOOLEAN Overlap; > + BOOLEAN OsSpecific; > +} EFI_PARTITION_ENTRY_STATUS; > + > +typedef struct { > + CONST EFI_GUID TypeGuid; > + CONST CHAR16 *TypeName; > + > +} EFI_KNOWN_PARTITION_TYPE; > + > +EFI_KNOWN_PARTITION_TYPE *PartitionGetKnownType ( > + IN UINTN Index, > + IN OUT OPTIONAL UINTN *NumEntries > + ); > + > +EFI_STATUS > +PartitionGetGptTables ( > + IN EFI_DISK_IO_PROTOCOL *DiskIoProt, > + IN EFI_BLOCK_IO_PROTOCOL *BlockIoProt > + ); > + > +UINTN > +PartitionListGptEntries ( > + VOID > + ); > + > +VOID > +PartitionPrintGptPartInfo ( > + IN EFI_PARTITION_ENTRY *Entry > + ); > + > +EFI_STATUS > +GetPartitionTypeStr ( > + IN EFI_GUID Guid, > + OUT CHAR16 *PartTypeStr, > + IN BOOLEAN NoGuidStr > + ); > + > + > +EFI_STATUS > +PartitionGptClearAll ( > + VOID > + ); > + > +EFI_STATUS > +PartitionGptCreatePartition ( > + IN CONST CHAR16 *PartName, > + IN EFI_LBA StartLba, > + IN EFI_LBA PartitionSize, > + IN UINT64 Attributes, > + IN EFI_GUID PartTypeGuid); > + > +EFI_STATUS > +PartitionGptModifyPartition ( > + IN EFI_PARTITION_ENTRY *Entry, > + IN MOD_PARAMS *Params, > + IN MOD_FLAGS Flags > + ); > + > +VOID > +GptCleanupGlobals ( > + VOID > + ); > + > +EFI_PARTITION_ENTRY * > +PartitionFindPartitionByCriteria ( > + IN CONST CHAR16 *Name, > + IN EFI_LBA StartLba, > + IN EFI_LBA EndingLba, > + IN SEARCH_TYPE SearchType); > + > +VOID > +PrintErr ( > + IN CONST CHAR16 *Message, > + IN EFI_STATUS Status > + ); > + > +#endif //_GPTWORKER_H_ > diff --git > a/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c > b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c > new file mode 100644 > index 000000000000..b2d562443ae3 > --- /dev/null > +++ > b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c > @@ -0,0 +1,1267 @@ > +/********************************************************* > ********************** > +Copyright (C) 2016, Marvell International Ltd. All rights reserved. > +Copyright (C) 2016, Broadcom. All rights reserved. > + > +Redistribution and use in source and binary forms, with or without > modification, > +are permitted provided that the following conditions are met: > + > +* Redistributions of source code must retain the above copyright notice, > + this list of conditions and the following disclaimer. > + > +* Redistributions in binary form must reproduce the above copyright > + notice, this list of conditions and the following disclaimer in the > + documentation and/or other materials provided with the distribution. > + > +* Neither the name of Marvell nor the names of its contributors may be > + used to endorse or promote products derived from this software without > + specific prior written permission. > + > +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND > CONTRIBUTORS "AS IS" AND > +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, > THE IMPLIED > +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR > PURPOSE ARE > +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR > CONTRIBUTORS BE LIABLE FOR > +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > CONSEQUENTIAL DAMAGES > +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS > OR SERVICES; > +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER > CAUSED AND ON > +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR > TORT > +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF > THE USE OF THIS > +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. > + > +********************************************************* > **********************/ > + > +#include "FatFormat.h" > +#include > > +#include > + > +CONST CHAR16 gShellGptFileName[] =3D L"ShellCommand"; > +STATIC CONST CHAR16 gAppName[] =3D L"gpt"; > +EFI_HANDLE gShellGptHiiHandle =3D NULL; > + > +STATIC CONST SHELL_PARAM_ITEM ParamList[] =3D { > + // 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 parti= tion 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 operati= ons > + { 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 certa= in partition > (startLba, lastLba, attributes) > + { L"fatformat", TypeFlag }, // FAT format of a partition > + { L"-type", TypeValue }, // Set GUID type to either an= arbitrary > GUID, or to a GUID from a know partition type > + { L"-yes", TypeFlag }, // Warn, but do not prompt on= potentially > destructive operations, > + // assume all YES. Potentiall= y dangerous > + { L"-verbose", TypeFlag }, // Print additional informati= on on the > operation > + { L"-fat16", TypeFlag }, // Do FAT16 format if possibl= e (by default > format is FAT32) > + { NULL, TypeMax } > +}; > + > +typedef enum { > + // Not requires presence > + CLEAR =3D BIT0, > + CREATE =3D BIT1, > + LIST =3D BIT2, > + SYNC =3D BIT3, > + TYPES_INFO =3D BIT4, > + > + // Requires presence > + DELETE =3D BIT5, > + INFO =3D BIT6, > + READ =3D BIT7, > + READ_FILE =3D BIT8, > + RENAME =3D BIT9, > + SETATTR =3D BIT10, > + SETTYPE =3D BIT11, > + WRITE =3D BIT12, > + WRITE_FILE =3D BIT13, > + FAT_FORMAT =3D BIT14, > +} Flags; > + > +/** > + Return the file name of the help text file if not using HII. > + > + @return The string pointer to the file name. > +**/ > +CONST CHAR16 * > +EFIAPI > +ShellCommandGetManFileNameGpt ( > + VOID > + ) > +{ > + > + return gShellGptFileName; > +} > + > +/** > + Open a file for read or write > + > + @param [in] FilePath The path to the file to be opened/created > + @param [out] FileHandle The handle of the file on successful open/cr= eate > + @param [in] WriteNeeded Indicates that the file is being opened for > write > + > + @return EFI_SUCCESS File opened/created successfully > + @return other Failed to open/create the file > + > +**/ > +STATIC > +EFI_STATUS > +OpenAndPrepareFile ( > + IN CHAR16 *FilePath, > + OUT SHELL_FILE_HANDLE *FileHandle, > + IN BOOLEAN WriteNeeded > + ) > +{ > + EFI_STATUS Status; > + UINT64 OpenMode; > + > + OpenMode =3D EFI_FILE_MODE_READ; > + > + if (WriteNeeded) { > + OpenMode |=3D EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE; > + } > + > + Status =3D 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 =3D FileHandleSetPosition (*FileHandle, 0); > + > + if (EFI_ERROR (Status)) { > + ShellPrintHiiEx (-1, -1, > + NULL, STRING_TOKEN (STR_GPT_ERROR), > + gShellGptHiiHandle, > + gAppName, > + Status, > + "Cannot set file position to the first byte" > + ); > + > + ShellCloseFile (FileHandle); > + return Status; > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Print error using generic HII format string > + > + @param [in] Message Error message to be displayed > + @param [in] Status Status from the previous operation > + > +**/ > +VOID > +PrintErr ( > + IN CONST CHAR16 *Message, > + IN EFI_STATUS Status > + ) > +{ > + ShellPrintHiiEx (-1, -1, > + NULL, STRING_TOKEN (STR_GPT_ERROR), > + gShellGptHiiHandle, > + gAppName, > + Status, > + Message > + ); > +} > + > +/** > + Find out if this is a partitionable device by Device Path > + > + @param [in] DevicePath Device path of the block device > + > + @return TRUE Block device is partitionable > + @return FALSE Block device is not partitionable > + > +**/ > + > +STATIC > +BOOLEAN > +IsPartitionableDevicePath ( > + IN EFI_DEVICE_PATH *DevicePath > + ) > +{ > + UINTN PathSize; > + EFI_DEVICE_PATH *PathInstance; > + BOOLEAN Partitionable; > + > + Partitionable =3D TRUE; > + while (DevicePath !=3D NULL) { > + PathInstance =3D GetNextDevicePathInstance (&DevicePath, &PathSize); > + > + while (!IsDevicePathEnd (PathInstance)) { > + if ((DevicePathType (PathInstance) =3D=3D MEDIA_DEVICE_PATH)) { > + Partitionable =3D FALSE; > + } > + > + PathInstance =3D NextDevicePathNode (PathInstance); > + } > + } > + return Partitionable; > +} > + > +/** > + Prompt a user with HII prompt and get answer (Yes, or No) > + > + @param [in] HiiFormatStringId ID of the HII string in the .uni fi= le > + > + @return EFI_SUCCESS A user answered "Yes" > + @return EFI_ABORTED A user answered "No" > + > +**/ > +STATIC > +EFI_STATUS > +GptPromptYesNo ( > + IN CONST EFI_STRING_ID HiiFormatStringId > + ) > +{ > + EFI_STATUS Status; > + VOID *Response; > + > + Status =3D ShellPromptForResponseHii (ShellPromptResponseTypeYesNo, > HiiFormatStringId, gShellGptHiiHandle, &Response); > + if ((EFI_ERROR (Status)) || (*(SHELL_PROMPT_RESPONSE *)Response) !=3D > ShellPromptResponseYes) { > + return EFI_ABORTED; > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Format a size in human-readable format > + > + @param [in] Size The size to be formatted > + @param [out] Buffer Buffer receiving the format string > + > + The size is formatted so that it represents a unit and a metric. > + Thus, for 1967128576 bytes it would be 1.8G; > + for 33554432 bytes it would be 32M, etc. > + > +**/ > +STATIC > +VOID FormatSize ( > + IN UINT64 Size, > + IN CHAR16 *Buffer > + ) > +{ > +#define MAX_SIZE_BUF_SIZE 32 > + UINT64 Base; > + UINT64 Frac; > + CHAR16 Metric; > + > + Metric =3D L'B'; > + Frac =3D 0; > + if (Size < SIZE_1KB) { > + Base =3D Size; > + } else if (Size < SIZE_1MB) { > + Base =3D Size / SIZE_1KB; > + Frac =3D ((Size % SIZE_1KB) * 10) >> 10; > + Metric =3D L'K'; > + } else if (Size < SIZE_1GB) { > + Base =3D Size / SIZE_1MB; > + Frac =3D ((Size % SIZE_1MB) * 10) >> 20; > + Metric =3D L'M'; > + } else if (Size < SIZE_1TB) { > + Base =3D Size / SIZE_1GB; > + Frac =3D ((Size % SIZE_1GB) * 10) >> 30; > + Metric =3D L'G'; > + } else { > + Base =3D Size / SIZE_1TB; > + Frac =3D ((Size % SIZE_1TB) * 10) >> 40; > + Metric =3D L'T'; > + } > + if (Frac) { > + UnicodeSPrint (Buffer, MAX_SIZE_BUF_SIZE, L"%d.%d%c", Base, Frac, > Metric); > + } else { > + UnicodeSPrint (Buffer, MAX_SIZE_BUF_SIZE, L"%d%c", Base, Metric); > + } > +} > + > +/** > + Find and print a table of all partitionable devices > + > + @return EFI_SUCCESS Successfully obtained a list > + @return EFI_OUT_OF_RESOURCES Could not allocate memory > + @return other Error obtaining the list of devices > + > +**/ > + > +STATIC > +EFI_STATUS > +FindAndPrintPartitionableDevices ( > + VOID > + ) > +{ > + UINTN Index; > + IN EFI_HANDLE *HandlePointer; > + UINTN HandleCount; > + UINTN DevCount; > + EFI_STATUS Status; > + BOOLEAN FirstTime; > + CHAR16 *BufferForSize; > + > + Status =3D gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGu= id, > NULL, &HandleCount, &HandlePointer); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + DevCount =3D 0; > + FirstTime =3D TRUE; > + BufferForSize =3D NULL; > + > + for (Index =3D 0; Index < HandleCount; Index++) { > + EFI_DEVICE_PATH *DevicePath; > + CONST CHAR16 *MapPath; > + CHAR16 *Match; > + EFI_BLOCK_IO *BlkIo; > + EFI_DISK_IO *DiskIo; > + > + Status =3D gBS->HandleProtocol (HandlePointer[Index], > &gEfiBlockIoProtocolGuid, (VOID **)&BlkIo); > + if (EFI_ERROR (Status)) { > + continue; > + } > + > + DevicePath =3D DevicePathFromHandle (HandlePointer[Index]); > + if (!IsPartitionableDevicePath (DevicePath)) { > + continue; > + } > + MapPath =3D gEfiShellProtocol->GetMapFromDevicePath (&DevicePath); > + if (MapPath =3D=3D NULL) { > + continue; > + } > + > + Status =3D gBS->HandleProtocol (HandlePointer[Index], > &gEfiDiskIoProtocolGuid, (VOID **)&DiskIo); > + if (EFI_ERROR (Status)) { > + continue; > + } > + > + Match =3D StrStr (MapPath, L";BLK"); > + if (Match) { > + MapPath =3D Match; > + MapPath++; > + } > + > + if (FirstTime) { > + BufferForSize =3D AllocateZeroPool (MAX_SIZE_BUF_SIZE * sizeof > (CHAR16)); > + if (BufferForSize =3D=3D NULL) { > + Status =3D EFI_OUT_OF_RESOURCES; > + PrintErr (L"Could not allocate memory for size buffer\n", Status= ); > + return Status; > + } > + Print (L" Device\t Size Comments\n"); > + Print (L" ------ ------- --------------------------------------= ---------------------- > \n"); > + FirstTime =3D FALSE; > + } > + GptCleanupGlobals (); > + FormatSize (MultU64x32 (BlkIo->Media->LastBlock + 1, BlkIo->Media- > >BlockSize), BufferForSize); > + ShellPrintHiiEx (-1, -1, > + NULL, STRING_TOKEN (STR_GPT_LIST_DEVS), > + gShellGptHiiHandle, > + MapPath, > + BufferForSize); > + if (BlkIo->Media->ReadOnly) { > + Print (L"Read-Only! "); > + } > + if (!BlkIo->Media->MediaPresent) { > + Print (L"No Media! "); > + } > + if (!EFI_ERROR (PartitionGetGptTables (DiskIo, BlkIo))) { > + Print (L"Valid GPT. "); > + } > + if (BlkIo->Media->RemovableMedia) { > + Print (L"Removable device."); > + } > + Print (L"\n"); > + DevCount++; > + } > + Print (L"\r\n"); > + if (DevCount) { > + Print (L"%d potentially partitionable device(s) found\n", DevCount); > + } else { > + Print (L"No potentially partitionable device(s) found\n"); > + } > + > + GptCleanupGlobals (); > + SHELL_FREE_NON_NULL (BufferForSize); > + > + return EFI_SUCCESS; > +} > + > +SHELL_STATUS > +EFIAPI > +ShellCommandRunGpt ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_SYSTEM_TABLE *SystemTable > + ) > +{ > + EFI_STATUS Status; > + LIST_ENTRY *CheckPackage; > + EFI_PHYSICAL_ADDRESS Address; > + EFI_PHYSICAL_ADDRESS Offset; > + UINT64 PartAttributes; > + EFI_GUID PartTypeGuid; > + SHELL_FILE_HANDLE FileHandle; > + UINT64 ByteCount; > + UINT64 FileSize; > + UINTN I; > + UINT8 *Buffer; > + UINT8 *FileBuffer; > + > + CHAR16 *ProblemParam; > + CHAR16 *FilePath; > + CONST CHAR16 *AddressStr; > + CONST CHAR16 *OffsetStr; > + CONST CHAR16 *PartName; > + CONST CHAR16 *NewPartName; > + CONST CHAR16 *AttrStr; > + CONST CHAR16 *GuidStr; > + CONST CHAR16 *VolumeName; > + CONST CHAR16 *LengthStr; > + CONST CHAR16 *FileStr; > + > + BOOLEAN AddrFlag; > + BOOLEAN LengthFlag; > + BOOLEAN FileFlag; > + BOOLEAN GuidFlag; > + BOOLEAN OffsetFlag; > + BOOLEAN PartNameFlag; > + BOOLEAN NewPartNameFlag; > + BOOLEAN AttrFlag; > + > + UINTN Flag; > + UINTN CheckFlag; > + > + CONST CHAR16 *BlockName; > + > + EFI_DEVICE_PATH_PROTOCOL *DevPath; > + EFI_BLOCK_IO_PROTOCOL *BlockIo; > + EFI_DISK_IO_PROTOCOL *DiskIo; > + EFI_HANDLE BlockIoHandle; > + MOD_PARAMS ModParams; > + EFI_PARTITION_ENTRY *Entry; > + > + UINTN NumKnownPartTypesEntries; > + > + BOOLEAN TableNotEmpty; > + BOOLEAN GptIsValid; > + BOOLEAN NoPrompt; > + BOOLEAN Quiet; > + BOOLEAN ForceFat16; > + > + UINT64 TimeStampB; > + UINT64 TimeStampE; > + UINT64 SpeedKB; > + UINT64 Freq; > + > + // Initialization > + Address =3D Offset =3D 0; > + PartAttributes =3D Flag =3D 0; > + ZeroMem (&PartTypeGuid, sizeof (EFI_GUID)); > + FileHandle =3D NULL; > + Buffer =3D FileBuffer =3D NULL; > + AddressStr =3D OffsetStr =3D PartName =3D NewPartName =3D AttrStr =3D = GuidStr =3D > + VolumeName =3D LengthStr =3D FileStr =3D NULL; > + AddrFlag =3D FileFlag =3D GuidFlag =3D NewPartNameFlag =3D AttrFlag = =3D FALSE; > + LengthFlag =3D OffsetFlag =3D PartNameFlag =3D TRUE; > + NoPrompt =3D ForceFat16 =3D FALSE; > + Quiet =3D TRUE; > + TimeStampB =3D 0; > + TimeStampE =3D 0; > + GptIsValid =3D FALSE; > + > + // Parse Shell command line > + Status =3D ShellInitialize (); > + if (EFI_ERROR (Status)) { > + PrintErr (L"Cannot initialize Shell", Status); > + ASSERT_EFI_ERROR (Status); > + return SHELL_ABORTED; > + } > + > + Status =3D ShellCommandLineParse (ParamList, &CheckPackage, > &ProblemParam, TRUE); > + if (EFI_ERROR (Status)) { > + PrintErr (L"Error while parsing command line", Status); > + return SHELL_ABORTED; > + } > + > + NoPrompt =3D ShellCommandLineGetFlag (CheckPackage, L"-yes"); > + Quiet =3D !ShellCommandLineGetFlag (CheckPackage, L"-verbose"); > + ForceFat16 =3D ShellCommandLineGetFlag (CheckPackage, L"-fat16"); > + > + Freq =3D GetPerformanceCounterProperties (NULL, NULL); > + > + // Check flags provided by user > + Flag |=3D (ShellCommandLineGetFlag (CheckPackage, L"clear") << 0); > + Flag |=3D (ShellCommandLineGetFlag (CheckPackage, L"create") << 1); > + Flag |=3D (ShellCommandLineGetFlag (CheckPackage, L"list") << 2); > + Flag |=3D (ShellCommandLineGetFlag (CheckPackage, L"sync") << 3); > + Flag |=3D (ShellCommandLineGetFlag (CheckPackage, L"typesinfo") << 4); > + Flag |=3D (ShellCommandLineGetFlag (CheckPackage, L"delete") << 5); > + Flag |=3D (ShellCommandLineGetFlag (CheckPackage, L"info") << 6); > + Flag |=3D (ShellCommandLineGetFlag (CheckPackage, L"read") << 7); > + Flag |=3D (ShellCommandLineGetFlag (CheckPackage, L"readfile") << 8); > + Flag |=3D (ShellCommandLineGetFlag (CheckPackage, L"rename") << 9); > + Flag |=3D (ShellCommandLineGetFlag (CheckPackage, L"setattr") << 10); > + Flag |=3D (ShellCommandLineGetFlag (CheckPackage, L"settype") << 11); > + Flag |=3D (ShellCommandLineGetFlag (CheckPackage, L"write") << 12); > + Flag |=3D (ShellCommandLineGetFlag (CheckPackage, L"writefile") << 13)= ; > + Flag |=3D (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 =3D 0; Index < NumKnownPartTypesEntries; Index++) { > + EFI_KNOWN_PARTITION_TYPE *PartType; > + > + PartType =3D PartitionGetKnownType (Index, NULL); > + if (PartType =3D=3D NULL) { > + break; > + } > + Print (L" %3d\t%-36s\t%g\n", Index, PartType->TypeName, &PartType- > >TypeGuid); > + } > + if (Flag =3D=3D TYPES_INFO) { > + return SHELL_SUCCESS; > + } > + } > + > + // Start parsing the command. > + BlockName =3D ShellCommandLineGetRawValue (CheckPackage, 1); > + if (BlockName =3D=3D NULL) { > + if (Flag & LIST) { > + Status =3D FindAndPrintPartitionableDevices (); > + if (EFI_ERROR (Status)) { > + PrintErr (L"Error getting list of partitionable devices", Status= ); > + goto CleanUp; > + } > + return Status; > + } > + PrintErr (L"Missing block device name", EFI_INVALID_PARAMETER); > + return SHELL_INVALID_PARAMETER; > + } > + > + // Find device handle by mapped name > + if (gEfiShellProtocol->GetDevicePathFromMap (BlockName) =3D=3D NULL) { > + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), > gShellGptHiiHandle, gAppName, BlockName); > + Status =3D SHELL_INVALID_PARAMETER; > + } else { > + DevPath =3D (EFI_DEVICE_PATH_PROTOCOL *)gEfiShellProtocol- > >GetDevicePathFromMap (BlockName); > + if (gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &DevPath, NULL) > =3D=3D EFI_NOT_FOUND) { > + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN > (STR_GEN_MAP_PROTOCOL), gShellGptHiiHandle, gAppName, BlockName, > L"BlockIo"); > + Status =3D SHELL_INVALID_PARAMETER; > + } > + } > + > + if (Status) { > + return SHELL_INVALID_PARAMETER; > + } > + > + BlockIoHandle =3D 0; > + > + Status =3D gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, > (EFI_DEVICE_PATH_PROTOCOL **)&DevPath, &BlockIoHandle); > + if (EFI_ERROR (Status)) { > + goto CleanUp; > + } > + > + Status =3D 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 =3D 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 =3D Flag; > + for (I =3D 0; CheckFlag; CheckFlag >>=3D 1) { > + I +=3D CheckFlag & 1; > + if (I > 1) { > + PrintErr (L"Too many flags", EFI_INVALID_PARAMETER); > + Status =3D SHELL_INVALID_PARAMETER; > + goto CleanUp; > + } > + } > + > + if (Flag & SYNC) { > + // Let the Partition table driver know that > + // we want to reread the tables > + Status =3D gBS->ReinstallProtocolInterface ( > + BlockIoHandle, > + &gEfiBlockIoProtocolGuid, > + BlockIo, > + BlockIo > + ); > + Status =3D 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 =3D SHELL_INVALID_PARAMETER; > + goto CleanUp; > + } > + > + if (!BlockIo->Media->MediaPresent) { > + PrintErr (L"Media is not present!\n", EFI_NO_MEDIA); > + Status =3D EFI_NO_MEDIA; > + goto CleanUp; > + } > + > + // Preload GPT tables with validation > + Status =3D PartitionGetGptTables (DiskIo, BlockIo); > + if (EFI_ERROR (Status)) { > + BOOLEAN CanContinue; > + > + CanContinue =3D (Flag & CREATE) || (Flag & CLEAR) || (Flag & > FAT_FORMAT); > + if (Status !=3D EFI_NOT_FOUND) { > + PrintErr (L"Unexpected error getting GPT tables", Status); > + goto CleanUp; > + } else { > + if (!CanContinue) { > + PrintErr (L"No GPT table found. Create first", Status); > + goto CleanUp; > + } > + } > + } else { > + GptIsValid =3D TRUE; > + } > + > + // Do we have any partitions already? > + TableNotEmpty =3D (PartitionFindPartitionByCriteria (NULL, 0, 0, SRC_A= NY) !=3D > NULL); > + > + Status =3D SHELL_INVALID_PARAMETER; > + > + if ((Flag < LIST) || > + (Flag & DELETE) || > + (Flag > READ_FILE) > + ) { > + if (BlockIo->Media->ReadOnly) { > + PrintErr (L"Cannot write to a read-only device", > EFI_INVALID_PARAMETER); > + Status =3D SHELL_INVALID_PARAMETER; > + goto CleanUp; > + } > + } > + > + if (BlockIo->Media->RemovableMedia) { > + Print (L"%s is a removable device. Just a note\n", BlockName); > + } > + > + switch (Flag) { > + case INFO: > + PartName =3D ShellCommandLineGetRawValue (CheckPackage, 2); > + OffsetFlag =3D FALSE; > + LengthFlag =3D FALSE; > + break; > + case LIST: > + { > + UINTN NumEntries; > + > + NumEntries =3D PartitionListGptEntries (); > + if (NumEntries =3D=3D 0) { > + Print (L"GPT is valid on %s, but no partition(s) defined yet\r\n= Use > create command to create a GPT partition\n", BlockName); > + } > + Status =3D 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, th= e > user is > + // responsible for operation because there is no confirmation (ass= uming > yes on all queries). > + if ((NoPrompt) || (!GptPromptYesNo (STRING_TOKEN > (STR_GPT_CLEAR_SURE)) && > + (!GptPromptYesNo (STRING_TOKEN > (STR_GPT_ABSOLUTELY_SURE)))) > + ) { > + PartitionGptClearAll (); > + } > + Status =3D SHELL_SUCCESS; > + goto CleanUp; > + break; > + case CREATE: > + PartName =3D ShellCommandLineGetRawValue (CheckPackage, 2); > + OffsetStr =3D ShellCommandLineGetRawValue (CheckPackage, 3); > + LengthStr =3D ShellCommandLineGetRawValue (CheckPackage, 4); > + AttrStr =3D ShellCommandLineGetRawValue (CheckPackage, 5); > + GuidStr =3D ShellCommandLineGetValue (CheckPackage, L"-type= "); > + GuidFlag =3D TRUE; > + break; > + case DELETE: > + PartName =3D ShellCommandLineGetRawValue (CheckPackage, 2); > + LengthFlag =3D FALSE; > + OffsetFlag =3D FALSE; > + break; > + case RENAME: > + PartName =3D ShellCommandLineGetRawValue (CheckPackage, 2); > + NewPartName =3D ShellCommandLineGetRawValue (CheckPackage, 3); > + NewPartNameFlag =3D TRUE; > + LengthFlag =3D FALSE; > + OffsetFlag =3D FALSE; > + break; > + case SETATTR: > + PartName =3D ShellCommandLineGetRawValue (CheckPackage, 2); > + AttrStr =3D ShellCommandLineGetRawValue (CheckPackage, 3); > + AttrFlag =3D TRUE; > + LengthFlag =3D FALSE; > + OffsetFlag =3D FALSE; > + break; > + case SETTYPE: > + PartName =3D ShellCommandLineGetRawValue (CheckPackage, 2); > + GuidStr =3D ShellCommandLineGetValue (CheckPackage, L"-type= "); > + GuidFlag =3D TRUE; > + LengthFlag =3D FALSE; > + OffsetFlag =3D FALSE; > + break; > + case FAT_FORMAT: > + PartName =3D ShellCommandLineGetRawValue (CheckPackage, 2); > + VolumeName =3D ShellCommandLineGetRawValue (CheckPackage, 3); > + LengthFlag =3D FALSE; > + OffsetFlag =3D FALSE; > + PartNameFlag =3D (PartName !=3D 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 =3D ShellCommandLineGetRawValue (CheckPackage, 2); > + PartName =3D ShellCommandLineGetRawValue (CheckPackage, 3); > + OffsetStr =3D ShellCommandLineGetRawValue (CheckPackage, 4); > + LengthStr =3D ShellCommandLineGetRawValue (CheckPackage, 5); > + AddrFlag =3D TRUE; > + break; > + case READ_FILE: > + FileStr =3D ShellCommandLineGetRawValue (CheckPackage, 2); > + PartName =3D ShellCommandLineGetRawValue (CheckPackage, 3); > + OffsetStr =3D ShellCommandLineGetRawValue (CheckPackage, 4); > + LengthStr =3D ShellCommandLineGetRawValue (CheckPackage, 5); > + FileFlag =3D TRUE; > + break; > + case WRITE_FILE: > + FileStr =3D ShellCommandLineGetRawValue (CheckPackage, 2); > + PartName =3D ShellCommandLineGetRawValue (CheckPackage, 3); > + OffsetStr =3D ShellCommandLineGetRawValue (CheckPackage, 4); > + LengthFlag =3D FALSE; > + FileFlag =3D TRUE; > + break; > + default: > + PrintErr (L"Unsupported or missing command. Try \"help gpt\"", > EFI_INVALID_PARAMETER); > + Status =3D SHELL_INVALID_PARAMETER; > + goto CleanUp; > + } > + > + // Read address parameter > + if ((AddressStr =3D=3D NULL) & AddrFlag) { > + PrintErr (L"No address parameter", EFI_INVALID_PARAMETER); > + goto CleanUp; > + } else if (AddrFlag) { > + Address =3D ShellHexStrToUintn (AddressStr); > + if (Address =3D=3D (UINTN)(-1)) { > + PrintErr (L"Wrong address parameter", EFI_INVALID_PARAMETER); > + goto CleanUp; > + } > + } > + > + if ((PartName =3D=3D 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 =3D=3D NULL) & OffsetFlag) { > + PrintErr (L"No offset Parameter", EFI_INVALID_PARAMETER); > + goto CleanUp; > + } else if (OffsetFlag) { > + Offset =3D ShellHexStrToUintn (OffsetStr); > + if (Offset < 0) { > + Print (L"%s: Wrong offset parameter: %s\n", gAppName, OffsetStr); > + goto CleanUp; > + } > + } > + > + // Read length parameter > + if ((LengthStr =3D=3D NULL) & LengthFlag) { > + PrintErr (L"No length parameter", EFI_INVALID_PARAMETER); > + goto CleanUp; > + } else if (LengthFlag) { > + ByteCount =3D (UINT64)ShellStrToUintn (LengthStr); > + if (ByteCount < 0) { > + Print (L"%s: Wrong length parameter %s!\n", gAppName, LengthStr); > + goto CleanUp; > + } > + } > + > + if ((NewPartName =3D=3D 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 =3D=3D NULL) & AttrFlag) { > + PrintErr (L"Missing attributes parameter", EFI_INVALID_PARAMETER); > + goto CleanUp; > + } else if (AttrStr) { > + PartAttributes =3D (UINT64)ShellStrToUintn (AttrStr); > + } > + > + if ((GuidStr =3D=3D NULL) & GuidFlag) { > + PrintErr (L"Missing partition type GUID parameter", > EFI_INVALID_PARAMETER); > + goto CleanUp; > + } else if (GuidFlag) { > + Status =3D SHELL_INVALID_PARAMETER; > + if (InternalShellIsHexOrDecimalNumber (GuidStr, FALSE, TRUE, FALSE))= { > + UINTN Ordinal; > + > + Ordinal =3D ShellStrToUintn (GuidStr); > + if (Ordinal < NumKnownPartTypesEntries) { > + PartTypeGuid =3D PartitionGetKnownType (Ordinal, NULL)->TypeGuid= ; > + Status =3D SHELL_SUCCESS; > + } else { > + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), > gShellGptHiiHandle, gAppName, GuidStr); > + goto CleanUp; > + } > + } else { > + Status =3D ConvertStringToGuid (GuidStr, &PartTypeGuid); > + if ((EFI_ERROR (Status)) || (IsZeroGuid (&PartTypeGuid))) { > + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), > gShellGptHiiHandle, gAppName, GuidStr); > + Status =3D SHELL_INVALID_PARAMETER; > + goto CleanUp; > + } > + } > + } > + > + if (FileFlag) { > + // Read FilePath parameter > + if (FileStr =3D=3D NULL) { > + PrintErr (L"No FilePath parameter", EFI_INVALID_PARAMETER); > + goto CleanUp; > + } else { > + FilePath =3D (CHAR16 *)FileStr; > + Status =3D 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 =3D SHELL_INVALID_PARAMETER; > + goto CleanUp; > + } > + } > + > + Status =3D OpenAndPrepareFile (FilePath, &FileHandle, ((Flag & READ_= FILE) > !=3D 0)); > + if (EFI_ERROR (Status)) { > + Print (L"Error %r while preparing file %s", Status, FilePath); > + goto CleanUp; > + } > + > + // Get file size in order to check correctness at the end of transfe= r > + if (Flag & (WRITE_FILE)) { > + Status =3D FileHandleGetSize (FileHandle, &FileSize); > + if (EFI_ERROR (Status)) { > + PrintErr (L"Cannot get file size", Status); > + goto CleanUp; > + } > + ByteCount =3D (UINT64)FileSize; > + } > + > + FileBuffer =3D AllocateZeroPool ((UINTN)ByteCount); > + if (FileBuffer =3D=3D NULL) { > + PrintErr (L"Cannot allocate memory", EFI_OUT_OF_RESOURCES); > + Status =3D 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 =3D FileHandleRead (FileHandle, &ByteCount, FileBuffer); > + if (EFI_ERROR (Status)) { > + PrintErr (L"Read from file error", Status); > + goto Error_Free_Buffer; > + } else if (ByteCount !=3D (UINTN)FileSize) { > + PrintErr (L"Not whole file read. Abort", EFI_DEVICE_ERROR); > + Status =3D SHELL_DEVICE_ERROR; > + goto Error_Free_Buffer; > + } > + if (!Quiet) { > + Print (L"Writing %s into device %s, partition %s...\n", FilePath= , > BlockName, PartName); > + } > + } > + } > + > + Buffer =3D (UINT8 *)Address; > + if (FileFlag) { > + Buffer =3D FileBuffer; > + } > + > + if (Flag > TYPES_INFO) { > + Entry =3D PartitionFindPartitionByCriteria (PartName, 0, 0, SRC_BY_N= AME); > + if (!Entry && PartName && (InternalShellIsHexOrDecimalNumber > (PartName, FALSE, TRUE, FALSE))) { > + Entry =3D 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 t= he name > is spelled properly\n", PartName); > + Status =3D SHELL_NOT_FOUND; > + goto CleanUp; > + } > + } > + > + switch (Flag) { > + case CREATE: > + if (!TableNotEmpty && !GptIsValid) { > + if (!NoPrompt) { > + // Ask a user to confirm re-init of the GPT if > + // It was not present before create was invoked > + if ((GptPromptYesNo (STRING_TOKEN (STR_GPT_CLEAR_SURE))) || > + (GptPromptYesNo (STRING_TOKEN (STR_GPT_ABSOLUTELY_SURE)))) > { > + goto CleanUp; > + } > + } > + } > + > + Status =3D PartitionGptCreatePartition ( > + PartName, > + Offset, // Lba. If 0, the next available is assumed > + ByteCount, // in MegaBytes. If 0 the whole remaining space is as= sumed > + PartAttributes, > + PartTypeGuid); > + break; > + case DELETE: > + ModParams.PartName =3D PartName; > + ShellPrintHiiEx (-1, -1, > + NULL, STRING_TOKEN (STR_GPT_DELETE_WARNING), > + gShellGptHiiHandle, > + Entry->PartitionName > + ); > + if ((NoPrompt) || (!GptPromptYesNo (STRING_TOKEN > (STR_GPT_ABSOLUTELY_SURE)))) { > + Status =3D PartitionGptModifyPartition ( > + Entry, &ModParams, MOD_DELETE); > + if (EFI_ERROR (Status)) { > + PrintErr (L"Error deleting the partition", Status); > + goto CleanUp; > + } > + Status =3D SHELL_SUCCESS; > + } else { > + Status =3D SHELL_ABORTED; > + } > + break; > + case FAT_FORMAT: > + { > + EFI_LBA StartingLBA; > + EFI_LBA EndingLBA; > + CHAR8 LabelName[12]; > + CHAR16 *FormatType; > + > + if (VolumeName) { > + if (StrLen (VolumeName) > FAT_LABEL_LENGTH) { > + Status =3D EFI_INVALID_PARAMETER; > + PrintErr (L"The volume label is too long", Status); > + Status =3D 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 =3D 0; > + EndingLBA =3D BlockIo->Media->LastBlock; > + if (Entry) { > + StartingLBA =3D Entry->StartingLBA; > + EndingLBA =3D Entry->EndingLBA; > + } > + FormatType =3D FAT32_FORMAT; > + if (ForceFat16) { > + UINT64 VolumeSectors; > + > + FormatType =3D FAT16_FORMAT; > + VolumeSectors =3D DivU64x32 ( > + MultU64x32 ( > + EndingLBA - StartingLBA + 1, BlockIo->Media->BlockSize), > + FAT_SECTOR_SIZE); > + if (VolumeSectors > FAT16_MAX_SECTORS) { > + FormatType =3D FAT32_FORMAT; > + Print (L"Note: this volume will be formatted as FAT32 (too m= any > sectors for FAT16)\n"); > + } > + } > + if (!Quiet) { > + Print (L"Formatting %s to %s...\r", PartNameFlag ? Entry- > >PartitionName : BlockName, FormatType); > + } > + Status =3D FatFormat (StartingLBA, EndingLBA, BlockIo, DiskIo, > VolumeName ? LabelName : NULL, !ForceFat16); > + if (EFI_ERROR (Status)) { > + PrintErr (L"Error formatting the partition ", = Status); > + goto CleanUp; > + } else if (!Quiet) { > + Print (L"%s successfully formatted to %s. Formatted size %llu = MiB\n", > + PartNameFlag ? Entry->PartitionName : BlockName, > + FormatType, > + MultU64x32 (EndingLBA - StartingLBA + 1, BlockIo->Media= - > >BlockSize) >> 20 > + ); > + } > + } else { > + Status =3D SHELL_ABORTED; > + } > + } > + break; > + case RENAME: > + ModParams.PartName =3D PartName; > + ModParams.NewName =3D NewPartName; > + Status =3D PartitionGptModifyPartition ( > + Entry, &ModParams, MOD_RENAME); > + break; > + case SETATTR: > + ModParams.Attributes =3D PartAttributes; > + Status =3D PartitionGptModifyPartition ( > + Entry, &ModParams, MOD_ATTR); > + break; > + case SETTYPE: > + ModParams.PartTypeGuid =3D PartTypeGuid; > + Status =3D PartitionGptModifyPartition ( > + Entry, &ModParams, MOD_TYPE); > + break; > + case INFO: > + PartitionPrintGptPartInfo (Entry); > + Status =3D SHELL_SUCCESS; > + break; > + case READ: > + case READ_FILE: > + case WRITE: > + case WRITE_FILE: > + { > + UINT64 MaxBytes; > + BOOLEAN OpRead; > + > + OpRead =3D ((Flag & READ) || (Flag & READ_FILE)); > + MaxBytes =3D MultU64x32 ( > + Entry->EndingLBA - Entry->StartingLBA, > + BlockIo->Media->BlockSize) + > + BlockIo->Media->BlockSize - > + MultU64x32 (Offset, BlockIo->Media->BlockSize); > + if (ByteCount > MaxBytes) { > + Status =3D 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 =3D SHELL_INVALID_PARAMETER; > + goto CleanUp; > + } > + > + TimeStampB =3D GetPerformanceCounter (); > + if (OpRead) { > + Status =3D DiskIo->ReadDisk (DiskIo, > + BlockIo->Media->MediaId, > + MultU64x32 (Offset + Entry->StartingL= BA, BlockIo- > >Media->BlockSize), ByteCount, Buffer); > + } else { > + Status =3D DiskIo->WriteDisk (DiskIo, BlockIo->Media->MediaId, > + MultU64x32 (Offset + Entry->Starting= LBA, BlockIo- > >Media->BlockSize), ByteCount, Buffer); > + } > + } > + break; > + default: > + Status =3D SHELL_INVALID_PARAMETER; > + PrintErr (L"Unknown command. Try \"help gpt\"", > EFI_INVALID_PARAMETER); > + goto CleanUp; > + } > + > + if (EFI_ERROR (Status)) { > + PrintErr (L"Error while performing transfer\n", Status); > + goto CleanUp; > + } > + > + TimeStampE =3D ((GetPerformanceCounter () - TimeStampB) * 1000) / Freq= ; > + SpeedKB =3D 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 =3D FileHandleWrite (FileHandle, &ByteCount, FileBuffer); > + if (EFI_ERROR (Status)) { > + ShellPrintHiiEx (-1, -1, > + NULL, > + STRING_TOKEN (STR_GPT_FILE_WRITE_FAIL), > + gShellGptHiiHandle, > + gAppName, > + FilePath, > + Status > + ); > + Status =3D 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 !=3D NULL) { > + ShellCloseFile (&FileHandle); > + FileHandle =3D NULL; > + } > + } > + > + Status =3D 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 =3D SHELL_ABORTED; > + } > + > + return Status; > +} > + > +EFI_STATUS > +EFIAPI > +ShellGptLibConstructor ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_SYSTEM_TABLE *SystemTable > + ) > +{ > + gShellGptHiiHandle =3D NULL; > + > + gShellGptHiiHandle =3D HiiAddPackages ( > + &gShellGptHiiGuid, gImageHandle, > + UefiShellGptCommandLibStrings, NULL > + ); > + if (gShellGptHiiHandle =3D=3D 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 !=3D NULL) { > + HiiRemovePackages (gShellGptHiiHandle); > + } > + return EFI_SUCCESS; > +} > diff --git > a/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf > b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf > new file mode 100644 > index 000000000000..9b3a6f56c9b7 > --- /dev/null > +++ > b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf > @@ -0,0 +1,74 @@ > +# > +# Copyright (C) 2016, Marvell International Ltd. All rights reserved. > +# Copyright (C) 2016, Broadcom. All rights reserved > +# > +# Redistribution and use in source and binary forms, with or without > +# modification, are permitted provided that the following conditions are > met: > +# > +# * Redistributions of source code must retain the above copyright notic= e, > +# this list of conditions and the following disclaimer. > +# > +# * Redistributions in binary form must reproduce the above copyright > +# notice, this list of conditions and the following disclaimer in the > +# documentation and/or other materials provided with the distribution. > +# > +# * Neither the name of Marvell nor the names of its contributors may be > +# used to endorse or promote products derived from this software without > +# specific prior written permission. > +# > +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND > CONTRIBUTORS "AS IS" > +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT > LIMITED TO, THE > +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A > PARTICULAR PURPOSE ARE > +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR > CONTRIBUTORS BE LIABLE > +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > CONSEQUENTIAL > +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF > SUBSTITUTE GOODS OR > +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) > HOWEVER > +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, > STRICT LIABILITY, > +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY > OUT OF THE USE > +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH > DAMAGE. > +# > + > +[Defines] > + INF_VERSION =3D 0x00010006 > + BASE_NAME =3D UefiShellGptCommandLib > + FILE_GUID =3D F62ACF25-0D15-22F5-E642-FFB6515E00D7 > + MODULE_TYPE =3D UEFI_APPLICATION > + VERSION_STRING =3D 0.1 > + LIBRARY_CLASS =3D NULL|UEFI_APPLICATION UEFI_DRIVER > + CONSTRUCTOR =3D ShellGptLibConstructor > + DESTRUCTOR =3D ShellGptLibDestructor > + > +[Sources] > + FatFormat.c > + GptWorker.c > + UefiShellGptCommandLib.c > + UefiShellGptCommandLib.uni > + > +[Packages] > + MdeModulePkg/MdeModulePkg.dec > + MdePkg/MdePkg.dec > + ShellPkg/ShellPkg.dec > + > +[LibraryClasses] > + BaseLib > + BaseMemoryLib > + DebugLib > + DevicePathLib > + FileHandleLib > + HiiLib > + MemoryAllocationLib > + PcdLib > + ShellCommandLib > + ShellLib > + UefiBootServicesTableLib > + UefiRuntimeServicesTableLib > + UefiLib > + > +[Protocols] > + gEfiBlockIoProtocolGuid > + gEfiDevicePathProtocolGuid > + gEfiDiskIoProtocolGuid > + > +[Guids] > + gShellGptHiiGuid > + gEfiPartTypeUnusedGuid ## SOMETIMES_CONSUMES ## = GUID > diff --git > a/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni > b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni > new file mode 100644 > index 000000000000..c0ad20a7f7cd > --- /dev/null > +++ > b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni > @@ -0,0 +1,113 @@ > +/********************************************************* > ********************** > +Copyright (C) 2016 Marvell International Ltd. All rights reserved > +Copyright (C) 2016, Broadcom. All rights reserved */ > + > +Redistribution and use in source and binary forms, with or without > modification, > +are permitted provided that the following conditions are met: > + > + * Redistributions of source code must retain the above copyright > notice, > + this list of conditions and the following disclaimer. > + > + * Redistributions in binary form must reproduce the above copyri= ght > + notice, this list of conditions and the following disclaimer i= n the > + documentation and/or other materials provided with the distrib= ution. > + > + * 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. > + > +********************************************************* > **********************/ > + > +/=3D# > + > +#langdef en-US "english" > + > +#string STR_GEN_PARAM_INV #language en-US "%H%s%N: Invalid > argument - '%H%s%N'\r\n" > +#string STR_GEN_MAP_PROTOCOL #language en-US "%H%s%N: > Mapped device '%B%s%N' does not have protocol %B%s%N\r\n" > + > +#string STR_GPT_ERROR #language en-US "%H%s%N: %r - %s\r\n" > +#string STR_GPT_NOT_EMPTY #language en-US "%H%s%N: > WARNING!!! This device has valid GPT partition tables!\r\n" > +#string STR_GPT_CLEAR_SURE #language en-US "Are you sure you want > to (re)inintialize GPT tables on this device? %BY%Nes, %BN%No " > +#string STR_GPT_ABSOLUTELY_SURE #language en-US "\r\nAre you *** > ABSOLUTELY SURE *** you want to perform this operation ? %BY%Nes, > %BN%No " > +#string STR_GPT_FORMAT_WARNING #language en-US "%H%s%N: > WARNING!!! Formatting of this partition will destroy all data on it!\r\n" > +#string STR_GPT_FORMAT_SURE #language en-US "Are you sure you > want to format this partition and destroy all data on it ? %BY%Nes, %BN%N= o > " > +#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 | -typesinf= o | - > 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 pa= rtition to > store/load data\r\n" > +" FilePath - Path to file to read data into or write/update data = from\r\n" > +" -yes - Assume yes for all queries, do not prompt\r\n > +" -verbose - Print additional information on operation\r\n" > +" -fat16 - (For format only, has no effect for anything else) -= Format to > FAT16 if possible\r\n\r\n" > +".SH EXAMPLES\r\n" > +" \r\n" > +"EXAMPLES:\r\n" > +"Get info on the particular partition with name PartitionName on the blo= ck > device blk0:\r\n" > +" gpt %Hinfo%N blk0: PartitionName\r\n" > +"List all available GPT partitions on the block device blk0:\r\n" > +" gpt %Hlist%N blk0:\r\n" > +"Note: the ordinal number shown by this command can be used as a > partition name in any command requiring partition name\r\n" > +"Thus gpt info blk0: 1 is valid if there is a partition with ordinal 1 p= resent 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 d= evice > 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 utili= ty, > 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 blo= ck > device blk0: into file fs2:file.bin\r\n" > +" gpt %Hreadfile%N blk0: fs2:file.bin PartitionName 0x0 0x3000\r\n" > +"Write contents of file fs2:file.bin into partition named PartitionName = with > offset (in lba) 0x10 on a block device blk0:\r\n" > +" gpt %Hwritefile%N blk0: fs2:file.bin PartitionName 0x10\r\n" > +"FAT Format the partition PartitionName on block device blk0:\r\n" > +" gpt %Hfatformat%N blk0: PartitionName\r\n" > +"FAT Format the whole device blk0:\r\n" > +" gpt fatformat blk0:\r\n" > + > +".SH RETURNVALUES\r\n" > +" \r\n" > +"RETURN VALUES:\r\n" > +" SHELL_SUCCESS The action was completed as requested.\r\n" > +" Specific Shell error Error while processing command\r\n" > diff --git a/ShellPkg/ShellPkg.dec b/ShellPkg/ShellPkg.dec > index bb31c2df8cb3..5f73379f9eec 100644 > --- a/ShellPkg/ShellPkg.dec > +++ b/ShellPkg/ShellPkg.dec > @@ -56,6 +56,7 @@ [Guids] > gShellNetwork2HiiGuid =3D {0x174b2b5, 0xf505, 0x4b12, {0xaa,= 0x60, > 0x59, 0xdf, 0xf8, 0xd6, 0xea, 0x37}} > gShellTftpHiiGuid =3D {0x738a9314, 0x82c1, 0x4592, {0x8f= , 0xf7, 0xc1, > 0xbd, 0xf1, 0xb2, 0x0e, 0xd4}} > gShellBcfgHiiGuid =3D {0x5f5f605d, 0x1583, 0x4a2d, {0xa6= , 0xb2, 0xeb, > 0x12, 0xda, 0xb4, 0xa2, 0xb6}} > + gShellGptHiiGuid =3D {0x5a1ed739, 0x5ef1, 0x429a, {0x8d= , 0xf8, 0x28, > 0xc9, 0x92, 0x64, 0xd7, 0xf8}} >=20 > [Protocols] > gEfiShellEnvironment2Guid =3D {0x47c7b221, 0xc42a, 0x11d2, {= 0x8e, > 0x57, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}} > diff --git a/ShellPkg/ShellPkg.dsc b/ShellPkg/ShellPkg.dsc > index 6b7864bac395..b6a8072dedb5 100644 > --- a/ShellPkg/ShellPkg.dsc > +++ b/ShellPkg/ShellPkg.dsc > @@ -91,6 +91,7 @@ [Components] >=20 > ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib > .inf >=20 > ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib > .inf >=20 > ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsL > ib.inf > + ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf >=20 > ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLi > b.inf >=20 > ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1Commands > Lib.inf >=20 > ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1Comm > andsLib.inf > @@ -121,6 +122,9 @@ [Components] > !ifdef $(INCLUDE_TFTP_COMMAND) >=20 > 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) > } >=20 > -- > 1.9.1 >=20 > _______________________________________________ > edk2-devel mailing list > edk2-devel@lists.01.org > https://lists.01.org/mailman/listinfo/edk2-devel