From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pf0-x22b.google.com (mail-pf0-x22b.google.com [IPv6:2607:f8b0:400e:c00::22b]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 98A651A1E3C for ; Sat, 15 Oct 2016 22:25:03 -0700 (PDT) Received: by mail-pf0-x22b.google.com with SMTP id s8so66217995pfj.2 for ; Sat, 15 Oct 2016 22:25:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=o7z6FDwzlfJzDR2iUIEztUvY3iLjgd2/ayEVtJ+vgoI=; b=WzuJoshb6lRKQGBkRLNTWf6hMWaK9t6hJXJFD7PjTYwkIMh99NTLiJwr5Tkwo+7YCS uwI/41cRc68sgvtcdAvGV9fMQrsu7q38iSPoBxWKTh7lNOL2uAb0Z5uj3hZfXNYH9okE 9RadXcRocdVEbOD4xUe57OX2JfImNiQ1s85kA= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=o7z6FDwzlfJzDR2iUIEztUvY3iLjgd2/ayEVtJ+vgoI=; b=kAb3uqlnpKercyHFPx4TtjMFxbfx2yWyU20beWOOYtsLDOrx/8PVhQaj2/FG4Xq9QU tZ4cwmYay0hO+LolQS4y+4YK7HzjkHZ0ZnoN+kVUBTBD0mCSU5PboYZw48WMS0THRnG9 r+V8+Glz9unRk/9OmRBJFSv9BkjGCFmAml/cielq2lu4pcPWZOWtrLej/7s7L6rR5X+v 6KYeyg2K1LH9e8DQ35k+bYS5tlYfeNobDp+wES0d6dNfuAaXYhDcVhoFvgVwOQvyy4ce g27KbVxB8VZHrCnOUYPNczbPNgjP9Z0A3PSuS5AlmRIX3+QLa85isJV49QLKUfa/YE3J 0aaA== X-Gm-Message-State: AA6/9RmJxoZ2fITtUg2y4G+UG6IFwE8EaxxHW9yfsbT5vWWVSe6eeUzyWk41i0i4OBaTnDCW X-Received: by 10.99.60.19 with SMTP id j19mr24096468pga.8.1476595502417; Sat, 15 Oct 2016 22:25:02 -0700 (PDT) Received: from LBRMN-LNXUB114.ric.broadcom.com ([216.31.219.19]) by smtp.gmail.com with ESMTPSA id 21sm24676936pfs.88.2016.10.15.22.25.00 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sat, 15 Oct 2016 22:25:01 -0700 (PDT) From: Vladimir Olovyannikov To: jaben.carsey@intel.com, edk2-devel@lists.01.org, ruiyu.ni@intel.com Cc: Vladimir Olovyannikov Date: Sat, 15 Oct 2016 22:23:40 -0700 Message-Id: <1476595420-12566-1-git-send-email-vladimir.olovyannikov@broadcom.com> X-Mailer: git-send-email 1.9.1 MIME-Version: 1.0 Subject: [PATCH] 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: Sun, 16 Oct 2016 05:25:03 -0000 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows managing (create, delete, modify, fat format) of GPT partitions from within UEFI Shell. Syntax: gpt [device_mapped_name] [parameters...] See usage examples in the .uni file --- .../Library/UefiShellGptCommandLib/FatFormat.c | 611 +++++++ .../Library/UefiShellGptCommandLib/FatFormat.h | 111 ++ .../Library/UefiShellGptCommandLib/GptWorker.c | 1902 ++++++++++++++++++++ .../Library/UefiShellGptCommandLib/GptWorker.h | 186 ++ .../UefiShellGptCommandLib.c | 1135 ++++++++++++ .../UefiShellGptCommandLib.inf | 79 + .../UefiShellGptCommandLib.uni | 117 ++ ShellPkg/ShellPkg.dec | 1 + ShellPkg/ShellPkg.dsc | 4 + 9 files changed, 4146 insertions(+) create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf create mode 100644 ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni diff --git a/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c new file mode 100644 index 000000000000..ba7904e6be28 --- /dev/null +++ b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.c @@ -0,0 +1,611 @@ +/** @file + + Copyright (c) 2003 - 2012, Rob Riglar, Ultra-Embedded.com. All rights reserved
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +/* Portions Copyright (c) 2016, Broadcom. All rights reserved */ + +#include "FatFormat.h" + +//----------------------------------------------------------------------------- +// Tables +//----------------------------------------------------------------------------- +typedef struct +{ + UINT64 Sectors; + UINT8 SectorsPerCluster; +} SectorsPerClusterTable; + +STATIC SectorsPerClusterTable ClusterSizeTable16[] = +{ + { 32680, 2 }, // 16MB - 1K + { 262144, 4 }, // 128MB - 2K + { 524288, 8 }, // 256MB - 4K + { 1048576, 16 }, // 512MB - 8K + { 2097152, 32 }, // 1GB - 16K + { 4194304, 64 }, // 2GB - 32K + { 8388608, 128 }, // 2GB - 64K [Warning only supported by Windows XP onwards] + { 0, 0 } // Invalid +}; + +STATIC SectorsPerClusterTable ClusterSizeTable32[] = +{ + { 532480, 1 }, // 260MB - 512b + { 16777216, 8 }, // 8GB - 4K + { 33554432, 16 }, // 16GB - 8K + { 67108864, 32 }, // 32GB - 16K + { 0xFFFFFFFF, 64 }, // >32GB - 32K + { 0, 0 } // Invalid +}; + +STATIC +EFI_LBA LbaOfCluster ( + IN FATFS *Fs, + IN UINT64 ClusterNumber + ) +{ + if (Fs->FatType == FAT_TYPE_16) + return (Fs->ClusterBeginLba + + (Fs->RootEntryCount * 32 / FAT_SECTOR_SIZE) + + ((ClusterNumber - 2) * Fs->SectorsPerCluster)); + else + return ((Fs->ClusterBeginLba + + ((ClusterNumber - 2) * Fs->SectorsPerCluster))); +} + +//----------------------------------------------------------------------------- +// fatfs_calc_cluster_size: Calculate what cluster size should be used +//----------------------------------------------------------------------------- +STATIC +UINT8 CalcClusterSize ( + IN UINTN Sectors, + IN BOOLEAN IsFat32) +{ + UINTN Index; + + if (!IsFat32) { + for (Index = 0; ClusterSizeTable16[Index].SectorsPerCluster != 0; Index++) + if (Sectors <= ClusterSizeTable16[Index].Sectors) + return ClusterSizeTable16[Index].SectorsPerCluster; + } else { + for (Index = 0; ClusterSizeTable32[Index].SectorsPerCluster != 0; Index++) + if (Sectors <= ClusterSizeTable32[Index].Sectors) + return ClusterSizeTable32[Index].SectorsPerCluster; + } + + return 0; +} +//----------------------------------------------------------------------------- +// fatfs_erase_sectors: Erase a number of sectors +//----------------------------------------------------------------------------- +STATIC +EFI_STATUS +EraseSectors ( + IN FATFS *Fs, + IN EFI_LBA Lba, + IN UINTN Count + ) +{ + UINTN Index; + EFI_STATUS Status; + + // Zero Sector first + ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE); + + for (Index = 0; Index < Count; Index++) + Status = Fs->DiskIo->WriteDisk ( + Fs->DiskIo, Fs->BlockIo->Media->MediaId, + MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) + + MultU64x32 ((Lba + Index), FAT_SECTOR_SIZE), + FAT_SECTOR_SIZE, Fs->CurrentSector.Sector); + + return Status; +} +//----------------------------------------------------------------------------- +// fatfs_create_boot_sector: Create the boot Sector +//----------------------------------------------------------------------------- +STATIC +EFI_STATUS +CreateBootSector ( + IN FATFS *Fs, + IN EFI_LBA BootSectorLba, + IN UINT64 VolSectors, + IN CONST CHAR8 *Name, + IN BOOLEAN IsFat32 + ) +{ + UINTN TotalClusters; + UINTN Index; + EFI_STATUS Status; + + // Zero Sector initially + ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE); + + // OEM Name & Jump Code + Fs->CurrentSector.Sector[0] = 0xEB; + Fs->CurrentSector.Sector[1] = 0x3C; + Fs->CurrentSector.Sector[2] = 0x90; + Fs->CurrentSector.Sector[3] = 0x4D; + Fs->CurrentSector.Sector[4] = 0x53; + Fs->CurrentSector.Sector[5] = 0x44; + Fs->CurrentSector.Sector[6] = 0x4F; + Fs->CurrentSector.Sector[7] = 0x53; + Fs->CurrentSector.Sector[8] = 0x35; + Fs->CurrentSector.Sector[9] = 0x2E; + Fs->CurrentSector.Sector[10] = 0x30; + + // Bytes per Sector + Fs->CurrentSector.Sector[11] = (FAT_SECTOR_SIZE >> 0) & 0xFF; + Fs->CurrentSector.Sector[12] = (FAT_SECTOR_SIZE >> 8) & 0xFF; + + // Get sectors per cluster size for the disk + Fs->SectorsPerCluster = CalcClusterSize (VolSectors, IsFat32); + if (!Fs->SectorsPerCluster) + return 0; // Invalid disk size + + // Sectors per cluster + Fs->CurrentSector.Sector[13] = Fs->SectorsPerCluster; + + // Reserved Sectors + if (!IsFat32) + Fs->ReservedSectors = 8; + else + Fs->ReservedSectors = 32; + Fs->CurrentSector.Sector[14] = (Fs->ReservedSectors >> 0) & 0xFF; + Fs->CurrentSector.Sector[15] = (Fs->ReservedSectors >> 8) & 0xFF; + + // Number of FATS + Fs->NumOfFats = 2; + Fs->CurrentSector.Sector[16] = Fs->NumOfFats; + + // Max entries in root dir (FAT16 only) + if (!IsFat32) { + Fs->RootEntryCount = 512; + Fs->CurrentSector.Sector[17] = (Fs->RootEntryCount >> 0) & 0xFF; + Fs->CurrentSector.Sector[18] = (Fs->RootEntryCount >> 8) & 0xFF; + } else { + Fs->RootEntryCount = 0; + Fs->CurrentSector.Sector[17] = 0; + Fs->CurrentSector.Sector[18] = 0; + } + + // [FAT16] Total sectors (use FAT32 count instead) + Fs->CurrentSector.Sector[19] = 0x00; + Fs->CurrentSector.Sector[20] = 0x00; + + // Media type + Fs->CurrentSector.Sector[21] = 0xF8; + + + // FAT16 BS Details + if (!IsFat32) { + // Count of sectors used by the FAT table (FAT16 only) + TotalClusters = (VolSectors / Fs->SectorsPerCluster) + 1; + Fs->FatSectors = (TotalClusters / (FAT_SECTOR_SIZE / 2)) + 1; + Fs->CurrentSector.Sector[22] = (UINT8)((Fs->FatSectors >> 0) & 0xFF); + Fs->CurrentSector.Sector[23] = (UINT8)((Fs->FatSectors >> 8) & 0xFF); + + // Sectors per track + Fs->CurrentSector.Sector[24] = 0x00; + Fs->CurrentSector.Sector[25] = 0x00; + + // Heads + Fs->CurrentSector.Sector[26] = 0x00; + Fs->CurrentSector.Sector[27] = 0x00; + + // Hidden sectors + Fs->CurrentSector.Sector[28] = 0x20; + Fs->CurrentSector.Sector[29] = 0x00; + Fs->CurrentSector.Sector[30] = 0x00; + Fs->CurrentSector.Sector[31] = 0x00; + + // Total sectors for this volume + Fs->CurrentSector.Sector[32] = (UINT8)((VolSectors >> 0) & 0xFF); + Fs->CurrentSector.Sector[33] = (UINT8)((VolSectors >> 8) & 0xFF); + Fs->CurrentSector.Sector[34] = (UINT8)((VolSectors >> 16) & 0xFF); + Fs->CurrentSector.Sector[35] = (UINT8)((VolSectors >> 24) & 0xFF); + + // Drive number + Fs->CurrentSector.Sector[36] = 0x00; + + // Reserved + Fs->CurrentSector.Sector[37] = 0x00; + + // Boot signature + Fs->CurrentSector.Sector[38] = 0x29; + + // Volume ID + Fs->CurrentSector.Sector[39] = 0x12; + Fs->CurrentSector.Sector[40] = 0x34; + Fs->CurrentSector.Sector[41] = 0x56; + Fs->CurrentSector.Sector[42] = 0x78; + + // Volume name + for (Index = 0; Index < 11; Index++) { + if (Index < AsciiStrLen (Name)) + Fs->CurrentSector.Sector[Index + 43] = Name[Index]; + else + Fs->CurrentSector.Sector[Index + 43] = ' '; + } + + // File sys type + Fs->CurrentSector.Sector[54] = 'F'; + Fs->CurrentSector.Sector[55] = 'A'; + Fs->CurrentSector.Sector[56] = 'T'; + Fs->CurrentSector.Sector[57] = '1'; + Fs->CurrentSector.Sector[58] = '6'; + Fs->CurrentSector.Sector[59] = ' '; + Fs->CurrentSector.Sector[60] = ' '; + Fs->CurrentSector.Sector[61] = ' '; + + // Signature + Fs->CurrentSector.Sector[510] = 0x55; + Fs->CurrentSector.Sector[511] = 0xAA; + } + // FAT32 BS Details + else { + // Count of sectors used by the FAT table (FAT16 only) + Fs->CurrentSector.Sector[22] = 0; + Fs->CurrentSector.Sector[23] = 0; + + // Sectors per track (default) + Fs->CurrentSector.Sector[24] = 0x3F; + Fs->CurrentSector.Sector[25] = 0x00; + + // Heads (default) + Fs->CurrentSector.Sector[26] = 0xFF; + Fs->CurrentSector.Sector[27] = 0x00; + + // Hidden sectors + Fs->CurrentSector.Sector[28] = 0x00; + Fs->CurrentSector.Sector[29] = 0x00; + Fs->CurrentSector.Sector[30] = 0x00; + Fs->CurrentSector.Sector[31] = 0x00; + + // Total sectors for this volume + Fs->CurrentSector.Sector[32] = (UINT8)((VolSectors >> 0) & 0xFF); + Fs->CurrentSector.Sector[33] = (UINT8)((VolSectors >> 8) & 0xFF); + Fs->CurrentSector.Sector[34] = (UINT8)((VolSectors >> 16) & 0xFF); + Fs->CurrentSector.Sector[35] = (UINT8)((VolSectors >> 24) & 0xFF); + + TotalClusters = (VolSectors / Fs->SectorsPerCluster) + 1; + Fs->FatSectors = (TotalClusters / (FAT_SECTOR_SIZE / 4)) + 1; + + // BPB_FATSz32 + Fs->CurrentSector.Sector[36] = (UINT8)((Fs->FatSectors >> 0) & 0xFF); + Fs->CurrentSector.Sector[37] = (UINT8)((Fs->FatSectors >> 8) & 0xFF); + Fs->CurrentSector.Sector[38] = (UINT8)((Fs->FatSectors >> 16) & 0xFF); + Fs->CurrentSector.Sector[39] = (UINT8)((Fs->FatSectors >> 24) & 0xFF); + + // BPB_ExtFlags + Fs->CurrentSector.Sector[40] = 0; + Fs->CurrentSector.Sector[41] = 0; + + // BPB_FSVer + Fs->CurrentSector.Sector[42] = 0; + Fs->CurrentSector.Sector[43] = 0; + + // BPB_RootClus + Fs->CurrentSector.Sector[44] = (UINT8)((Fs->RootdirFirstCluster >> 0) & 0xFF); + Fs->CurrentSector.Sector[45] = (UINT8)((Fs->RootdirFirstCluster >> 8) & 0xFF); + Fs->CurrentSector.Sector[46] = (UINT8)((Fs->RootdirFirstCluster >> 16) & 0xFF); + Fs->CurrentSector.Sector[47] = (UINT8)((Fs->RootdirFirstCluster >> 24) & 0xFF); + + // BPB_FSInfo + Fs->CurrentSector.Sector[48] = (UINT8)((Fs->FsInfoSector >> 0) & 0xFF); + Fs->CurrentSector.Sector[49] = (UINT8)((Fs->FsInfoSector >> 8) & 0xFF); + + // BPB_BkBootSec + Fs->CurrentSector.Sector[50] = 6; + Fs->CurrentSector.Sector[51] = 0; + + // Drive number + Fs->CurrentSector.Sector[64] = 0x00; + + // Boot signature + Fs->CurrentSector.Sector[66] = 0x29; + + // Volume ID + Fs->CurrentSector.Sector[67] = 0x12; + Fs->CurrentSector.Sector[68] = 0x34; + Fs->CurrentSector.Sector[69] = 0x56; + Fs->CurrentSector.Sector[70] = 0x78; + + // Volume name + for (Index = 0; Index < 11; Index++) { + if (Index < (int)AsciiStrLen (Name)) + Fs->CurrentSector.Sector[Index + 71] = Name[Index]; + else + Fs->CurrentSector.Sector[Index + 71] = ' '; + } + + // File sys type + Fs->CurrentSector.Sector[82] = 'F'; + Fs->CurrentSector.Sector[83] = 'A'; + Fs->CurrentSector.Sector[84] = 'T'; + Fs->CurrentSector.Sector[85] = '3'; + Fs->CurrentSector.Sector[86] = '2'; + Fs->CurrentSector.Sector[87] = ' '; + Fs->CurrentSector.Sector[88] = ' '; + Fs->CurrentSector.Sector[89] = ' '; + + // Signature + Fs->CurrentSector.Sector[510] = 0x55; + Fs->CurrentSector.Sector[511] = 0xAA; + } + + Status = Fs->DiskIo->WriteDisk ( + Fs->DiskIo, Fs->BlockIo->Media->MediaId, + MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) + + MultU64x32 (Fs->FatBeginLba, FAT_SECTOR_SIZE), + FAT_SECTOR_SIZE, + Fs->CurrentSector.Sector); + + return Status; +} +//----------------------------------------------------------------------------- +// fatfs_create_fsinfo_sector: Create the FSInfo Sector (FAT32) +//----------------------------------------------------------------------------- +STATIC +EFI_STATUS +CreateFsinfoSector ( + IN FATFS *Fs, + IN EFI_LBA SectorLba + ) +{ + EFI_STATUS Status; + + // Zero Sector initially + ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE); + + // FSI_LeadSig + Fs->CurrentSector.Sector[0] = 0x52; + Fs->CurrentSector.Sector[1] = 0x52; + Fs->CurrentSector.Sector[2] = 0x61; + Fs->CurrentSector.Sector[3] = 0x41; + + // FSI_StrucSig + Fs->CurrentSector.Sector[484] = 0x72; + Fs->CurrentSector.Sector[485] = 0x72; + Fs->CurrentSector.Sector[486] = 0x41; + Fs->CurrentSector.Sector[487] = 0x61; + + // FSI_Free_Count + Fs->CurrentSector.Sector[488] = 0xFF; + Fs->CurrentSector.Sector[489] = 0xFF; + Fs->CurrentSector.Sector[490] = 0xFF; + Fs->CurrentSector.Sector[491] = 0xFF; + + // FSI_Nxt_Free + Fs->CurrentSector.Sector[492] = 0xFF; + Fs->CurrentSector.Sector[493] = 0xFF; + Fs->CurrentSector.Sector[494] = 0xFF; + Fs->CurrentSector.Sector[495] = 0xFF; + + // Signature + Fs->CurrentSector.Sector[510] = 0x55; + Fs->CurrentSector.Sector[511] = 0xAA; + + Status = Fs->DiskIo->WriteDisk ( + Fs->DiskIo, Fs->BlockIo->Media->MediaId, + MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) + + MultU64x32 (SectorLba, FAT_SECTOR_SIZE), + FAT_SECTOR_SIZE, + Fs->CurrentSector.Sector); + + return Status; +} +//----------------------------------------------------------------------------- +// fatfs_erase_fat: Erase FAT table using fs details in fs struct +//----------------------------------------------------------------------------- +STATIC +EFI_STATUS +EraseFat ( + IN FATFS *Fs, + IN BOOLEAN IsFat32) +{ + UINTN Index; + EFI_STATUS Status; + + // Zero Sector initially + ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE); + + // Initialise default allocate / reserved clusters + if (!IsFat32) { + SET_16BIT_WORD (Fs->CurrentSector.Sector, 0, 0xFFF8); + SET_16BIT_WORD (Fs->CurrentSector.Sector, 2, 0xFFFF); + } else { + SET_32BIT_WORD (Fs->CurrentSector.Sector, 0, 0x0FFFFFF8); + SET_32BIT_WORD (Fs->CurrentSector.Sector, 4, 0xFFFFFFFF); + SET_32BIT_WORD (Fs->CurrentSector.Sector, 8, 0x0FFFFFFF); + } + + Status = Fs->DiskIo->WriteDisk ( + Fs->DiskIo, Fs->BlockIo->Media->MediaId, + MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) + + MultU64x32 (Fs->FatBeginLba, FAT_SECTOR_SIZE), + FAT_SECTOR_SIZE, + Fs->CurrentSector.Sector); + if (EFI_ERROR (Status)) { + return Status; + } + + // Zero remaining FAT sectors + ZeroMem (Fs->CurrentSector.Sector, FAT_SECTOR_SIZE); + for (Index = 1; Index < Fs->FatSectors * Fs->NumOfFats; Index++) { + Status = Fs->DiskIo->WriteDisk ( + Fs->DiskIo, + Fs->BlockIo->Media->MediaId, + MultU64x32 (Fs->StartingLBA, Fs->BlockIo->Media->BlockSize) + + MultU64x32 ((Fs->FatBeginLba + Index), FAT_SECTOR_SIZE), + FAT_SECTOR_SIZE, + Fs->CurrentSector.Sector); + if (EFI_ERROR (Status)) { + return Status; + } + } + return Status; +} +//----------------------------------------------------------------------------- +// fatfs_format_fat16: Format a FAT16 partition +//----------------------------------------------------------------------------- +STATIC +EFI_STATUS +FormatFat16 ( + IN FATFS *Fs, + IN UINT64 VolumeSectors, + IN CONST CHAR8 *Name + ) +{ + EFI_STATUS Status; + + Fs->CurrentSector.Address = FAT32_INVALID_CLUSTER; + Fs->CurrentSector.Dirty = 0; + + Fs->NextFreeCluster = 0; // Invalid + + // Volume is FAT16 + Fs->FatType = FAT_TYPE_16; + + // Not valid for FAT16 + Fs->FsInfoSector = 0; + Fs->RootdirFirstCluster = 0; + + Fs->LbaBegin = 0; + Status = CreateBootSector (Fs, Fs->LbaBegin, VolumeSectors, Name, 0); + if (EFI_ERROR (Status)) { + return Status; + } + + // For FAT16 (which this may be), RootdirFirstCluster is actuall RootdirFirstSector + Fs->RootdirFirstSector = Fs->ReservedSectors + (Fs->NumOfFats * Fs->FatSectors); + Fs->RootdirSectors = ((Fs->RootEntryCount * 32) + + (FAT_SECTOR_SIZE - 1)) / FAT_SECTOR_SIZE; + + // First FAT LBA Address + Fs->FatBeginLba = Fs->LbaBegin + Fs->ReservedSectors; + + // The Address of the first data cluster on this volume + Fs->ClusterBeginLba = Fs->FatBeginLba + + (Fs->NumOfFats * Fs->FatSectors); + + // Initialise FAT sectors + Status = EraseFat (Fs, 0); + if (EFI_ERROR (Status)) { + return Status; + } + + // Erase Root directory + Status = EraseSectors ( + Fs, + Fs->LbaBegin + Fs->RootdirFirstSector, + Fs->RootdirSectors); + + return Status; +} +//----------------------------------------------------------------------------- +// fatfs_format_fat32: Format a FAT32 partition +//----------------------------------------------------------------------------- +STATIC +EFI_STATUS +FormatFat32 ( + IN FATFS *Fs, + IN UINTN VolumeSectors, + IN CONST CHAR8 *Name + ) +{ + EFI_STATUS Status; + + Fs->CurrentSector.Address = FAT32_INVALID_CLUSTER; + Fs->CurrentSector.Dirty = 0; + + Fs->NextFreeCluster = 0; // Invalid + + // Volume is FAT32 + Fs->FatType = FAT_TYPE_32; + + // Basic defaults for normal FAT32 partitions + Fs->FsInfoSector = 1; + Fs->RootdirFirstCluster = 2; + + // Sector 0: Boot Sector + // NOTE: We don't need an MBR, it is a waste of a good Sector! + Fs->LbaBegin = 0; + Status = CreateBootSector (Fs, Fs->LbaBegin, VolumeSectors, Name, 1); + if (EFI_ERROR (Status)) { + return Status; + } + + // First FAT LBA address + Fs->FatBeginLba = Fs->LbaBegin + Fs->ReservedSectors; + + // The address of the first data cluster on this volume + Fs->ClusterBeginLba = Fs->FatBeginLba + (Fs->NumOfFats * Fs->FatSectors); + + // Initialise FSInfo sector + Status = CreateFsinfoSector (Fs, Fs->FsInfoSector); + if (EFI_ERROR (Status)) { + return Status; + } + + // Initialise FAT sectors + Status = EraseFat (Fs, 1); + if (EFI_ERROR (Status)) { + return Status; + } + + // Erase Root directory + Status = EraseSectors ( + Fs, + LbaOfCluster (Fs, Fs->RootdirFirstCluster), + Fs->SectorsPerCluster); + + return Status; +} +//----------------------------------------------------------------------------- +// fatfs_format: Format a partition with either FAT16 or FAT32 based on size +//----------------------------------------------------------------------------- +EFI_STATUS +FatFormat ( + IN EFI_LBA StartingLBA, + IN EFI_LBA EndingLBA, + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN CHAR8 *VolumeName, + IN BOOLEAN ForceFat32 + ) +{ + FATFS Fs; + UINT64 VolumeSectors; + + VolumeSectors = DivU64x32 ( + MultU64x32 ( + EndingLBA - StartingLBA + 1, BlockIo->Media->BlockSize), + FAT_SECTOR_SIZE); + + if (VolumeName == NULL) { + VolumeName = DEFAULT_FAT_LABEL_NAME; + } + + ZeroMem (&Fs, sizeof(Fs)); + + Fs.StartingLBA = StartingLBA; + Fs.EndingLBA = EndingLBA; + Fs.BlockIo = BlockIo; + Fs.DiskIo = DiskIo; + // 2GB - 32K limit for safe behaviour for FAT16 + if ((VolumeSectors <= 4194304) && (!ForceFat32)) { + return FormatFat16 (&Fs, VolumeSectors, VolumeName); + } else { + return FormatFat32 (&Fs, VolumeSectors, VolumeName); + } +} diff --git a/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h new file mode 100644 index 000000000000..d1a325a57abe --- /dev/null +++ b/ShellPkg/Library/UefiShellGptCommandLib/FatFormat.h @@ -0,0 +1,111 @@ +/** @file + + Copyright (c) 2003 - 2012, Ultra-Embedded.com. All rights reserved
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +/* Portions Copyright (c) 2016, Broadcom. All rights reserved */ + +#ifndef __FAT_FORMAT_H__ +#define __FAT_FORMAT_H__ + +#include "GptWorker.h" + +#define FAT_SECTOR_SIZE 512 +#define FAT_BUFFER_SECTORS 1 +#define FAT32_LAST_CLUSTER 0xFFFFFFFF +#define FAT32_INVALID_CLUSTER 0xFFFFFFFF +#define FAT_DIR_ENTRY_SIZE 32 +#define FAT_BUFFERS 1 +#define DEFAULT_FAT_LABEL_NAME "EFIVOL" + +#define GET_32BIT_WORD(Buffer, Location) ( ((UINT32)Buffer[Location + 3] << 24) + \ + ((UINT32)Buffer[Location + 2] <<16 ) + \ + ((UINT32)Buffer[Location + 1] << 8) + \ + (UINT32)Buffer[Location+0] ) + +#define GET_16BIT_WORD(Buffer, Location) ( ((UINT16)Buffer[Location + 1] << 8) + \ + (UINT16)Buffer[Location+0]) + +#define SET_32BIT_WORD(Buffer, Location, Value) { Buffer[Location + 0] = (UINT8)((Value) & 0xFF); \ + Buffer[Location + 1] = (UINT8)((Value >> 8) & 0xFF); \ + Buffer[Location + 2] = (UINT8)((Value >> 16) & 0xFF); \ + Buffer[Location + 3] = (UINT8)((Value >> 24) & 0xFF); } + +#define SET_16BIT_WORD(Buffer, Location, Value) { Buffer[Location + 0] = (UINT8)((Value) & 0xFF); \ + Buffer[Location + 1] = (UINT8)((Value >> 8) & 0xFF); } + +typedef enum eFatType +{ + FAT_TYPE_16, + FAT_TYPE_32 +} FAT_FS_TYPE; + + +// Forward declaration +typedef struct _FAT_BUFFER FAT_BUFFER; + +struct _FAT_BUFFER { + UINT8 Sector[FAT_SECTOR_SIZE * FAT_BUFFER_SECTORS]; + UINTN Address; + BOOLEAN Dirty; + UINT8 *Ptr; + + // Next in chain of sector buffers + struct FAT_BUFFER *NextBuf; +}; + +typedef struct +{ + // Filesystem globals + UINT8 SectorsPerCluster; + EFI_LBA ClusterBeginLba; + UINTN RootdirFirstCluster; + UINTN RootdirFirstSector; + UINTN RootdirSectors; + EFI_LBA FatBeginLba; + UINT16 FsInfoSector; + EFI_LBA LbaBegin; + UINTN FatSectors; + UINTN NextFreeCluster; + UINT16 RootEntryCount; + UINT16 ReservedSectors; + UINT8 NumOfFats; + FAT_FS_TYPE FatType; + + // Working buffer + FAT_BUFFER CurrentSector; + // FAT Buffer + FAT_BUFFER *FatBufferHead; + FAT_BUFFER FatBuffers[FAT_BUFFERS]; + EFI_LBA StartingLBA; + EFI_LBA EndingLBA; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + EFI_DISK_IO_PROTOCOL *DiskIo; + +} FATFS; + + + +//----------------------------------------------------------------------------- +// Prototypes +//----------------------------------------------------------------------------- +EFI_STATUS +FatFormat ( + IN EFI_LBA StartingLBA, + IN EFI_LBA EndingLBA, + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN CHAR8 *VolumeName, + IN BOOLEAN ForceFat32 + ); + +#endif diff --git a/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c new file mode 100644 index 000000000000..0546c94488b0 --- /dev/null +++ b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.c @@ -0,0 +1,1902 @@ +/** @file +Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.
+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 "GptWorker.h" + +#define GPT_DEBUG_LEVEL 0 + +STATIC EFI_PARTITION_TABLE_HEADER *PrimaryHeader = NULL; +STATIC EFI_PARTITION_TABLE_HEADER *BackupHeader = NULL; +STATIC EFI_PARTITION_ENTRY *PartEntry = NULL; +STATIC EFI_PARTITION_ENTRY_STATUS *PEntryStatus = NULL; + +STATIC EFI_BLOCK_IO_PROTOCOL *BlockIo; +STATIC EFI_DISK_IO_PROTOCOL *DiskIo; + +STATIC BOOLEAN MbrValid; +STATIC BOOLEAN GptValid; + +STATIC EFI_KNOWN_PARTITION_TYPE PartitionTypes[] = +{ + // Known Partition type GUIDs + // Expand this table as needed. + // Starting with EFI System partition + { { 0xC12A7328L, 0xF81F, 0x11D2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B } }, L"EFI System" }, + // Known Windows partition types + { { 0xE3C9E316L, 0x0B5C, 0x4DB8, { 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE } }, L"MS Windows Reserved (MSR)" }, + { { 0xEBD0A0A2L, 0xB9E5, 0x4433, { 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 } }, L"MS Windows Basic Data" }, + { { 0x5808C8AAL, 0x7E8F, 0x42E0, { 0x85, 0xD2, 0xE1, 0xE9, 0x04, 0x34, 0xCF, 0xB3 } }, L"MS Windows LDM Metadata" }, + { { 0xAF9B60A0L, 0x1431, 0x4F62, { 0xBC, 0x68, 0x33, 0x11, 0x71, 0x4A, 0x69, 0xAD } }, L"MS Windows LDM Data" }, + { { 0xDE94BBA4L, 0x06D1, 0x4D40, { 0xA1, 0x6A, 0xBF, 0xD5, 0x01, 0x79, 0xD6, 0xAC } }, L"MS Windows Recovery Environment" }, + { { 0xE75CAF8FL, 0xF680, 0x4CEE, { 0xAF, 0xA3, 0xB0, 0x01, 0xE5, 0x6E, 0xFC, 0x2D } }, L"MS Windows Storage Spaces" }, + // Known Linux partition types + { { 0x0FC63DAFL, 0x8483, 0x4772, { 0x8E, 0x79, 0x3D, 0x69, 0xD8, 0x47, 0x7D, 0xE4 } }, L"Linux Filesystem Data" }, + { { 0xA19D880FL, 0x05FC, 0x4D3B, { 0xA0, 0x06, 0x74, 0x3F, 0x0F, 0x84, 0x91, 0x1E } }, L"Linux RAID" }, + { { 0x44479540L, 0xF297, 0x41B2, { 0x9A, 0xF7, 0xD1, 0x31, 0xD5, 0xF0, 0x45, 0x8A } }, L"Linux Root (x86)" }, + { { 0x4F68BCE3L, 0xE8CD, 0x4DB1, { 0x96, 0xE7, 0xFB, 0xCA, 0xF9, 0x84, 0xB7, 0x09 } }, L"Linux Root (x86-64)" }, + { { 0x69DAD710L, 0x2CE4, 0x4E3C, { 0xB1, 0x6C, 0x21, 0xA1, 0xD4, 0x9A, 0xBe, 0xD3 } }, L"Linux Root (ARM 32-bit)" }, + { { 0xB921B045L, 0x1DF0, 0x41C3, { 0xAF, 0x44, 0x4C, 0x6F, 0x28, 0x0D, 0x3F, 0xAE } }, L"Linux Root (ARM 64-bit/AARCH64)" }, + { { 0x0657FD6DL, 0xA4AB, 0x43C4, { 0x84, 0xE5, 0x09, 0x33, 0xC8, 0x4B, 0x4F, 0x4F } }, L"Linux Swap" }, + { { 0xE6D6D379L, 0xF507, 0x44C2, { 0xA2, 0x3C, 0x23, 0x8F, 0x2A, 0x3D, 0xF9, 0x28 } }, L"Linux Logical Volume Manager (LVM)" }, + { { 0x933AC7E1L, 0x2EB4, 0x4F13, { 0xB8, 0x44, 0x0E, 0x14, 0xE2, 0xAE, 0xF9, 0x15 } }, L"Linux /home" }, + { { 0x3B8F8425L, 0x20E0, 0x4F3B, { 0x90, 0x7F, 0x1A, 0x25, 0xA7, 0x6F, 0x98, 0xE8 } }, L"Linux /srv (server data)" }, + { { 0x7FFEC5C9L, 0x2D00, 0x49B7, { 0x89, 0x41, 0x3E, 0xA1, 0x0A, 0x55, 0x86, 0xB7 } }, L"Linux Plain dm-crypt" }, + { { 0xCA7D7CCBL, 0x63ED, 0x4C53, { 0x86, 0x1C, 0x17, 0x42, 0x53, 0x60, 0x59, 0xCC } }, L"Linux LUKS" }, + { { 0x8DA63339L, 0x0007, 0x60C0, { 0xC4, 0x36, 0x08, 0x3A, 0xC8, 0x23, 0x09, 0x08 } }, L"Linux Reserved" }, +}; + +MASTER_BOOT_RECORD ProtectiveMbrTemplate = { + { 0 }, // BoostStrapCode [440] + { 0 }, // UniqueMbrSignature[4] (unused) + { 0 }, // Unknown[2] + + // PARTITIONS + { + // MBR_PARTITION_RECORD + { + 0, // BootIndicator + 0, // StartHead + 0x1, // StartSector + 0x1, // StartTrack + PMBR_GPT_PARTITION, // OSIndicator + 0xff, // EndHead + 0xff, // EndSector + 0xff, // EndTrack + { 0x1, 0x0, 0x0, 0x0 }, // StartingLba[4] + { 0xff, 0xff, 0xff, 0xff }, // SizeInLba[4] + }, + { 0 }, { 0 }, { 0 }, // Unused partitions + }, + + MBR_SIGNATURE // Signature +}; + +STATIC UINT32 CurRand = 1; + +/** + Get random seed based on the RTC + +**/ + +STATIC +VOID +Srand (VOID) +{ + EFI_TIME Time; + UINT32 Seed; + UINT64 MonotonicCount; + + gRT->GetTime (&Time, NULL); + Seed = (~Time.Hour << 24 | Time.Day << 16 | Time.Minute << 8 | Time.Second); + Seed ^= Time.Nanosecond; + Seed ^= Time.Year << 7; + + gBS->GetNextMonotonicCount (&MonotonicCount); + Seed += (UINT32)MonotonicCount; + + /* Store this seed */ + CurRand = (UINT32)Seed; +} + +/** + Get a pseudo-random number + + @retval A pseudo-random number in the range 0 - 0x7fff +**/ + +STATIC UINTN Rand (VOID) +{ + /* return a pseudo-random in range 0 - 0x7fff */ + return ((CurRand = CurRand * 214013L + 2531011L) >> 16) & 0x7fff; +} + +/** + Generate a GUID + + @param[in] Guid A pointer to a GUID receiving a generated value +**/ + +STATIC VOID +GenerateGuid (OUT GUID *Guid) +{ + UINTN Index; + UINT16 Buffer[sizeof(GUID)]; + + /* Generates 128 random bits for new UUID */ + for (Index = 0; Index < sizeof(GUID); Index++) { + UINTN V; + + V = Rand () >> 7; + Buffer[Index] = (UINT16)V; + } + /* set variant 10x and version 4 as required by RFC 4122 */ + Buffer[8] = 0x80 | (Buffer[8] & 0x3f); + Buffer[6] = 0x40 | (Buffer[6] & 0xf); + CopyGuid (Guid, (CONST GUID *)Buffer); +} + +/** + Clean up globals +**/ +VOID +GptCleanupGlobals (VOID) +{ + SHELL_FREE_NON_NULL (PrimaryHeader); + SHELL_FREE_NON_NULL (BackupHeader); + SHELL_FREE_NON_NULL (PartEntry); + SHELL_FREE_NON_NULL (PEntryStatus); + GptValid = FALSE; + MbrValid = FALSE; +} + +/** + Caution: This function may receive untrusted input. + The GPT partition table header is external input, so this routine + will do basic validation for GPT partition table header before return. + + @param[in] Lba The starting Lba of the Partition Table + @param[out] PartHeader Stores the partition table that is read + + @retval EFI_SUCCESS The partition table is valid + @retval ERROR The partition table is not valid + +**/ +STATIC +EFI_STATUS +PartitionValidGptTable ( + IN EFI_LBA Lba, + OUT EFI_PARTITION_TABLE_HEADER *PartHeader + ); + +/** + Check if the CRC field in the Partition table header is valid + for Partition entry array. + + @param[in] PartHeader Partition table header structure + + @retval TRUE the CRC is valid + @retval FALSE the CRC is invalid + +**/ +STATIC +BOOLEAN +PartitionCheckGptEntryArrayCRC ( + IN EFI_PARTITION_TABLE_HEADER *PartHeader + ); + + +/** + Restore Partition Table to its alternate place + (Primary -> Backup or Backup -> Primary). + + @param[in] PartHeader Partition table header structure. + + @retval TRUE Restoring succeeds + @retval FALSE Restoring failed + +**/ +STATIC +BOOLEAN +PartitionRestoreGptTable ( + IN EFI_PARTITION_TABLE_HEADER *PartHeader + ); + + +/** + This routine will check GPT partition entry and return entry status. + + Caution: This function may receive untrusted input. + The GPT partition entry is external input, so this routine + will do basic validation for GPT partition entry and report status. + + @param[in] PartHeader Partition table header structure + @param[in] PartEntry The partition entry array + @param[out] PEntryStatus the partition entry status array + recording the status of each partition + +**/ +STATIC +VOID +PartitionCheckGptEntry ( + IN EFI_PARTITION_TABLE_HEADER *PartHeader, + IN EFI_PARTITION_ENTRY *PartEntry, + OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus + ); + + +/** + Checks the CRC32 value in the table header. + + @param MaxSize Max Size limit + @param Size The size of the table + @param Hdr Table to check + + @return TRUE CRC Valid + @return FALSE CRC Invalid + +**/ +STATIC +BOOLEAN +PartitionCheckCrcAltSize ( + IN UINTN MaxSize, + IN UINTN Size, + IN OUT EFI_TABLE_HEADER *Hdr + ); + + +/** + Checks the CRC32 value in the table header. + + @param MaxSize Max Size limit + @param Hdr Table to check + + @return TRUE CRC Valid + @return FALSE CRC Invalid + +**/ +STATIC +BOOLEAN +PartitionCheckCrc ( + IN UINTN MaxSize, + IN OUT EFI_TABLE_HEADER *Hdr + ); + + +/** + Updates the CRC32 value in the table header. + + @param Size The size of the table + @param Hdr Table to update + +**/ +STATIC +VOID +PartitionSetCrcAltSize ( + IN UINTN Size, + IN OUT EFI_TABLE_HEADER *Hdr + ); + + +/** + Updates the CRC32 value in the table header. + + @param Hdr Table to update + +**/ +STATIC +VOID +PartitionSetCrc ( + IN OUT EFI_TABLE_HEADER *Hdr + ); + + +/** + Get GPT tables. + + Caution: This function may receive untrusted input. + The GPT partition table is external input, so this routine + will do basic validation for GPT partition table before install + child handle for each GPT partition. + + @param[in] DiskIoProt DiskIo interface. + @param[in] BlockIoProt BlockIo interface. + + @retval EFI_SUCCESS Valid GPT disk. + @retval EFI_MEDIA_CHANGED Media changed Detected. + @retval other Not a valid GPT disk. + +**/ +EFI_STATUS +PartitionGetGptTables ( + IN EFI_DISK_IO_PROTOCOL *DiskIoProt, + IN EFI_BLOCK_IO_PROTOCOL *BlockIoProt + ) +{ + EFI_STATUS Status; + UINT32 BlockSize; + EFI_LBA LastBlock; + UINTN Index; + EFI_STATUS GptValidStatus; + UINT32 MediaId; + MASTER_BOOT_RECORD *ProtectiveMbr; + + // Clear leftovers + GptCleanupGlobals (); + + MbrValid = FALSE; + GptValid = FALSE; + + ProtectiveMbr = NULL; + + BlockIo = BlockIoProt; + DiskIo = DiskIoProt; + + if (CurRand == 1) { + Srand (); + } + + BlockSize = BlockIo->Media->BlockSize; + LastBlock = BlockIo->Media->LastBlock; + MediaId = BlockIo->Media->MediaId; + + DEBUG ((EFI_D_VERBOSE, " BlockSize : %d \n", BlockSize)); + DEBUG ((EFI_D_VERBOSE, " LastBlock : %lx \n", LastBlock)); + + GptValidStatus = EFI_NOT_FOUND; + GptValid = FALSE; + MbrValid = FALSE; + + // + // Allocate a buffer for the Protective MBR + // + ProtectiveMbr = AllocatePool (BlockSize); + if (ProtectiveMbr == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Read the Protective MBR from LBA #0 + // + Status = DiskIo->ReadDisk ( + DiskIo, + MediaId, + 0, + BlockSize, + ProtectiveMbr + ); + if (EFI_ERROR (Status)) { + GptValidStatus = Status; + goto Done; + } + + // + // Verify that the Protective MBR is valid + // + for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) { + if (ProtectiveMbr->Partition[Index].BootIndicator == 0x00 && + ProtectiveMbr->Partition[Index].OSIndicator == PMBR_GPT_PARTITION && + UNPACK_UINT32 (ProtectiveMbr->Partition[Index].StartingLBA) == 1 + ) { + break; + } + } + if (Index == MAX_MBR_PARTITIONS) { + goto Done; + } + + MbrValid = TRUE; + + // + // Allocate the GPT structures + // + PrimaryHeader = AllocateZeroPool (sizeof(EFI_PARTITION_TABLE_HEADER)); + if (PrimaryHeader == NULL) { + goto Done; + } + + BackupHeader = AllocateZeroPool (sizeof(EFI_PARTITION_TABLE_HEADER)); + if (BackupHeader == NULL) { + goto Done; + } + + // + // Check primary and backup partition tables + // + Status = PartitionValidGptTable (PRIMARY_PART_HEADER_LBA, PrimaryHeader); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_INFO, " Not Valid primary partition table\n")); + + Status = PartitionValidGptTable (LastBlock, BackupHeader); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_INFO, " Not Valid backup partition table\n")); + goto Done; + } else { + DEBUG ((EFI_D_INFO, " Valid backup partition table\n")); + DEBUG ((EFI_D_INFO, " Restore primary partition table by the backup\n")); + if (!PartitionRestoreGptTable (BackupHeader)) { + DEBUG ((EFI_D_INFO, " Restore primary partition table error\n")); + } + + Status = PartitionValidGptTable (BackupHeader->AlternateLBA, PrimaryHeader); + if (!EFI_ERROR (Status)) { + DEBUG ((EFI_D_INFO, " Restore backup partition table success\n")); + } + } + } else if (EFI_ERROR (PartitionValidGptTable (PrimaryHeader->AlternateLBA, BackupHeader))) { + DEBUG ((EFI_D_INFO, " Valid primary and !Valid backup partition table\n")); + DEBUG ((EFI_D_INFO, " Restore backup partition table by the primary\n")); + if (!PartitionRestoreGptTable (PrimaryHeader)) { + DEBUG ((EFI_D_INFO, " Restore backup partition table error\n")); + } + + Status = PartitionValidGptTable (PrimaryHeader->AlternateLBA, BackupHeader); + if (!EFI_ERROR (Status)) { + DEBUG ((EFI_D_INFO, " Restore backup partition table success\n")); + } + } + + DEBUG ((EFI_D_VERBOSE, " Valid primary and Valid backup partition table\n")); + + // + // Read the EFI Partition Entries + // + PartEntry = AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry); + if (PartEntry == NULL) { + DEBUG ((EFI_D_ERROR, "Allocate pool error\n")); + goto Done; + } + + Status = DiskIo->ReadDisk ( + DiskIo, + MediaId, + MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockSize), + PrimaryHeader->NumberOfPartitionEntries * (PrimaryHeader->SizeOfPartitionEntry), + PartEntry + ); + if (EFI_ERROR (Status)) { + GptValidStatus = Status; + DEBUG ((EFI_D_ERROR, " Partition Entry ReadDisk error\n")); + goto Done; + } + + DEBUG ((EFI_D_VERBOSE, " Partition entries read block success\n")); + + DEBUG ((EFI_D_VERBOSE, " Number of partition entries: %d\n", PrimaryHeader->NumberOfPartitionEntries)); + + PEntryStatus = AllocateZeroPool (PrimaryHeader->NumberOfPartitionEntries * sizeof(EFI_PARTITION_ENTRY_STATUS)); + if (PEntryStatus == NULL) { + DEBUG ((EFI_D_ERROR, "Allocate pool error\n")); + goto Done; + } + + // + // Check the integrity of partition entries + // + PartitionCheckGptEntry (PrimaryHeader, PartEntry, PEntryStatus); + + // + // If we got this far the GPT layout of the disk is valid and we should return true + // + GptValidStatus = EFI_SUCCESS; + + Done: + SHELL_FREE_NON_NULL (ProtectiveMbr); + if (EFI_ERROR (GptValidStatus)) { + SHELL_FREE_NON_NULL (PrimaryHeader); + SHELL_FREE_NON_NULL (BackupHeader); + SHELL_FREE_NON_NULL (PartEntry); + SHELL_FREE_NON_NULL (PEntryStatus); + } else { + GptValid = TRUE; + } + + return GptValidStatus; +} + +/** + This routine will read GPT partition table header and return it. + + Caution: This function may receive untrusted input. + The GPT partition table header is external input, so this routine + will do basic validation for GPT partition table header before return. + + @param[in] Lba The starting Lba of the Partition Table + @param[out] PartHeader Stores the partition table that is read + + @retval TRUE The partition table is valid + @retval FALSE The partition table is not valid + +**/ +STATIC +EFI_STATUS +PartitionValidGptTable ( + IN EFI_LBA Lba, + OUT EFI_PARTITION_TABLE_HEADER *PartHeader + ) +{ + EFI_STATUS Status; + UINT32 BlockSize; + EFI_PARTITION_TABLE_HEADER *PartHdr; + UINT32 MediaId; + + BlockSize = BlockIo->Media->BlockSize; + MediaId = BlockIo->Media->MediaId; + PartHdr = AllocateZeroPool (BlockSize); + + if (PartHdr == NULL) { + DEBUG ((EFI_D_ERROR, "Allocate pool error\n")); + return EFI_OUT_OF_RESOURCES; + } + // + // Read the EFI Partition Table Header + // + Status = DiskIo->ReadDisk ( + DiskIo, + MediaId, + MultU64x32 (Lba, BlockSize), + BlockSize, + PartHdr + ); + if (EFI_ERROR (Status)) { + FreePool (PartHdr); + return Status; + } + + if ((PartHdr->Header.Signature != EFI_PTAB_HEADER_ID) || + !PartitionCheckCrc (BlockSize, &PartHdr->Header) || + PartHdr->MyLBA != Lba || + (PartHdr->SizeOfPartitionEntry < sizeof(EFI_PARTITION_ENTRY)) + ) { + DEBUG ((EFI_D_ERROR, "Invalid efi partition table header\n")); + FreePool (PartHdr); + return EFI_VOLUME_CORRUPTED; + } + + // + // Ensure the NumberOfPartitionEntries * SizeOfPartitionEntry doesn't overflow. + // + if (PartHdr->NumberOfPartitionEntries > DivU64x32 (MAX_UINTN, PartHdr->SizeOfPartitionEntry)) { + FreePool (PartHdr); + return EFI_VOLUME_CORRUPTED; + } + + CopyMem (PartHeader, PartHdr, sizeof(EFI_PARTITION_TABLE_HEADER)); + if (!PartitionCheckGptEntryArrayCRC (PartHeader)) { + FreePool (PartHdr); + return EFI_VOLUME_CORRUPTED; + } + + DEBUG ((EFI_D_VERBOSE, " Valid efi partition table header\n")); + FreePool (PartHdr); + + return EFI_SUCCESS; +} + +/** + Check if the CRC field in the Partition table header is valid + for Partition entry array. + + @param[in] PartHeader Partition table header structure + + @retval TRUE the CRC is valid + @retval FALSE the CRC is invalid + +**/ +STATIC +BOOLEAN +PartitionCheckGptEntryArrayCRC ( + IN EFI_PARTITION_TABLE_HEADER *PartHeader + ) +{ + EFI_STATUS Status; + UINT8 *Ptr; + UINT32 Crc; + UINTN Size; + + // + // Read the EFI Partition Entries + // + Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry); + if (Ptr == NULL) { + DEBUG ((EFI_D_ERROR, " Allocate pool error\n")); + return FALSE; + } + + Status = DiskIo->ReadDisk ( + DiskIo, + BlockIo->Media->MediaId, + MultU64x32 (PartHeader->PartitionEntryLBA, BlockIo->Media->BlockSize), + PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry, + Ptr + ); + if (EFI_ERROR (Status)) { + FreePool (Ptr); + return FALSE; + } + + Size = PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry; + + Status = gBS->CalculateCrc32 (Ptr, Size, &Crc); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "CheckPEntryArrayCRC: Crc calculation failed\n")); + FreePool (Ptr); + return FALSE; + } + + FreePool (Ptr); + + return (BOOLEAN)(PartHeader->PartitionEntryArrayCRC32 == Crc); +} + + +/** + Restore Partition Table to its alternate place + (Primary -> Backup or Backup -> Primary). + + @param[in] PartHeader Partition table header structure. + + @retval TRUE Restoring succeeds + @retval FALSE Restoring failed + +**/ +STATIC +BOOLEAN +PartitionRestoreGptTable ( + IN EFI_PARTITION_TABLE_HEADER *PartHeader + ) +{ + EFI_STATUS Status; + UINTN BlockSize; + EFI_PARTITION_TABLE_HEADER *PartHdr; + EFI_LBA PEntryLBA; + UINT8 *Ptr; + UINT32 MediaId; + + PartHdr = NULL; + Ptr = NULL; + + BlockSize = BlockIo->Media->BlockSize; + MediaId = BlockIo->Media->MediaId; + + PartHdr = AllocateZeroPool (BlockSize); + + if (PartHdr == NULL) { + DEBUG ((EFI_D_ERROR, "Allocate pool error\n")); + return FALSE; + } + + PEntryLBA = (PartHeader->MyLBA == PRIMARY_PART_HEADER_LBA) ?\ + (PartHeader->LastUsableLBA + 1) :\ + (PRIMARY_PART_HEADER_LBA + 1); + + CopyMem (PartHdr, PartHeader, sizeof(EFI_PARTITION_TABLE_HEADER)); + + PartHdr->MyLBA = PartHeader->AlternateLBA; + PartHdr->AlternateLBA = PartHeader->MyLBA; + PartHdr->PartitionEntryLBA = PEntryLBA; + PartitionSetCrc ((EFI_TABLE_HEADER *)PartHdr); + + Status = DiskIo->WriteDisk ( + DiskIo, + MediaId, + MultU64x32 (PartHdr->MyLBA, (UINT32)BlockSize), + BlockSize, + PartHdr + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry); + if (Ptr == NULL) { + DEBUG ((EFI_D_ERROR, " Allocate pool error\n")); + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + Status = DiskIo->ReadDisk ( + DiskIo, + MediaId, + MultU64x32 (PartHeader->PartitionEntryLBA, (UINT32)BlockSize), + PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry, + Ptr + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = DiskIo->WriteDisk ( + DiskIo, + MediaId, + MultU64x32 (PEntryLBA, (UINT32)BlockSize), + PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry, + Ptr + ); + + Done: + FreePool (PartHdr); + + if (Ptr != NULL) { + FreePool (Ptr); + } + + if (EFI_ERROR (Status)) { + return FALSE; + } + + return TRUE; +} + +/** + This routine will check GPT partition entry and return entry status. + + Caution: This function may receive untrusted input. + The GPT partition entry is external input, so this routine + will do basic validation for GPT partition entry and report status. + + @param[in] PartHeader Partition table header structure + @param[in] PartEntry The partition entry array + @param[out] PEntryStatus the partition entry status array + recording the status of each partition + +**/ +STATIC +VOID +PartitionCheckGptEntry ( + IN EFI_PARTITION_TABLE_HEADER *PartHeader, + IN EFI_PARTITION_ENTRY *PartEntry, + OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus + ) +{ + EFI_LBA StartingLBA; + EFI_LBA EndingLBA; + EFI_PARTITION_ENTRY *Entry; + UINTN Index1; + UINTN Index2; + + DEBUG ((EFI_D_VERBOSE, " start check partition entries\n")); + for (Index1 = 0; Index1 < PartHeader->NumberOfPartitionEntries; Index1++) { + Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index1 * PartHeader->SizeOfPartitionEntry); + if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) { + continue; + } + + StartingLBA = Entry->StartingLBA; + EndingLBA = Entry->EndingLBA; + if (StartingLBA > EndingLBA || + StartingLBA < PartHeader->FirstUsableLBA || + StartingLBA > PartHeader->LastUsableLBA || + EndingLBA < PartHeader->FirstUsableLBA || + EndingLBA > PartHeader->LastUsableLBA + ) { + PEntryStatus[Index1].OutOfRange = TRUE; + continue; + } + + if ((Entry->Attributes & BIT1) != 0) { + // + // If Bit 1 is set, this indicate that this is an OS specific GUID partition. + // + PEntryStatus[Index1].OsSpecific = TRUE; + } + + for (Index2 = Index1 + 1; Index2 < PartHeader->NumberOfPartitionEntries; Index2++) { + Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index2 * PartHeader->SizeOfPartitionEntry); + if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) { + continue; + } + + if (Entry->EndingLBA >= StartingLBA && Entry->StartingLBA <= EndingLBA) { + // + // This region overlaps with the Index1'th region + // + PEntryStatus[Index1].Overlap = TRUE; + PEntryStatus[Index2].Overlap = TRUE; + continue; + } + } + } + + DEBUG ((EFI_D_VERBOSE, " End check partition entries\n")); +} + + +/** + Updates the CRC32 value in the table header. + + @param Hdr Table to update + +**/ +STATIC +VOID +PartitionSetCrc ( + IN OUT EFI_TABLE_HEADER *Hdr + ) +{ + PartitionSetCrcAltSize (Hdr->HeaderSize, Hdr); +} + + +/** + Updates the CRC32 value in the table header. + + @param Size The size of the table + @param Hdr Table to update + +**/ +STATIC +VOID +PartitionSetCrcAltSize ( + IN UINTN Size, + IN OUT EFI_TABLE_HEADER *Hdr + ) +{ + UINT32 Crc; + + Hdr->CRC32 = 0; + gBS->CalculateCrc32 ((UINT8 *)Hdr, Size, &Crc); + Hdr->CRC32 = Crc; +} + + +/** + Checks the CRC32 value in the table header. + + @param MaxSize Max Size limit + @param Hdr Table to check + + @return TRUE CRC Valid + @return FALSE CRC Invalid + +**/ +STATIC +BOOLEAN +PartitionCheckCrc ( + IN UINTN MaxSize, + IN OUT EFI_TABLE_HEADER *Hdr + ) +{ + return PartitionCheckCrcAltSize (MaxSize, Hdr->HeaderSize, Hdr); +} + + +/** + Checks the CRC32 value in the table header. + + @param MaxSize Max Size limit + @param Size The size of the table + @param Hdr Table to check + + @return TRUE CRC Valid + @return FALSE CRC Invalid + +**/ +STATIC +BOOLEAN +PartitionCheckCrcAltSize ( + IN UINTN MaxSize, + IN UINTN Size, + IN OUT EFI_TABLE_HEADER *Hdr + ) +{ + UINT32 Crc; + UINT32 OrgCrc; + EFI_STATUS Status; + + Crc = 0; + + if (Size == 0) { + // + // If header size is 0 CRC will pass so return FALSE here + // + return FALSE; + } + + if ((MaxSize != 0) && (Size > MaxSize)) { + DEBUG ((EFI_D_ERROR, "CheckCrc32: Size > MaxSize\n")); + return FALSE; + } + // + // clear old crc from header + // + OrgCrc = Hdr->CRC32; + Hdr->CRC32 = 0; + + Status = gBS->CalculateCrc32 ((UINT8 *)Hdr, Size, &Crc); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc calculation failed\n")); + return FALSE; + } + // + // set results + // + Hdr->CRC32 = Crc; + + // + // return status + // + DEBUG_CODE_BEGIN (); + if (OrgCrc != Crc) { + DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc check failed\n")); + } + DEBUG_CODE_END (); + + return (BOOLEAN)(OrgCrc == Crc); +} + +/** + Converts a GUID into a unicode string. + + @param [in] Guid A GUID to be converted + @param [out] Buffer A pointer to a buffer receiving the string + @param [in] BufferSize Size of the buffer + + @return EFI_SUCCESS Successful conversion + @return EFI_INVALID_PARAMETER Conversion failed + +**/ + +STATIC +EFI_STATUS +GuidToString ( + IN EFI_GUID *Guid, + OUT CHAR16 *Buffer, + IN UINTN BufferSize + ) +{ + UINTN Size; + EFI_STATUS Status; + + Status = EFI_SUCCESS; + + Size = UnicodeSPrint ( + Buffer, + BufferSize, + L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + (UINTN)Guid->Data1, + (UINTN)Guid->Data2, + (UINTN)Guid->Data3, + (UINTN)Guid->Data4[0], + (UINTN)Guid->Data4[1], + (UINTN)Guid->Data4[2], + (UINTN)Guid->Data4[3], + (UINTN)Guid->Data4[4], + (UINTN)Guid->Data4[5], + (UINTN)Guid->Data4[6], + (UINTN)Guid->Data4[7] + ); + if (!Size) { + Status = EFI_INVALID_PARAMETER; + } + + return Status; +} + +/** + Get a string representation of a known + partition type GUID. If partition GUID is not + known, gets a string representation of the GUID + + @param GUID Guid to be searched for + @param PartTypeStr Buffer receiving the string + @param NoGuidStr Do not convert GUID to string + for an unknown partition type + + @return EFI_SUCCESS GUID type is known + @return EFI_NOT_FOUND Unknown GUID partition type + +**/ +EFI_STATUS +GetPartitionTypeStr ( + IN EFI_GUID Guid, + OUT CHAR16 *PartTypeStr, + IN BOOLEAN NoGuidStr) +{ + UINTN Index; + EFI_STATUS Status; + + Status = EFI_SUCCESS; + for (Index = 0; Index < ARRAY_SIZE (PartitionTypes); Index++) { + if (CompareGuid (&Guid, &PartitionTypes[Index].TypeGuid)) { + StrnCpy (PartTypeStr, PartitionTypes[Index].TypeName, MAX_PARTITION_NAME_LENGTH); + return Status; + } + } + if (!NoGuidStr) { + GuidToString (&Guid, PartTypeStr, (MAX_PARTITION_NAME_LENGTH + 1) * sizeof(CHAR16)); + } + return EFI_NOT_FOUND; +} + +/** + Lists partitions on a block device. + + @return Number of partitions used +**/ + +UINTN +PartitionListGptEntries (VOID) +{ + UINTN Index; + EFI_PARTITION_ENTRY *Entry; + EFI_LBA Length; + UINTN NumEntries; // Used entries + UINTN BlockSize; + BOOLEAN FirstTime; + UINT64 BlocksOccupied; + + NumEntries = 0; + BlockSize = BlockIo->Media->BlockSize; + FirstTime = TRUE; + + if (!GptValid) { + return 0; + } + + BlocksOccupied = 0; + + for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) { + + BOOLEAN Specific; + CHAR16 PartTypeStr[MAX_PARTITION_NAME_LENGTH + 1]; + + Specific = FALSE; + + Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index * PrimaryHeader->SizeOfPartitionEntry); + + Length = Entry->EndingLBA - Entry->StartingLBA + 1; + + if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) { + continue; + } + + if (FirstTime) { + Print (L" No \t%-36s\tStart (LBA)\tEnd (LBA)\tSize (MiB)\t Partition Type\r\n", L"Name"); + Print (L" ---- -------------------------------------- ----------- ----------- ---------- -------------------------------\r\n"); + FirstTime = FALSE; + } + NumEntries++; + if (PEntryStatus[Index].OutOfRange || + PEntryStatus[Index].Overlap || + PEntryStatus[Index].OsSpecific) { + Specific = TRUE; + } + + BlocksOccupied += Length; + + GetPartitionTypeStr (Entry->PartitionTypeGUID, (CHAR16 *)&PartTypeStr, FALSE); + + Print (L"%1s %-3d\t%-36s\t0x%09llx\t0x%09llx\t%06llu\t %s\r\n", + Specific ? L"S" : L"", + Index + 1, + Entry->PartitionName, + (UINT64)Entry->StartingLBA, + (UINT64)Entry->EndingLBA, + (MultU64x32 (Length, BlockSize)) >> 20, + PartTypeStr); + } + + // This code block is to provide additional info + { + UINT64 DiskSizeMiB, SizeOccupiedMiB; + + DiskSizeMiB = MultU64x32 (PrimaryHeader->LastUsableLBA - PrimaryHeader->FirstUsableLBA + 1, BlockIo->Media->BlockSize) >> 20; + SizeOccupiedMiB = MultU64x32 (BlocksOccupied, BlockIo->Media->BlockSize) >> 20; + Print (L"\r\n%d partition(s) used out of %d\r\n", NumEntries, PrimaryHeader->NumberOfPartitionEntries); + Print (L"Total device capacity (minus GPT service blocks): %llu MiB\r\nPartitioned space: %llu MiB\r\n", + DiskSizeMiB, + SizeOccupiedMiB); + Print (L"Unpartitioned space available: %llu MiB (%d%%)\n", + DiskSizeMiB - SizeOccupiedMiB, + (100 * (DiskSizeMiB - SizeOccupiedMiB)) / DiskSizeMiB); + } + + return NumEntries; +} + +/** + Locate a partition by criteria + + @param Name Partition name (or ordinal represented a string) + @param StartLba StartLba of the partition to search for + @param EndingLba EndingLba of the partition to search for + @param SearchType A combination (OR) of search options. + Options are: + SRC_BY_NAME = search by partition name + SRC_BY_LBA = search by Start/Ending lba + SRC_ANY = returns a first used partition + SRC_BY_NUM = search by ordinal + + + @return Non-NULL Pointer to th partition found + @return NULL No partition found + +**/ +EFI_PARTITION_ENTRY * +PartitionFindPartitionByCriteria ( + IN OPTIONAL CONST CHAR16 *Name, + IN OPTIONAL EFI_LBA StartLba, + IN OPTIONAL EFI_LBA EndingLba, + IN SEARCH_TYPE SearchType + ) +{ + UINTN Index; + EFI_PARTITION_ENTRY *Entry; + + if (!GptValid) { + return NULL; + } + + if (!Name && (SearchType & SRC_BY_NAME)) { + return NULL; + } + + for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) { + Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index * PrimaryHeader->SizeOfPartitionEntry); + + if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) { + continue; + } + + if (SearchType & SRC_ANY) { + return Entry; + } + + if (SearchType & SRC_BY_NAME) { + if (!StrCmp (Name, Entry->PartitionName)) { + return Entry; + } + } + if (SearchType & SRC_BY_NUM) { + UINTN Ordinal; + + Ordinal = ShellStrToUintn (Name); + if (Index == (Ordinal - 1)) { + return Entry; + } + } + if (SearchType & SRC_BY_LBA) { + if ( + ((StartLba >= Entry->StartingLBA) && + (StartLba <= Entry->EndingLBA) + ) || + ((EndingLba >= Entry->StartingLBA) && + (EndingLba <= Entry->EndingLBA) + ) + ) { + return Entry; + } + } + } + return NULL; +} + +/** + Prints information on a given partition. + + @param Entry Pointer to the Partition of interest +**/ + +VOID +PartitionPrintGptPartInfo ( + IN EFI_PARTITION_ENTRY *Entry + ) +{ + CONST CHAR16 PartStr[MAX_PARTITION_NAME_LENGTH + 1] = { L'\0' }; + CONST CHAR16 *StrUnknown = L"Unknown"; + EFI_STATUS Status; + EFI_LBA Length; + + ASSERT (Entry); + + Status = GetPartitionTypeStr (Entry->PartitionTypeGUID, (CHAR16 *)&PartStr, TRUE); + if (EFI_ERROR (Status)) { + StrCpy ((CHAR16 *)&PartStr, StrUnknown); + } + + Length = Entry->EndingLBA - Entry->StartingLBA + 1; + + Print (L"Partition name: %s\r\n", Entry->PartitionName); + Print (L"Starting LBA : 0x%09llx\r\nEnding LBA : 0x%09llx\r\n", + (UINT64)Entry->StartingLBA, (UINT64)Entry->EndingLBA); + Print (L"Partition Size: %llu MiB (0x%llx blocks)\n", + (MultU64x32 (Length, BlockIo->Media->BlockSize)) >> 20, Length); + Print (L"Attributes : 0x%09llx\r\n", Entry->Attributes); + Print (L"Type/GUID : %s/%g\r\n", PartStr, &Entry->PartitionTypeGUID); + Print (L"Unique GUID : %g\n", &Entry->UniquePartitionGUID); +} + + +/** + Writes protective MBR to a block device. + + @return EFI_SUCCESS MBR written successfully + @return other Failed to write an MBR + +**/ + +STATIC +EFI_STATUS +WriteProtectiveMbr ( + VOID + ) +{ + UINT32 BlockSize; + UINT64 DiskSize; + EFI_STATUS Status; + MBR_PARTITION_RECORD *Partition; + MASTER_BOOT_RECORD *ProtectiveMbr; + + BlockSize = BlockIo->Media->BlockSize; + + ProtectiveMbr = NULL; + ProtectiveMbr = AllocateZeroPool (BlockSize); + if (ProtectiveMbr == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + DiskSize = BlockIo->Media->LastBlock + 1; + if (DiskSize > 0xffffffff) { + DiskSize = 0xffffffff; + } + + CopyMem (ProtectiveMbr, &ProtectiveMbrTemplate, sizeof(MASTER_BOOT_RECORD)); + + Partition = &ProtectiveMbr->Partition[0]; + + Partition->BootIndicator = 0; + Partition->StartSector = 1; + + // + // We don't actually know this data, so we'll make up + // something that seems likely. + // + + // + // Old software is expecting the Partition to start on + // a Track boundary, so we'll set track to 1 to avoid "overlay" + // with the MBR + // + + Partition->StartTrack = 1; + + Status = DiskIo->WriteDisk ( + DiskIo, + BlockIo->Media->MediaId, + 0, + BlockSize, + ProtectiveMbr + ); + + MbrValid = !EFI_ERROR (Status); + + SHELL_FREE_NON_NULL (ProtectiveMbr); + + return Status; +} + +/** + Write GPT tables to the block device. + + @return EFI_SUCCESS GPT tables were successfully written/updated + @return other Failed to write/update GPT tables + +**/ + +STATIC +EFI_STATUS +WriteGPT ( + VOID + ) +/* + CALLER is expected to fill in: + FirstUseableLBA + LastUseableLBA + EntryCount + DiskGUID + + We fill in the rest, and blast it out. + + Returns a status. + +*/ +{ + UINT32 BlockSize; + UINT32 TableSize; + EFI_STATUS Status = EFI_SUCCESS; + + BlockSize = BlockIo->Media->BlockSize; + TableSize = PrimaryHeader->NumberOfPartitionEntries * sizeof(EFI_PARTITION_ENTRY); + + if (!MbrValid) { + WriteProtectiveMbr (); + } + // + // Write out the primary header... + // + PrimaryHeader->Header.Signature = EFI_PTAB_HEADER_ID; + PrimaryHeader->Header.Revision = GPT_REVISION_1_0; + PrimaryHeader->Header.HeaderSize = sizeof(EFI_PARTITION_TABLE_HEADER); + + PrimaryHeader->AlternateLBA = BackupHeader->MyLBA; + + PrimaryHeader->SizeOfPartitionEntry = sizeof(EFI_PARTITION_ENTRY); + + Status = gBS->CalculateCrc32 ((UINT8 *)PartEntry, TableSize, &PrimaryHeader->PartitionEntryArrayCRC32); + if (EFI_ERROR (Status)) { + return Status; + } + + // Write primary header + PartitionSetCrc (&PrimaryHeader->Header); + + Status = DiskIo->WriteDisk ( + DiskIo, + BlockIo->Media->MediaId, + MultU64x32 (PrimaryHeader->MyLBA, (UINT32)BlockSize), + BlockSize, + PrimaryHeader + ); + + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Write out the primary table ... + // + Status = DiskIo->WriteDisk ( + DiskIo, + BlockIo->Media->MediaId, + MultU64x32 (PrimaryHeader->PartitionEntryLBA, (UINT32)BlockSize), + TableSize, + PartEntry + ); + + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Write out the secondary header and table by calling restore + // + + if (!PartitionRestoreGptTable (PrimaryHeader)) { + return EFI_VOLUME_CORRUPTED; + } + BlockIo->FlushBlocks (BlockIo); + GptValid = !EFI_ERROR (Status); + + return Status; +} + +/** + (Re)initialize GPT tables on the block device + + @return EFI_SUCCESS Successfully (re)initialized GPT Tables + @return other Failed to (re)initialize GPT tables + +**/ +STATIC +EFI_STATUS +TableCreateEmptyGpt (VOID) +{ + UINTN EntryCount; + UINTN BlockFit; + UINTN BlockSize; + UINTN EntryBlocks; + UINT64 DiskSize; + UINTN TableSize; + EFI_LBA Header1_LBA; + EFI_LBA Table1_LBA; + EFI_LBA Header2_LBA; + EFI_LBA Table2_LBA; + EFI_LBA FirstUsableLBA; + EFI_LBA LastUsableLBA; + EFI_STATUS Status; + + EntryCount = ENTRY_DEFAULT; + BlockSize = BlockIo->Media->BlockSize; + BlockFit = BlockSize / sizeof(EFI_PARTITION_ENTRY); + + if (BlockFit > ENTRY_DEFAULT) { + EntryCount = BlockFit; + } + EntryBlocks = EntryCount / BlockFit; + + if ((EntryBlocks * BlockFit) != EntryCount) { + Status = EFI_VOLUME_CORRUPTED; + PrintErr (L"Invalid Entry blocks and Entry count combination\n", Status); + return Status; + } + + DiskSize = BlockIo->Media->LastBlock + 1; + + SHELL_FREE_NON_NULL (PrimaryHeader); + SHELL_FREE_NON_NULL (BackupHeader); + SHELL_FREE_NON_NULL (PartEntry); + + PrimaryHeader = AllocateZeroPool (BlockSize); + if (PrimaryHeader == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + BackupHeader = AllocateZeroPool (BlockSize); + if (BackupHeader == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Header1_LBA = 1; + Table1_LBA = 2; + FirstUsableLBA = Table1_LBA + EntryBlocks; + + Header2_LBA = DiskSize - 1; + Table2_LBA = Header2_LBA - EntryBlocks; + LastUsableLBA = Table2_LBA - 1; + + TableSize = EntryBlocks * BlockSize; + + if (TableSize != (EntryCount * sizeof(EFI_PARTITION_ENTRY))) { + Status = EFI_VOLUME_CORRUPTED; + PrintErr (L"Invalid Table size and Entry count combination\n", Status); + return Status; + } + + if (GPT_DEBUG_LEVEL) { + Print (L"DiskSize = %lx\n", DiskSize); + Print (L"BlockSize = %x\n", BlockSize); + Print (L"Header1_LBA = %lx\n", Header1_LBA); + Print (L"Table1_LBA = %lx\n", Table1_LBA); + Print (L"FirstUsableLBA = %lx\n", FirstUsableLBA); + Print (L"Header2_LBA = %lx\n", Header2_LBA); + Print (L"Table2_LBA = %lx\n", Table2_LBA); + Print (L"LastUsableLBA = %lx\n", LastUsableLBA); + Print (L"EntryCount = %x\n", EntryCount); + Print (L"EntryBlocks = %x\n", EntryBlocks); + } + + // + // Since we're making empty tables, we just write zeros... + // + + PartEntry = AllocateZeroPool (TableSize); + if (PartEntry == NULL) { + SHELL_FREE_NON_NULL (PrimaryHeader); + SHELL_FREE_NON_NULL (BackupHeader); + return EFI_OUT_OF_RESOURCES; + } + + PEntryStatus = AllocateZeroPool (TableSize); + + PrimaryHeader->FirstUsableLBA = FirstUsableLBA; + PrimaryHeader->LastUsableLBA = LastUsableLBA; + PrimaryHeader->NumberOfPartitionEntries = (UINT32)EntryCount; + GenerateGuid (&PrimaryHeader->DiskGUID); + + PrimaryHeader->MyLBA = Header1_LBA; + BackupHeader->MyLBA = Header2_LBA; + PrimaryHeader->PartitionEntryLBA = Table1_LBA; + BackupHeader->PartitionEntryLBA = Table2_LBA; + + Status = WriteGPT (); + + return Status; +} + +/** + Clear GPT partitions. + + @return EFI_SUCCESS Cleared successfully + @return FALSE Failed to clear + +**/ + +EFI_STATUS +PartitionGptClearAll (VOID) +{ + GptCleanupGlobals (); + GptValid = FALSE; + MbrValid = FALSE; + return TableCreateEmptyGpt (); +} + +/** + Create a GPT partition. + + @param PartName Partition Name + @param StartLba Starting LBA of the partition. + if zero, will be calculated + @param SizeInMegaBytes Size of the partition in MB + @param Attributes Partition attributes + @param PartTypeGuid a Type GUID to be assigned to the partition (not a partition unique GUID) + + + @return EFI_SUCCESS Partition successfully created + @return EFI_INVALID_PARAMETER Either partition exists, or wrong parameters specified + @return other Failed to create a partition +**/ +EFI_STATUS +PartitionGptCreatePartition ( + IN CONST CHAR16 *PartName, + IN EFI_LBA StartLba, + IN UINT64 SizeInMegabytes, + IN UINT64 Attributes, + IN EFI_GUID PartTypeGuid) +{ + EFI_GUID Guid, PartitionIdGuid; + EFI_STATUS Status; + UINT64 StartBlock; + UINT64 EndBlock; + UINT64 SizeInBytes = 0; + UINT32 BlockSize; + UINT64 DiskSizeBlocks; + UINT8 *p; + BOOLEAN OffsetSpecified = FALSE; + BOOLEAN AllZeros; + INTN AllZeroEntry; + INTN OldFreeEntry; + UINT64 AvailBlocks; + UINT64 BlocksToAllocate; + UINT64 HighSeen; + UINTN Slot; + UINT64 LowestAlignedLba; + UINT32 OptimalTransferBlocks; + UINTN i, j; + CHAR16 PartNameUsed[MAX_PARTITION_NAME_LENGTH + 1] = { L'\0' }; + EFI_PARTITION_ENTRY *Entry; + + LowestAlignedLba = 0; + OptimalTransferBlocks = 1; + + AllZeroEntry = -1; + OldFreeEntry = -1; + + BlockSize = BlockIo->Media->BlockSize; + OffsetSpecified = (StartLba != 0); + CopyMem (&PartNameUsed, PartName, sizeof(CHAR16) * StrSize (PartName)); + + GenerateGuid (&Guid); + + // Creating a new partition + if (!GptValid) { + // Creating a GPT for the first time + Status = TableCreateEmptyGpt (); + if (!EFI_ERROR (Status)) { + // Fill in the structures + Status = PartitionGetGptTables (DiskIo, BlockIo); + } + if (EFI_ERROR (Status)) { + return Status; + } + } + + Entry = PartitionFindPartitionByCriteria (PartName, 0, 0, SRC_BY_NAME); + if (Entry) { + Status = EFI_INVALID_PARAMETER; + PrintErr (L"Partition with this name already exists", Status); + return Status; + } + HighSeen = PrimaryHeader->FirstUsableLBA - 1; + + if (StartLba) { + // + // if offset is specified, compute the start and end blocks + // + StartBlock = StartLba; + // + // StartBlock should be aligned to OptimalTransferBlocks, the least common multiple of: + // a). the physical block boundary, if any + // b). the optimal transfer length granularity, if any + // + if (StartBlock < LowestAlignedLba) { + StartBlock = LowestAlignedLba; + } else { + while (((StartBlock - LowestAlignedLba) % OptimalTransferBlocks) != 0) { + StartBlock++; + } + } + + if (StartBlock < PrimaryHeader->FirstUsableLBA || + StartBlock > PrimaryHeader->LastUsableLBA) { + // + // Offset specified is too large + // + Status = EFI_INVALID_PARAMETER; + PrintErr (L"Specified offset is too large", EFI_INVALID_PARAMETER); + goto Exit; + } + + SizeInBytes = MultU64x32 (SizeInMegabytes, (1024 * 1024)); + if (SizeInBytes < SizeInMegabytes || SizeInBytes == 0) { + // + // If size is not specified or too large, + // try to make the partition as big as it can be + // + BlocksToAllocate = EndBlock = SizeInBytes = 0xffffffffffffffff; + } else { + BlocksToAllocate = DivU64x32 (SizeInBytes, BlockSize); + EndBlock = StartBlock + BlocksToAllocate - 1; + if (EndBlock > PrimaryHeader->LastUsableLBA) { + EndBlock = PrimaryHeader->LastUsableLBA; + BlocksToAllocate = EndBlock - StartBlock + 1; + } + } + } + + for (i = 0; i < PrimaryHeader->NumberOfPartitionEntries; i++) { + Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + i * PrimaryHeader->SizeOfPartitionEntry); + if (!CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) { + + // + // Type not null, so it's allocated + // + if (Entry->EndingLBA > HighSeen) { + HighSeen = Entry->EndingLBA; + } + if (OffsetSpecified) { + // + // make sure new partition does not overlap with existing partitions + // + if (Entry->StartingLBA <= StartBlock && + StartBlock <= Entry->EndingLBA) { + // + // starting block is inside an existing partition + // + Status = EFI_INVALID_PARAMETER; + PrintErr (L"Starting block is inside an existing partition", Status); + goto Exit; + } + if ((Entry->StartingLBA <= EndBlock && + EndBlock <= Entry->EndingLBA) || + (StartBlock <= Entry->StartingLBA && + Entry->StartingLBA <= EndBlock) || + (StartBlock <= Entry->EndingLBA && + Entry->EndingLBA <= EndBlock)) { + // + // new partition overlaps with an existing partition + // readjust new partition size to avoid overlapping + // + EndBlock = Entry->StartingLBA - 1; + if (EndBlock < StartBlock) { + Status = EFI_INVALID_PARAMETER; + PrintErr (L"Cannot readjust new partition size - overlapping", Status); + goto Exit; + } else { + BlocksToAllocate = EndBlock - StartBlock + 1; + } + } + } + } else { + p = (UINT8 *)(Entry); + AllZeros = TRUE; + for (j = 0; j < sizeof(EFI_PARTITION_ENTRY); j++) { + if (p[j] != 0) { + AllZeros = FALSE; + } + } + if (AllZeros) { + if (AllZeroEntry == -1) { + AllZeroEntry = i; + } + } else if (OldFreeEntry == -1) { + OldFreeEntry = i; + } + } + } + + // + // AllZeroEntry - if not -1, is pointer to a never before used entry (free) + // OldFreeEntry - if not -1, is pointer to some pre-used free entry + // + if ((AllZeroEntry == -1) && (OldFreeEntry == -1)) { + // + // TABLE IS FULL!! + // + Status = EFI_OUT_OF_RESOURCES; + PrintErr (L"Table is full", Status); + goto Exit; + } + + if (OffsetSpecified) { + // + // the user haven't specified the new partition size and we haven't + // run into any partition that will limit the size of this new partition. + // So, use the max it can + // + if (BlocksToAllocate == -1) { + EndBlock = PrimaryHeader->LastUsableLBA; + BlocksToAllocate = EndBlock - StartBlock + 1; + } + } else { + // + // Because HighSeen is the last LBA of the used blocks, let HighSeen align to the least common multiple of: + // a). the physical block boundary, if any + // b). the optimal transfer length granularity, if any + // + if (HighSeen + 1 < LowestAlignedLba) { + HighSeen = LowestAlignedLba - 1; + } else { + while (((HighSeen + 1 - LowestAlignedLba) % OptimalTransferBlocks) != 0) { + HighSeen++; + } + } + + if (PrimaryHeader->LastUsableLBA <= HighSeen) { + Status = EFI_OUT_OF_RESOURCES; + PrintErr (L"Disk has no free blocks (FULL) cannot create", Status); + goto Exit; + } + // + // [HighSeen+1 ... LastUsableLBA] is available... + // avail = (LastUsableLBA - (HighSeen+1)) + 1 => LastUsabbleLBA - HighSeen + // + AvailBlocks = PrimaryHeader->LastUsableLBA - HighSeen; + + SizeInBytes = MultU64x32 (SizeInMegabytes, (1024 * 1024)); + if (SizeInBytes < SizeInMegabytes) { + // + // overflow, force a very big answer + // + SizeInBytes = 0xffffffffffffffff; + } + + if ((SizeInBytes == 0) || + (SizeInBytes > (MultU64x32 (AvailBlocks, BlockSize)))) { + // + // User asked for zero, or for more than we've got, + // so give them all that is left + // + BlocksToAllocate = AvailBlocks; + + } else { + + // + // We would have to have a BlockSize > 1mb for Remainder to + // not be 0. Since we cannot actually test this case, we + // ingore it... + // + BlocksToAllocate = DivU64x32 (SizeInBytes, BlockSize); + + } + } + + // + // We have a name + // We have a type guid + // We have a size in blocks + // We have an attribute mask + // + + if (BlocksToAllocate < ((1024 * 1024) / BlockSize)) { + Status = EFI_OUT_OF_RESOURCES; + PrintErr (L"Partition is too small to be created", Status); + goto Exit; + } + + if (GPT_DEBUG_LEVEL) { + Print (L"Requested SizeInMegaBytes = %ld\n", SizeInMegabytes); + Print (L"Resulting size in Blocks = %ld\n", BlocksToAllocate); + Print (L"Results size in Bytes = %ld\n", MultU64x32 (BlocksToAllocate, BlockSize)); + } + + if (AllZeroEntry != -1) { + Slot = AllZeroEntry; + } else { + Slot = OldFreeEntry; + } + + GenerateGuid (&PartitionIdGuid); + Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Slot * PrimaryHeader->SizeOfPartitionEntry); + + CopyMem (&Entry->PartitionTypeGUID, &PartTypeGuid, sizeof(EFI_GUID)); + CopyMem (&Entry->UniquePartitionGUID, &PartitionIdGuid, sizeof(EFI_GUID)); + if (OffsetSpecified) { + PartEntry[Slot].StartingLBA = StartBlock; + PartEntry[Slot].EndingLBA = EndBlock; + } else { + PartEntry[Slot].StartingLBA = HighSeen + 1; + PartEntry[Slot].EndingLBA = HighSeen + BlocksToAllocate; + } + + if (!(((Entry->EndingLBA - Entry->StartingLBA) + 1) == BlocksToAllocate)) { + PrintErr (L"Wrong Size for new partiton", EFI_INVALID_PARAMETER); + goto Exit; + } + + if ((Entry->StartingLBA < PrimaryHeader->FirstUsableLBA) || + (Entry->EndingLBA > PrimaryHeader->LastUsableLBA)) { + PrintErr (L"New Partition out of bounds", EFI_INVALID_PARAMETER); + goto Exit; + } + + Entry->Attributes = Attributes; + CopyMem (&(Entry->PartitionName[0]), PartName, MAX_PARTITION_NAME_LENGTH * sizeof(CHAR16)); + + DiskSizeBlocks = BlockIo->Media->LastBlock + 1; + if (DiskSizeBlocks > 0xffffffff) { + DiskSizeBlocks = 0xffffffff; + } + + Status = WriteGPT (); + + if (EFI_ERROR (Status)) { + PrintErr (L"Attempt to Write out partition table failed", Status); + } + + Exit: + return Status; +} + +/** + Modifiy a partition based on parameters. + + @param Entry Pointer to an existing partition + @param Params Parameters to be modified + @param Flags Which parameter is to be modified + + @return EFI_SUCCESS Successfully modified the partition + @return other Failed to modify a partition + +**/ + +EFI_STATUS +PartitionGptModifyPartition ( + IN EFI_PARTITION_ENTRY *Entry, + IN MOD_PARAMS *Params, + IN MOD_FLAGS Flags + ) +{ + EFI_STATUS Status; + + ASSERT (Entry); + + Status = EFI_INVALID_PARAMETER; + + switch (Flags) { + case MOD_DELETE: + ZeroMem (Entry, sizeof(EFI_PARTITION_ENTRY)); + break; + case MOD_ATTR: + Entry->Attributes = Params->Attributes; + break; + case MOD_TYPE: + Entry->PartitionTypeGUID = Params->PartTypeGuid; + break; + case MOD_RENAME: + StrCpy (Entry->PartitionName, Params->NewName); + break; + default: + PrintErr (L"Unknown modification flag(s)", Status); + return Status; + } + + return WriteGPT (); +} + +EFI_KNOWN_PARTITION_TYPE *PartitionGetKnownType ( + IN UINTN Index, + IN OUT OPTIONAL UINTN *NumEntries + ) +{ + if (NumEntries) { + *NumEntries = ARRAY_SIZE(PartitionTypes); + } + if (Index > ARRAY_SIZE(PartitionTypes)) { + return NULL; + } + + return &PartitionTypes[Index]; +} + diff --git a/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h new file mode 100644 index 000000000000..9efec5cefe94 --- /dev/null +++ b/ShellPkg/Library/UefiShellGptCommandLib/GptWorker.h @@ -0,0 +1,186 @@ +/* + * BSD LICENSE + * + * Copyright(c) 2016 Broadcom. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Broadcom nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* GPT partitioner header file */ + +#ifndef _GPTWORKER_H_ +#define _GPTWORKER_H_ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef enum { + MOD_NAME = BIT0, + MOD_ATTR = BIT1, + MOD_TYPE = BIT2, + MOD_DELETE = BIT3, + MOD_RENAME = BIT4 +} MOD_FLAGS; + +typedef struct { + UINTN Attributes; + EFI_GUID PartTypeGuid; + CONST CHAR16 *PartName; + CONST CHAR16 *NewName; +} MOD_PARAMS; + +typedef enum { + SRC_BY_NAME = BIT0, + SRC_BY_LBA = BIT1, + SRC_BY_NUM = BIT2, + SRC_ANY = BIT3 +} SEARCH_TYPE; + +#define MAX_PARTITION_NAME_LENGTH 36 +#define ENTRY_DEFAULT 128 +#define GPT_REVISION_1_0 0x00010000 + +#define ARRAY_SIZE(x) \ + (sizeof(x) / sizeof((x)[0])) + +// +// Extract INT32 from char array +// +#define UNPACK_INT32(a) (INT32)( (((UINT8 *) a)[0] << 0) | \ + (((UINT8 *) a)[1] << 8) | \ + (((UINT8 *) a)[2] << 16) | \ + (((UINT8 *) a)[3] << 24) ) + +// +// Extract UINT32 from char array +// +#define UNPACK_UINT32(a) (UINT32)( (((UINT8 *) a)[0] << 0) | \ + (((UINT8 *) a)[1] << 8) | \ + (((UINT8 *) a)[2] << 16) | \ + (((UINT8 *) a)[3] << 24) ) + + +// +// GPT Partition Entry Status +// +typedef struct { + BOOLEAN OutOfRange; + BOOLEAN Overlap; + BOOLEAN OsSpecific; +} EFI_PARTITION_ENTRY_STATUS; + +typedef struct { + CONST EFI_GUID TypeGuid; + CONST CHAR16 *TypeName; + +} EFI_KNOWN_PARTITION_TYPE; + +EFI_KNOWN_PARTITION_TYPE *PartitionGetKnownType ( + IN UINTN Index, + IN OUT OPTIONAL UINTN *NumEntries + ); + +EFI_STATUS +PartitionGetGptTables ( + IN EFI_DISK_IO_PROTOCOL *DiskIoProt, + IN EFI_BLOCK_IO_PROTOCOL *BlockIoProt + ); + +UINTN +PartitionListGptEntries ( + VOID + ); + +VOID +PartitionPrintGptPartInfo ( + IN EFI_PARTITION_ENTRY *Entry + ); + +EFI_STATUS +GetPartitionTypeStr ( + EFI_GUID Guid, + CHAR16 *PartTypeStr, + BOOLEAN NoGuidStr + ); + + +EFI_STATUS +PartitionGptClearAll ( + VOID + ); + +EFI_STATUS +PartitionGptCreatePartition ( + CONST CHAR16 *PartName, + EFI_LBA StartLba, + EFI_LBA PartitionSize, + UINT64 Attributes, + EFI_GUID PartTypeGuid); + +EFI_STATUS +PartitionGptModifyPartition ( + EFI_PARTITION_ENTRY *Entry, + MOD_PARAMS *Params, + MOD_FLAGS Flags + ); + +VOID +GptCleanupGlobals ( + VOID + ); + +EFI_PARTITION_ENTRY * +PartitionFindPartitionByCriteria ( + CONST CHAR16 *Name, + EFI_LBA StartLba, + EFI_LBA EndingLba, + SEARCH_TYPE SearchType); + +VOID +PrintErr (IN CONST CHAR16 *Message, IN EFI_STATUS Status); + +#endif //_GPTWORKER_H_ diff --git a/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c new file mode 100644 index 000000000000..a9d74a780911 --- /dev/null +++ b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.c @@ -0,0 +1,1135 @@ +/******************************************************************************* +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +/* Portions Copyright (C) 2016 Broadcom */ + +#include "FatFormat.h" +#include +#include + +CONST CHAR16 gShellGptFileName[] = L"ShellCommand"; +STATIC CONST CHAR16 gAppName[] = L"gpt"; +EFI_HANDLE gShellGptHiiHandle = NULL; + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + // Partition-related operations + { L"clear", TypeFlag }, // Clears all partitions + { L"create", TypeFlag }, // Creates a partition + { L"delete", TypeFlag }, // Deletes a partition + { L"list", TypeFlag }, // Lists all partitions + { L"rename", TypeFlag }, // Renames a partition + { L"setattr", TypeFlag }, // Set attributes for a partition in partition table + { L"settype", TypeFlag }, + { L"sync", TypeFlag }, // Synchronizes either master or alternative partition table + { L"typesinfo", TypeFlag }, // Verifies correctness of master and alternative partition tables + // BlockIo-related operations + { L"read", TypeFlag }, // Reads n bytes into memory address from a partition starting from a certain lba + { L"readfile", TypeFlag }, // Same as above, but instead of store it in memory saves into a file system + { L"write", TypeFlag }, // Writes n bytes from memory into a partition starting from a certain lba + { L"writefile", TypeFlag }, // Same as above, but instead of getting data from memory reads a file + { L"info", TypeFlag }, // Get information on a certain partition (startLba, lastLba, attributes) + { L"fatformat", TypeFlag }, // FAT format of a partition + { L"-type", TypeValue }, + { L"-yes", TypeFlag }, + { L"-verbose", TypeFlag }, + { NULL, TypeMax } +}; + +typedef enum { + // Not requires presence + CLEAR = BIT0, + CREATE = BIT1, + LIST = BIT2, + SYNC = BIT3, + TYPES_INFO = BIT4, + + // Requires presence + DELETE = BIT5, + INFO = BIT6, + READ = BIT7, + READ_FILE = BIT8, + RENAME = BIT9, + SETATTR = BIT10, + SETTYPE = BIT11, + WRITE = BIT12, + WRITE_FILE = BIT13, + FAT_FORMAT = BIT14, +} Flags; + +/** + Return the file name of the help text file if not using HII. + + @return The string pointer to the file name. +**/ +CONST CHAR16 * +EFIAPI +ShellCommandGetManFileNameGpt ( + VOID + ) +{ + + return gShellGptFileName; +} + +STATIC +EFI_STATUS +OpenAndPrepareFile ( + IN CHAR16 *FilePath, + OUT SHELL_FILE_HANDLE *FileHandle, + IN BOOLEAN WriteNeeded + ) +{ + EFI_STATUS Status; + UINT64 OpenMode; + + OpenMode = EFI_FILE_MODE_READ; + + if (WriteNeeded) { + OpenMode |= EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE; + } + + Status = ShellOpenFileByName (FilePath, FileHandle, OpenMode, 0); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, + NULL, STRING_TOKEN (STR_GPT_ERROR), + gShellGptHiiHandle, + gAppName, + Status, + L"Cannot open file" + ); + return Status; + } + + Status = FileHandleSetPosition (*FileHandle, 0); + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, + NULL, STRING_TOKEN (STR_GPT_ERROR), + gShellGptHiiHandle, + gAppName, + Status, + "Cannot set file position to the first byte" + ); + + ShellCloseFile (FileHandle); + return Status; + } + + return EFI_SUCCESS; +} + +VOID +PrintErr ( + IN CONST CHAR16 *Message, + IN EFI_STATUS Status + ) +{ + ShellPrintHiiEx (-1, -1, + NULL, STRING_TOKEN (STR_GPT_ERROR), + gShellGptHiiHandle, + gAppName, + Status, + Message + ); +} + +STATIC +BOOLEAN +IsPartitionableDevicePath ( + IN EFI_DEVICE_PATH *DevicePath + ) +{ + UINTN PathSize; + EFI_DEVICE_PATH *PathInstance; + BOOLEAN Partitionable; + + Partitionable = TRUE; + while (DevicePath != NULL) { + PathInstance = GetNextDevicePathInstance (&DevicePath, &PathSize); + + while (!IsDevicePathEnd (PathInstance)) { + if ((DevicePathType (PathInstance) == MEDIA_DEVICE_PATH)) { + Partitionable = FALSE; + } + + PathInstance = NextDevicePathNode (PathInstance); + } + } + return Partitionable; +} + +STATIC +EFI_STATUS +GptPromptYesNo ( + IN CONST EFI_STRING_ID HiiFormatStringId + ) +{ + EFI_STATUS Status; + VOID *Response; + + Status = ShellPromptForResponseHii (ShellPromptResponseTypeYesNo, HiiFormatStringId, gShellGptHiiHandle, &Response); + if ((EFI_ERROR (Status)) || (*(SHELL_PROMPT_RESPONSE *)Response) != ShellPromptResponseYes) { + return EFI_ABORTED; + } + + return EFI_SUCCESS; +} + +STATIC +VOID FormatSize( + UINT64 Size, CHAR16 *Buffer) +{ +#define MAX_SIZE_BUF_SIZE 32 + UINT64 Base, Frac; + CHAR16 Metric; + + Metric = L'B'; + Frac = 0; + if (Size < SIZE_1KB) { + Base = Size; + } else if (Size < SIZE_1MB) { + Base = Size / SIZE_1KB; + Frac = ((Size % SIZE_1KB) * 10) >> 10; + Metric = L'K'; + } else if (Size < SIZE_1GB) { + Base = Size / SIZE_1MB; + Frac = ((Size % SIZE_1MB) * 10) >> 20; + Metric = L'M'; + } else if (Size < SIZE_1TB) { + Base = Size / SIZE_1GB; + Frac = ((Size % SIZE_1GB) * 10) >> 30; + Metric = L'G'; + } else { + Base = Size / SIZE_1TB; + Frac = ((Size % SIZE_1TB) * 10) >> 40; + Metric = L'T'; + } + if (Frac) { + UnicodeSPrint (Buffer, MAX_SIZE_BUF_SIZE, L"%d.%d%c", Base, Frac, Metric); + } else { + UnicodeSPrint (Buffer, MAX_SIZE_BUF_SIZE, L"%d%c", Base, Metric); + } +} + +STATIC +EFI_STATUS +FindAndPrintPartitionableDevices (VOID) +{ + UINTN Index; + EFI_HANDLE *HandlePointer; + UINTN HandleCount; + UINTN DevCount; + EFI_STATUS Status; + BOOLEAN FirstTime; + + Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &HandleCount, &HandlePointer); + if (EFI_ERROR (Status)) { + return Status; + } + + DevCount = 0; + FirstTime = TRUE; + + for (Index = 0; Index < HandleCount; Index++) { + EFI_DEVICE_PATH *DevicePath; + CONST CHAR16 *MapPath; + CHAR16 *Match; + EFI_BLOCK_IO *BlkIo; + EFI_DISK_IO *DiskIo; + CHAR16 *BufferForSize; + + Status = gBS->HandleProtocol (HandlePointer[Index], &gEfiBlockIoProtocolGuid, (VOID **)&BlkIo); + if (EFI_ERROR (Status)) { + continue; + } + + DevicePath = DevicePathFromHandle (HandlePointer[Index]); + if (!IsPartitionableDevicePath (DevicePath)) { + continue; + } + MapPath = gEfiShellProtocol->GetMapFromDevicePath (&DevicePath); + if (MapPath == NULL) { + continue; + } + + Status = gBS->HandleProtocol (HandlePointer[Index], &gEfiDiskIoProtocolGuid, (VOID **)&DiskIo); + if (EFI_ERROR (Status)) { + continue; + } + + Match = StrStr (MapPath, L";BLK"); + if (Match) { + MapPath = Match; + MapPath++; + } + + if (FirstTime) { + BufferForSize = AllocateZeroPool (MAX_SIZE_BUF_SIZE * sizeof (CHAR16)); + ASSERT (BufferForSize); + Print (L" Device\t Size Comments\n"); + Print (L" ------ ------- ------------------------------------------------------------\n"); + FirstTime = FALSE; + } + GptCleanupGlobals (); + FormatSize (MultU64x32 (BlkIo->Media->LastBlock + 1, BlkIo->Media->BlockSize), BufferForSize); + ShellPrintHiiEx (-1, -1, + NULL, STRING_TOKEN (STR_GPT_LIST_DEVS), + gShellGptHiiHandle, + MapPath, + BufferForSize); + if (BlkIo->Media->ReadOnly) { + Print (L"Read-Only! "); + } + if (!BlkIo->Media->MediaPresent) { + Print (L"No Media! "); + } + if (!EFI_ERROR (PartitionGetGptTables (DiskIo, BlkIo))) { + Print (L"Valid GPT. "); + } + if (BlkIo->Media->RemovableMedia) { + Print (L"Removable device."); + } + Print (L"\n"); + DevCount++; + } + Print (L"\r\n"); + if (DevCount) { + Print (L"%d potentially partitionable device(s) found\n", DevCount); + } else { + Print (L"No potentially partitionable device(s) found\n"); + } + + GptCleanupGlobals (); + return EFI_SUCCESS; +} + +SHELL_STATUS +EFIAPI +ShellCommandRunGpt ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *CheckPackage; + EFI_PHYSICAL_ADDRESS Address = 0, Offset = 0; + UINT64 PartAttributes = 0; + EFI_GUID PartTypeGuid = { 0 }; + SHELL_FILE_HANDLE FileHandle = NULL; + UINT64 ByteCount, FileSize; + UINTN I; + UINT8 *Buffer = NULL, *FileBuffer = NULL; + + CHAR16 * ProblemParam,*FilePath; + CONST CHAR16 *AddressStr = NULL, *OffsetStr = NULL; + CONST CHAR16 *PartName = NULL, *NewPartName = NULL, *AttrStr = NULL, + *GuidStr = NULL, *VolumeName = NULL; + CONST CHAR16 *LengthStr = NULL, *FileStr = NULL; + BOOLEAN AddrFlag = FALSE, LengthFlag = TRUE, FileFlag = FALSE, GuidFlag = FALSE, OffsetFlag = TRUE; + BOOLEAN PartNameFlag = TRUE, NewPartNameFlag = FALSE, AttrFlag = FALSE; + UINTN Flag = 0, CheckFlag = 0; + CONST CHAR16 *BlockName; + EFI_DEVICE_PATH_PROTOCOL *DevPath; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + EFI_DISK_IO_PROTOCOL *DiskIo; + EFI_HANDLE BlockIoHandle; + MOD_PARAMS ModParams; + EFI_PARTITION_ENTRY *Entry; + UINTN NumKnownPartTypesEntries; + BOOLEAN TableNotEmpty, NoPrompt = FALSE, Quiet = TRUE; + UINT64 TimeStampB, TimeStampE, SpeedKB, Freq; + + // Parse Shell command line + Status = ShellInitialize (); + if (EFI_ERROR (Status)) { + PrintErr (L"Cannot initialize Shell", Status); + ASSERT_EFI_ERROR (Status); + return SHELL_ABORTED; + } + + Status = ShellCommandLineParse (ParamList, &CheckPackage, &ProblemParam, TRUE); + if (EFI_ERROR (Status)) { + PrintErr (L"Error while parsing command line", Status); + return SHELL_ABORTED; + } + + TimeStampB = 0; + TimeStampE = 0; + + NoPrompt = ShellCommandLineGetFlag (CheckPackage, L"-yes"); + Quiet = !ShellCommandLineGetFlag (CheckPackage, L"-verbose"); + + Freq = GetPerformanceCounterProperties (NULL, NULL); + + // Check flags provided by user + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"clear") << 0); + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"create") << 1); + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"list") << 2); + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"sync") << 3); + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"typesinfo") << 4); + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"delete") << 5); + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"info") << 6); + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"read") << 7); + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"readfile") << 8); + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"rename") << 9); + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"setattr") << 10); + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"settype") << 11); + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"write") << 12); + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"writefile") << 13); + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"fatformat") << 14); + + PartitionGetKnownType ((UINTN)(-1), &NumKnownPartTypesEntries); + + if (Flag & TYPES_INFO) { + UINTN Index; + + Print (L" No\t%-36s\tGUID\r\n", L"Type name"); + Print (L" ---- ---------------------------------- ------------------------------------\n"); + for (Index = 0; Index < NumKnownPartTypesEntries; Index++) { + EFI_KNOWN_PARTITION_TYPE *PartType; + + PartType = PartitionGetKnownType (Index, NULL); + if (PartType == NULL) { + break; + } + Print (L" %3d\t%-36s\t%g\n", Index, PartType->TypeName, &PartType->TypeGuid); + } + if (Flag == TYPES_INFO) { + return SHELL_SUCCESS; + } + } + // Start parsing the command. + // Generally command is: + // block_name:bootpart_no addr or filename offset + + BlockName = ShellCommandLineGetRawValue (CheckPackage, 1); + if (BlockName == NULL) { + if (Flag & LIST) { + Status = FindAndPrintPartitionableDevices (); + if (EFI_ERROR (Status)) { + PrintErr (L"Error getting list of partitionable devices", Status); + Status = SHELL_ABORTED; + } + return Status; + } + PrintErr (L"Missing block device name", EFI_INVALID_PARAMETER); + return SHELL_INVALID_PARAMETER; + } + + // Find device handle by mapped name + if (gEfiShellProtocol->GetDevicePathFromMap (BlockName) == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellGptHiiHandle, gAppName, BlockName); + Status = SHELL_INVALID_PARAMETER; + } else { + DevPath = (EFI_DEVICE_PATH_PROTOCOL *)gEfiShellProtocol->GetDevicePathFromMap (BlockName); + if (gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &DevPath, NULL) == EFI_NOT_FOUND) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_MAP_PROTOCOL), gShellGptHiiHandle, gAppName, BlockName, L"BlockIo"); + Status = SHELL_INVALID_PARAMETER; + } + } + + if (Status) { + return SHELL_INVALID_PARAMETER; + } + + BlockIoHandle = 0; + + Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, (EFI_DEVICE_PATH_PROTOCOL **)&DevPath, &BlockIoHandle); + if (EFI_ERROR (Status)) { + goto CleanUp; + } + + Status = gBS->OpenProtocol (BlockIoHandle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo, gImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_MAP_PROTOCOL), gShellGptHiiHandle, gAppName, BlockName, L"BlockIo"); + goto CleanUp; + } + + Status = gBS->HandleProtocol ( + BlockIoHandle, + &gEfiDiskIoProtocolGuid, + (VOID **)&DiskIo + ); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_MAP_PROTOCOL), gShellGptHiiHandle, gAppName, BlockName, L"DiskIo"); + goto CleanUp; + } + + CheckFlag = Flag; + for (I = 0; CheckFlag; CheckFlag >>= 1) { + I += CheckFlag & 1; + if (I > 1) { + PrintErr (L"Too many flags", EFI_INVALID_PARAMETER); + Status = SHELL_INVALID_PARAMETER; + goto CleanUp; + } + } + + if (Flag & SYNC) { + // Let the Partition table driver know that + // we want to reread the tables + Status = gBS->ReinstallProtocolInterface ( + BlockIoHandle, + &gEfiBlockIoProtocolGuid, + BlockIo, + BlockIo + ); + Status = SHELL_SUCCESS; + goto CleanUp; + } + + if (!IsPartitionableDevicePath (DevicePathFromHandle (BlockIoHandle))) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellGptHiiHandle, gAppName, BlockName); + Print (L"%s is not a raw block device\n", BlockName); + Status = SHELL_INVALID_PARAMETER; + goto CleanUp; + } + + if (!BlockIo->Media->MediaPresent) { + PrintErr (L"Media is not present!\n", EFI_NO_MEDIA); + Status = EFI_NO_MEDIA; + goto CleanUp; + } + + // Preload GPT tables with validation + Status = PartitionGetGptTables (DiskIo, BlockIo); + if (EFI_ERROR (Status)) { + BOOLEAN CanContinue; + + CanContinue = (Flag & CREATE) || (Flag & CLEAR) || (Flag & FAT_FORMAT); + if (Status != EFI_NOT_FOUND) { + PrintErr (L"Unexpected error getting GPT tables", Status); + goto CleanUp; + } else { + if (!CanContinue) { + PrintErr (L"No GPT table found. Create first", Status); + goto CleanUp; + } + } + } + + // Do we have any partitions already? + TableNotEmpty = (PartitionFindPartitionByCriteria (NULL, 0, 0, SRC_ANY) != NULL); + + Status = SHELL_INVALID_PARAMETER; + + if ((Flag < LIST) || + (Flag & DELETE) || + (Flag > READ_FILE) + ) { + if (BlockIo->Media->ReadOnly) { + Status = EFI_INVALID_PARAMETER; + PrintErr (L"Cannot write to a read-only device", Status); + goto CleanUp; + } + } + + if (BlockIo->Media->RemovableMedia) { + Print (L"%s is a removable device. Just a note\n", BlockName); + } + + switch (Flag) { + case INFO: + PartName = ShellCommandLineGetRawValue (CheckPackage, 2); + OffsetFlag = FALSE; + LengthFlag = FALSE; + break; + case LIST: + { + UINTN NumEntries; + + NumEntries = PartitionListGptEntries (); + if (NumEntries == 0) { + Print (L"gpt: GPT is valid on %s, but no partition(s) defined yet. Use create\n", BlockName); + } + Status = SHELL_SUCCESS; + goto CleanUp; + break; + } + case CLEAR: + if (TableNotEmpty) { + // Tell the user what he/she is doing... + ShellPrintHiiEx (-1, -1, + NULL, STRING_TOKEN (STR_GPT_NOT_EMPTY), + gShellGptHiiHandle, + BlockName + ); + } + + // Even if GPT tables do not exist, there might be something. + // Warn the user and double sure it is the intention, + // to prevent a user from bricking a device (JTAG would be needed to recover) + // by overwriting an ATF boot device. However with NoPrompt on, the user is + // responsible for operation because there is no confirmation (assuming yes on all queries). + if ((NoPrompt) || (!GptPromptYesNo (STRING_TOKEN (STR_GPT_CLEAR_SURE)) && + (!GptPromptYesNo (STRING_TOKEN (STR_GPT_ABSOLUTELY_SURE)))) + ) { + PartitionGptClearAll (); + } + Status = SHELL_SUCCESS; + goto CleanUp; + break; + case CREATE: + PartName = ShellCommandLineGetRawValue (CheckPackage, 2); + OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 3); + LengthStr = ShellCommandLineGetRawValue (CheckPackage, 4); + AttrStr = ShellCommandLineGetRawValue (CheckPackage, 5); + GuidStr = ShellCommandLineGetValue (CheckPackage, L"-type"); + GuidFlag = TRUE; + break; + case DELETE: + PartName = ShellCommandLineGetRawValue (CheckPackage, 2); + LengthFlag = FALSE; + OffsetFlag = FALSE; + break; + case RENAME: + PartName = ShellCommandLineGetRawValue (CheckPackage, 2); + NewPartName = ShellCommandLineGetRawValue (CheckPackage, 3); + NewPartNameFlag = TRUE; + LengthFlag = FALSE; + OffsetFlag = FALSE; + break; + case SETATTR: + PartName = ShellCommandLineGetRawValue (CheckPackage, 2); + AttrStr = ShellCommandLineGetRawValue (CheckPackage, 3); + AttrFlag = TRUE; + LengthFlag = FALSE; + OffsetFlag = FALSE; + break; + case SETTYPE: + PartName = ShellCommandLineGetRawValue (CheckPackage, 2); + GuidStr = ShellCommandLineGetValue (CheckPackage, L"-type"); + GuidFlag = TRUE; + LengthFlag = FALSE; + OffsetFlag = FALSE; + break; + case FAT_FORMAT: + PartName = ShellCommandLineGetRawValue (CheckPackage, 2); + VolumeName = ShellCommandLineGetRawValue (CheckPackage, 3); + LengthFlag = FALSE; + OffsetFlag = FALSE; + PartNameFlag = (PartName != NULL); + if (!PartNameFlag && TableNotEmpty) { + // Tell the user what he/she is doing... + ShellPrintHiiEx (-1, -1, + NULL, STRING_TOKEN (STR_GPT_NOT_EMPTY), + gShellGptHiiHandle, + BlockName + ); + } + break; + // Fall through + case READ: + case WRITE: + AddressStr = ShellCommandLineGetRawValue (CheckPackage, 2); + PartName = ShellCommandLineGetRawValue (CheckPackage, 3); + OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 4); + LengthStr = ShellCommandLineGetRawValue (CheckPackage, 5); + AddrFlag = TRUE; + break; + case READ_FILE: + FileStr = ShellCommandLineGetRawValue (CheckPackage, 2); + PartName = ShellCommandLineGetRawValue (CheckPackage, 3); + OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 4); + LengthStr = ShellCommandLineGetRawValue (CheckPackage, 5); + FileFlag = TRUE; + break; + case WRITE_FILE: + FileStr = ShellCommandLineGetRawValue (CheckPackage, 2); + PartName = ShellCommandLineGetRawValue (CheckPackage, 3); + OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 4); + LengthFlag = FALSE; + FileFlag = TRUE; + break; + default: + Print (L"%s: Unsupported command. Try \"help %s\"", gAppName); + Status = SHELL_INVALID_PARAMETER; + goto CleanUp; + } + + // Read address parameter + if ((AddressStr == NULL) & AddrFlag) { + PrintErr (L"No address parameter", EFI_INVALID_PARAMETER); + goto CleanUp; + } else if (AddrFlag) { + Address = ShellHexStrToUintn (AddressStr); + if (Address == (UINTN)(-1)) { + PrintErr (L"Wrong address parameter", EFI_INVALID_PARAMETER); + goto CleanUp; + } + } + + if ((PartName == NULL) & PartNameFlag) { + PrintErr (L"Missing partition name", EFI_INVALID_PARAMETER); + goto CleanUp; + } else if (PartNameFlag) { + if (StrSize (PartName) > MAX_PARTITION_NAME_LENGTH) { + PrintErr (L"Partition name is too long (max 36 chars)", EFI_INVALID_PARAMETER); + goto CleanUp; + } + } + + // Read offset parameter + if ((OffsetStr == NULL) & OffsetFlag) { + PrintErr (L"No offset Parameter", EFI_INVALID_PARAMETER); + goto CleanUp; + } else if (OffsetFlag) { + Offset = ShellHexStrToUintn (OffsetStr); + if (Offset < 0) { + Print (L"%s: Wrong offset parameter: %s\n", gAppName, OffsetStr); + goto CleanUp; + } + } + + // Read length parameter + if ((LengthStr == NULL) & LengthFlag) { + PrintErr (L"No length parameter", EFI_INVALID_PARAMETER); + goto CleanUp; + } else if (LengthFlag) { + ByteCount = (UINT64)ShellStrToUintn (LengthStr); + if (ByteCount < 0) { + Print (L"%s: Wrong length parameter %s!\n", gAppName, LengthStr); + goto CleanUp; + } + } + + if ((NewPartName == NULL) & NewPartNameFlag) { + PrintErr (L"Missing name to be assigned to partition", EFI_INVALID_PARAMETER); + goto CleanUp; + } else if (NewPartNameFlag) { + if (StrSize (NewPartName) > MAX_PARTITION_NAME_LENGTH) { + PrintErr (L"Partition name is too long (max 36 chars)", EFI_INVALID_PARAMETER); + goto CleanUp; + } + } + + if ((AttrStr == NULL) & AttrFlag) { + PrintErr (L"Missing attributes parameter", EFI_INVALID_PARAMETER); + goto CleanUp; + } else if (AttrStr) { + PartAttributes = (UINT64)ShellStrToUintn (AttrStr); + } + + if ((GuidStr == NULL) & GuidFlag) { + PrintErr (L"Missing partition type GUID parameter", EFI_INVALID_PARAMETER); + goto CleanUp; + } else if (GuidFlag) { + Status = SHELL_INVALID_PARAMETER; + if (InternalShellIsHexOrDecimalNumber (GuidStr, FALSE, TRUE, FALSE)) { + UINTN Ordinal; + + Ordinal = ShellStrToUintn (GuidStr); + if (Ordinal < NumKnownPartTypesEntries) { + PartTypeGuid = PartitionGetKnownType (Ordinal, NULL)->TypeGuid; + Status = SHELL_SUCCESS; + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellGptHiiHandle, gAppName, GuidStr); + goto CleanUp; + } + } else { + Status = ConvertStringToGuid (GuidStr, &PartTypeGuid); + if ((EFI_ERROR (Status)) || (IsZeroGuid (&PartTypeGuid))) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellGptHiiHandle, gAppName, GuidStr); + Status = SHELL_INVALID_PARAMETER; + goto CleanUp; + } + } + } + + if (FileFlag) { + // Read FilePath parameter + if (FileStr == NULL) { + PrintErr (L"No FilePath parameter", EFI_INVALID_PARAMETER); + goto CleanUp; + } else { + FilePath = (CHAR16 *)FileStr; + Status = ShellIsFile (FilePath); + // When read file into flash, file doesn't have to exist + if (EFI_ERROR (Status && !(Flag & READ_FILE))) { + PrintErr (L"Wrong FilePath parameter", Status); + Status = SHELL_INVALID_PARAMETER; + goto CleanUp; + } + } + + Status = OpenAndPrepareFile (FilePath, &FileHandle, ((Flag & READ_FILE) != 0)); + if (EFI_ERROR (Status)) { + Print (L"Error %r while preparing file %s", Status, FilePath); + Status = SHELL_ABORTED; + goto CleanUp; + } + + // Get file size in order to check correctness at the end of transfer + if (Flag & (WRITE_FILE)) { + Status = FileHandleGetSize (FileHandle, &FileSize); + if (EFI_ERROR (Status)) { + PrintErr (L"Cannot get file size", Status); + Status = SHELL_ABORTED; + goto CleanUp; + } + ByteCount = (UINT64)FileSize; + } + + FileBuffer = AllocateZeroPool ((UINTN)ByteCount); + if (FileBuffer == NULL) { + PrintErr (L"Cannot allocate memory", EFI_OUT_OF_RESOURCES); + Status = SHELL_OUT_OF_RESOURCES; + goto Error_Close_File; + } + + // Read file content and store it in FileBuffer + if (Flag & (WRITE_FILE)) { + if (!Quiet) { + Print (L"Reading %s...\r", FilePath); + } + Status = FileHandleRead (FileHandle, &ByteCount, FileBuffer); + if (EFI_ERROR (Status)) { + PrintErr (L"Read from file error", Status); + Status = SHELL_ABORTED; + goto Error_Free_Buffer; + } else if (ByteCount != (UINTN)FileSize) { + PrintErr (L"Not whole file read. Abort", EFI_DEVICE_ERROR); + Status = SHELL_DEVICE_ERROR; + goto Error_Free_Buffer; + } + if (!Quiet) { + Print (L"Writing %s into device %s, partition %s...\n", FilePath, BlockName, PartName); + } + } + } + + Buffer = (UINT8 *)Address; + if (FileFlag) { + Buffer = FileBuffer; + } + + if (Flag > TYPES_INFO) { + Entry = PartitionFindPartitionByCriteria (PartName, 0, 0, SRC_BY_NAME); + if (!Entry && PartName && (InternalShellIsHexOrDecimalNumber (PartName, FALSE, TRUE, FALSE))) { + Entry = PartitionFindPartitionByCriteria (PartName, 0, 0, SRC_BY_NUM); + } + if ((!Entry) && (PartNameFlag)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellGptHiiHandle, gAppName, PartName); + Print (L"Could not find partition %s (case-sensitive). Make sure the name is spelled properly\n", PartName); + Status = SHELL_NOT_FOUND; + goto CleanUp; + } + } + + switch (Flag) { + case CREATE: + PartitionGptCreatePartition ( + PartName, + Offset, // Lba. If 0, the next available is assumed + ByteCount, // in MegaBytes. If 0 the whole remaining space is assumed + PartAttributes, + PartTypeGuid); + break; + case DELETE: + ModParams.PartName = PartName; + ShellPrintHiiEx (-1, -1, + NULL, STRING_TOKEN (STR_GPT_DELETE_WARNING), + gShellGptHiiHandle, + Entry->PartitionName + ); + if ((NoPrompt) || (!GptPromptYesNo (STRING_TOKEN (STR_GPT_ABSOLUTELY_SURE)))) { + Status = PartitionGptModifyPartition ( + Entry, &ModParams, MOD_DELETE); + if (EFI_ERROR (Status)) { + PrintErr (L"Error deleting the partition", Status); + Status = SHELL_ABORTED; + goto CleanUp; + } + Status = SHELL_SUCCESS; + } else { + Status = SHELL_ABORTED; + } + break; + case FAT_FORMAT: + { + EFI_LBA StartingLBA, EndingLBA; + CHAR8 LabelName[12]; + + if (VolumeName) { + if (StrLen (VolumeName) > 11) { + Status = EFI_INVALID_PARAMETER; + PrintErr (L"The volume label is too long", Status); + Status = SHELL_INVALID_PARAMETER; + goto CleanUp; + } + UnicodeStrToAsciiStr (VolumeName, (CHAR8 *)LabelName); + } + ShellPrintHiiEx (-1, -1, + NULL, STRING_TOKEN (STR_GPT_FORMAT_WARNING), + gShellGptHiiHandle, + Entry ? Entry->PartitionName : BlockName + ); + + if ((NoPrompt) || (!GptPromptYesNo (STRING_TOKEN (STR_GPT_FORMAT_SURE)) && + (!GptPromptYesNo (STRING_TOKEN (STR_GPT_ABSOLUTELY_SURE)))) + ) { + StartingLBA = 0; + EndingLBA = BlockIo->Media->LastBlock; + if (Entry) { + StartingLBA = Entry->StartingLBA; + EndingLBA = Entry->EndingLBA; + } + if (!Quiet) { + Print (L"Formatting %s to FAT32...\r", PartNameFlag ? Entry->PartitionName : BlockName); + } + Status = FatFormat (StartingLBA, EndingLBA, BlockIo, DiskIo, VolumeName ? LabelName : NULL, TRUE); + if (EFI_ERROR (Status)) { + PrintErr (L"Error formatting the partition to FAT ", Status); + Status = SHELL_ABORTED; + goto CleanUp; + } else if (!Quiet) { + Print (L"%s successfully formatted to FAT. Formatted size %llu MiB\n", + PartNameFlag ? Entry->PartitionName : BlockName, + MultU64x32 (EndingLBA - StartingLBA + 1, BlockIo->Media->BlockSize) >> 20 + ); + } + } else { + Status = SHELL_ABORTED; + } + } + break; + case RENAME: + ModParams.PartName = PartName; + ModParams.NewName = NewPartName; + Status = PartitionGptModifyPartition ( + Entry, &ModParams, MOD_RENAME); + break; + case SETATTR: + ModParams.Attributes = PartAttributes; + Status = PartitionGptModifyPartition ( + Entry, &ModParams, MOD_ATTR); + break; + case SETTYPE: + ModParams.PartTypeGuid = PartTypeGuid; + Status = PartitionGptModifyPartition ( + Entry, &ModParams, MOD_TYPE); + break; + case INFO: + PartitionPrintGptPartInfo (Entry); + Status = SHELL_SUCCESS; + break; + case READ: + case READ_FILE: + case WRITE: + case WRITE_FILE: + { + UINT64 MaxBytes; + BOOLEAN OpRead; + + OpRead = ((Flag & READ) || (Flag & READ_FILE)); + MaxBytes = MultU64x32 ( + Entry->EndingLBA - Entry->StartingLBA, + BlockIo->Media->BlockSize) + + BlockIo->Media->BlockSize - + MultU64x32 (Offset, BlockIo->Media->BlockSize); + if (ByteCount > MaxBytes) { + Status = EFI_INVALID_PARAMETER; + ShellPrintHiiEx (-1, -1, + NULL, (OpRead) ? + STRING_TOKEN (STR_GPT_READ_BOUNDARY) : + STRING_TOKEN (STR_GPT_WRITE_BOUNDARY), + gShellGptHiiHandle, + gAppName, + Entry->PartitionName, + MaxBytes, + ByteCount + ); + Status = SHELL_INVALID_PARAMETER; + goto CleanUp; + } + + TimeStampB = GetPerformanceCounter (); + if (OpRead) { + Status = DiskIo->ReadDisk (DiskIo, + BlockIo->Media->MediaId, + MultU64x32 (Offset + Entry->StartingLBA, BlockIo->Media->BlockSize), ByteCount, Buffer); + } else { + Status = DiskIo->WriteDisk (DiskIo, BlockIo->Media->MediaId, + MultU64x32 (Offset + Entry->StartingLBA, BlockIo->Media->BlockSize), ByteCount, Buffer); + } + } + break; + default: + Status = SHELL_INVALID_PARAMETER; + PrintErr (L"Unknown command. Try \"help gpt\"", EFI_INVALID_PARAMETER); + goto CleanUp; + } + + if (EFI_ERROR (Status)) { + PrintErr (L"Error while performing transfer\n", Status); + Status = SHELL_ABORTED; + goto CleanUp; + } + + TimeStampE = ((GetPerformanceCounter () - TimeStampB) * 1000) / Freq; + SpeedKB = TimeStampE ? (ByteCount / (TimeStampE / 1000)) >> 10 : 0; + + switch (Flag) { + case WRITE: + case WRITE_FILE: + if (!Quiet) { + ShellPrintHiiEx (-1, -1, + NULL, + STRING_TOKEN (STR_GPT_WRITE_OK), + gShellGptHiiHandle, + ByteCount, + Offset, + Entry->PartitionName, + TimeStampE, + SpeedKB + ); + } + break; + case READ: + if (!Quiet) { + ShellPrintHiiEx (-1, -1, + NULL, + STRING_TOKEN (STR_GPT_READ_OK), + gShellGptHiiHandle, + ByteCount, + Offset, + Entry->PartitionName, + TimeStampE, + SpeedKB + ); + } + break; + case READ_FILE: + Status = FileHandleWrite (FileHandle, &ByteCount, FileBuffer); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, + NULL, + STRING_TOKEN (STR_GPT_FILE_WRITE_FAIL), + gShellGptHiiHandle, + gAppName, + FilePath, + Status + ); + Status = SHELL_DEVICE_ERROR; + goto Error_Free_Buffer; + } + + if (!Quiet) { + ShellPrintHiiEx (-1, -1, + NULL, + STRING_TOKEN (STR_GPT_READFILE_OK), + gShellGptHiiHandle, + ByteCount, + Offset, + Entry->PartitionName, + FilePath, + TimeStampE, + SpeedKB + ); + } + break; + } + + if (FileFlag) { + SHELL_FREE_NON_NULL (FileBuffer); + if (FileHandle != NULL) { + ShellCloseFile (&FileHandle); + FileHandle = NULL; + } + } + + Status = SHELL_SUCCESS; + + Error_Free_Buffer: + SHELL_FREE_NON_NULL (FileBuffer); + Error_Close_File: + if (FileHandle) { + ShellCloseFile (&FileHandle); + } + CleanUp: + if (BlockIoHandle) { + // By UEFI Spec blocks must be flushed + BlockIo->FlushBlocks (BlockIo); + gBS->CloseProtocol (BlockIoHandle, &gEfiBlockIoProtocolGuid, gImageHandle, NULL); + } + + GptCleanupGlobals (); + + ShellCommandLineFreeVarList (CheckPackage); + + if (EFI_ERROR (Status)) { + Status = SHELL_ABORTED; + } + + return Status; +} + +EFI_STATUS +EFIAPI +ShellGptLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + gShellGptHiiHandle = NULL; + + gShellGptHiiHandle = HiiAddPackages ( + &gShellGptHiiGuid, gImageHandle, + UefiShellGptCommandLibStrings, NULL + ); + if (gShellGptHiiHandle == NULL) { + return EFI_DEVICE_ERROR; + } + + ShellCommandRegisterCommandName ( + gAppName, ShellCommandRunGpt, ShellCommandGetManFileNameGpt, 0, + gAppName, TRUE, gShellGptHiiHandle, STRING_TOKEN (STR_GET_HELP_GPT) + ); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +ShellGptLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + + if (gShellGptHiiHandle != NULL) { + HiiRemovePackages (gShellGptHiiHandle); + } + return EFI_SUCCESS; +} diff --git a/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf new file mode 100644 index 000000000000..1be4b1ab0f11 --- /dev/null +++ b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf @@ -0,0 +1,79 @@ +# +# Marvell BSD License Option +# +# If you received this File from Marvell, you may opt to use, redistribute +# and/or modify this File under the following licensing terms. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of Marvell nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +# +# Portions Copyright (C) 2016 Broadcom +# + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = UefiShellGptCommandLib + FILE_GUID = F62ACF25-0D15-22F5-E642-FFB6515E00D7 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 0.1 + LIBRARY_CLASS = NULL|UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = ShellGptLibConstructor + DESTRUCTOR = ShellGptLibDestructor + +[Sources] + FatFormat.c + GptWorker.c + UefiShellGptCommandLib.c + UefiShellGptCommandLib.uni + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + DevicePathLib + FileHandleLib + HiiLib + MemoryAllocationLib + PcdLib + ShellCommandLib + ShellLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + UefiLib + +[Protocols] + gEfiBlockIoProtocolGuid + gEfiDevicePathProtocolGuid + gEfiDiskIoProtocolGuid + +[Guids] + gShellGptHiiGuid + gEfiPartTypeUnusedGuid ## SOMETIMES_CONSUMES ## GUID diff --git a/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni new file mode 100644 index 000000000000..55bcb42cfeb3 --- /dev/null +++ b/ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.uni @@ -0,0 +1,117 @@ +/******************************************************************************* +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +/* Portions Copyright (C) 2016 Broadcom */ +/=# + +#langdef en-US "english" + +#string STR_GEN_PARAM_INV #language en-US "%H%s%N: Invalid argument - '%H%s%N'\r\n" +#string STR_GEN_MAP_PROTOCOL #language en-US "%H%s%N: Mapped device '%B%s%N' does not have protocol %B%s%N\r\n" + +#string STR_GPT_ERROR #language en-US "%H%s%N: %r - %s\r\n" +#string STR_GPT_NOT_EMPTY #language en-US "%H%s%N: WARNING!!! This device has valid GPT partition tables!\r\n" +#string STR_GPT_CLEAR_SURE #language en-US "Are you sure you want to clear the GPT tables on this device? %BY%Nes, %BN%No " +#string STR_GPT_ABSOLUTELY_SURE #language en-US "\r\nAre you *** ABSOLUTELY SURE *** you want to perform this operation ? %BY%Nes, %BN%No " +#string STR_GPT_FORMAT_WARNING #language en-US "%H%s%N: WARNING!!! Formatting of this partition will destroy all data on it!\r\n" +#string STR_GPT_FORMAT_SURE #language en-US "Are you sure you want to format this partition to FAT32 and destroy all data on it ? %BY%Nes, %BN%No " +#string STR_GPT_DELETE_WARNING #language en-US "%H%s%N: Deleting of this partition will make data on it unreachable!\r\n" +#string STR_GPT_READ_BOUNDARY #language en-US "%H%s%N: Attempt to read beyond %H%s%N partition boundary (can read upto %llu bytes from the given offset, requested %llu bytes)\r\n" +#string STR_GPT_WRITE_BOUNDARY #language en-US "%H%s%N: Attempt to write beyond %H%s%N partition boundary (can write upto %llu bytes from the given offset, requested %llu bytes)\r\n" +#string STR_GPT_FILE_WRITE_FAIL #language en-US "%H%s%N: Failed to write to the file %s, error %r\r\n" + +#string STR_GPT_WRITE_OK #language en-US "Written %llu bytes at offset 0x%x, partition %s. Elapsed time %llums (%llu KB/s)\r\n" +#string STR_GPT_READ_OK #language en-US "Read %llu bytes from offset 0x%x, partition %s. Elapsed time %llums (%llu KB/s)\r\n" +#string STR_GPT_READFILE_OK #language en-US "Read %llu bytes from offset 0x%x, partition %s into file %s. Elapsed time %llums (%llu KB/s)\r\n" +#string STR_GPT_LIST_DEVS #language en-US " %H%+6s%N %+8s " + +#string STR_GET_HELP_GPT #language en-US "" +".TH gpt 0 "GPT partition manager."\r\n" +".SH NAME\r\n" +"Manages GPT partitions on a block device.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"gpt [read | readfile | write | writefile | list | info | clear |\r\n" +" create | delete | rename | setattrs | sync | fatformat | -typesinfo | -yes] \r\n" +"This is a complex utility. Please see examples for usage info\r\n" +".SH OPTIONS\r\n" +" \r\n" +" Device - Block device to be used for the operation\r\n" +" Length - Number of bytes to transfer (for read/write))\r\n" +" Address - Address in RAM to store/load data\r\n" +" Offset - Offset (in blocks) from beggining of the specifie partition to store/load data\r\n" +" FilePath - Path to file to read data into or write/update data from\r\n" +" -yes - Assume yes for all queries, do not prompt\r\n\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +"Get the list of available partitionable block device(s)\r\n" +" gpt %Hlist%N\r\n" +"Get info on the particular partition with name PartitionName on the block device blk0:\r\n" +" gpt %Hinfo%N blk0: PartitionName\r\n" +"List all available GPT partitions on the block device blk0:\r\n" +" gpt list blk0:\r\n" +"Note: the ordinal number shown by this command can be used as a partition name in any command requiring partition name\r\n" +"Thus gpt info blk0: 1 is valid if there is a partition with ordinal 1 present in the output of gpt list command\r\n" +"Get information on all recognized partition types\r\n" +" gpt %Htypesinfo%N\r\n" +"Clear partitions information and install empty GPT tables for a block device blk0:\r\n" +" gpt %Hclear%N blk0:\r\n" +"Create a GPT partition with name PartitionName and type EFI SYSTEM in the GPT table, using the next available LBA, with size\r\n" +"64MiB, with system attribute, on block device blk0:\r\n" +" gpt %Hcreate%N blk0: PartitionName 0 64 1 -type 0\r\n" +"Same as above, but now the partition type is not known to the gpt utility, so use some GUID known to a 3rd party\r\n" +" gpt create blk0: PartitionName 0 64 1 -type 44581A4A-C834-D1A6-2602-9D522A8F2307\r\n" +"Rename the GPT partition PartitionName on blk0: to NewPartitionName\r\n" +" gpt %Hrename%N blk0: PartitionName NewPartitionName\r\n" +"Have the PartitionDxe driver to re-read GPT tables on a block device blk0:(after they were updated with gpt utility)\r\n" +" gpt %Hsync%N blk0:\r\n" +"Read 4K from block offset 0x0e000 in Partition named PartitionName of the block device at blk0: into RAM at address 0x100000\r\n" +" gpt %Hread%N blk0: 0x100000 PartitionName 0xe000 4096\r\n" +"Write 512 bytes from 0x200000 at RAM into the block device at blk0: partition PartitionName at offset 0x1000\r\n" +" gpt %Hwrite%N blk0: 0x200000 PartitionName 0x1000 512\r\n" +"Read 0x3000 bytes from 0x0 offset of Partition PartitionName at the block device blk0: into file fs2:file.bin\r\n" +" gpt %Hreadfile%N blk0: fs2:file.bin PartitionName 0x0 0x3000\r\n" +"Write contents of file fs2:file.bin into partition named PartitionName with offset (in lba) 0x10 on a block device blk0:\r\n" +" gpt %Hwritefile%N blk0: fs2:file.bin PartitionName 0x10\r\n" +"FAT Format the partition PartitionName on block device blk0:\r\n" +" gpt %Hfatformat%N blk0: PartitionName\r\n" +"FAT Format the whole device blk0:\r\n" +" gpt fatformat blk0:\r\n" + +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" Specific Shell error Error while processing command\r\n" diff --git a/ShellPkg/ShellPkg.dec b/ShellPkg/ShellPkg.dec index 39f8012b98c1..5374a2a62d5f 100644 --- a/ShellPkg/ShellPkg.dec +++ b/ShellPkg/ShellPkg.dec @@ -56,6 +56,7 @@ [Guids] gShellNetwork2HiiGuid = {0x174b2b5, 0xf505, 0x4b12, {0xaa, 0x60, 0x59, 0xdf, 0xf8, 0xd6, 0xea, 0x37}} gShellTftpHiiGuid = {0x738a9314, 0x82c1, 0x4592, {0x8f, 0xf7, 0xc1, 0xbd, 0xf1, 0xb2, 0x0e, 0xd4}} gShellBcfgHiiGuid = {0x5f5f605d, 0x1583, 0x4a2d, {0xa6, 0xb2, 0xeb, 0x12, 0xda, 0xb4, 0xa2, 0xb6}} + gShellGptHiiGuid = {0x5a1ed739, 0x5ef1, 0x429a, {0x8d, 0xf8, 0x28, 0xc9, 0x92, 0x64, 0xd7, 0xf8}} [Protocols] gEfiShellProtocolGuid = {0x6302d008, 0x7f9b, 0x4f30, {0x87, 0xac, 0x60, 0xc9, 0xfe, 0xf5, 0xda, 0x4e}} diff --git a/ShellPkg/ShellPkg.dsc b/ShellPkg/ShellPkg.dsc index 809bd4220af2..984c1d0ad48b 100644 --- a/ShellPkg/ShellPkg.dsc +++ b/ShellPkg/ShellPkg.dsc @@ -89,6 +89,7 @@ [Components] ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.inf ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.inf ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.inf + ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLib.inf ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.inf @@ -119,6 +120,9 @@ [Components] !ifdef $(INCLUDE_TFTP_COMMAND) NULL|ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.inf !endif #$(INCLUDE_TFTP_COMMAND) +!ifdef $(INCLUDE_GPT_COMMAND) + NULL|ShellPkg/Library/UefiShellGptCommandLib/UefiShellGptCommandLib.inf +!endif #$(INCLUDE_GPT_COMMAND) !endif #$(NO_SHELL_PROFILES) } -- 1.9.1