]> git.proxmox.com Git - mirror_edk2.git/commitdiff
FatPkg: Add GPT check in FatPei to support Capsule-on-Disk feature.
authorChen A Chen <chen.a.chen@intel.com>
Wed, 16 Jan 2019 06:59:57 +0000 (14:59 +0800)
committerHao Wu <hao.a.wu@intel.com>
Thu, 31 Jan 2019 03:10:55 +0000 (11:10 +0800)
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=1470
This feature is used for finding GPT partition.
Follow the following step to check.
1) Check Protective MBR.
2) Check GPT primary/backup header.
3) Check GPT primary/backup entry array.

Cc: Ruiyu Ni <ray.ni@intel.com>
Cc: Zhang Chao B <chao.b.zhang@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Chen A Chen <chen.a.chen@intel.com>
Reviewed-by: Hao Wu <hao.a.wu@intel.com>
FatPkg/FatPei/FatLitePeim.h
FatPkg/FatPei/FatPei.inf
FatPkg/FatPei/Gpt.c [new file with mode: 0644]
FatPkg/FatPei/Part.c

index fbf887da5fa353c105ad84fff4df96845caf0a80..82ab045f2a8f11df8cb14ae82b635c70f379c1b1 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Data structures for FAT recovery PEIM\r
 \r
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>\r
 \r
 This program and the accompanying materials are licensed and made available\r
 under the terms and conditions of the BSD License which accompanies this\r
@@ -27,6 +27,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <Library/BaseLib.h>\r
 #include <Library/PeimEntryPoint.h>\r
 #include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
 #include <Library/PcdLib.h>\r
 #include <Library/PeiServicesTablePointerLib.h>\r
 #include <Library/PeiServicesLib.h>\r
index 57312a90471d310737780ec6bdc9cf3a87b8b071..050bc4e157c72eb7a83c3fa3f8faf8d7dc763653 100644 (file)
@@ -31,6 +31,7 @@
 \r
 [Sources]\r
   Mbr.c\r
+  Gpt.c\r
   Eltorito.c\r
   Part.c\r
   FatLiteApi.c\r
@@ -49,6 +50,7 @@
 [LibraryClasses]\r
   PcdLib\r
   BaseMemoryLib\r
+  MemoryAllocationLib\r
   PeimEntryPoint\r
   BaseLib\r
   DebugLib\r
@@ -61,6 +63,7 @@
   gRecoveryOnFatIdeDiskGuid                   ## SOMETIMES_CONSUMES   ## UNDEFINED\r
   gRecoveryOnFatFloppyDiskGuid                ## SOMETIMES_CONSUMES   ## UNDEFINED\r
   gRecoveryOnFatNvmeDiskGuid                  ## SOMETIMES_CONSUMES   ## UNDEFINED\r
+  gEfiPartTypeUnusedGuid                      ## SOMETIMES_CONSUMES   ## UNDEFINED\r
 \r
 \r
 [Ppis]\r
diff --git a/FatPkg/FatPei/Gpt.c b/FatPkg/FatPei/Gpt.c
new file mode 100644 (file)
index 0000000..c3afb66
--- /dev/null
@@ -0,0 +1,548 @@
+/** @file\r
+  Routines supporting partition discovery and\r
+  logical device reading\r
+\r
+Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <IndustryStandard/Mbr.h>\r
+#include <Uefi/UefiGpt.h>\r
+#include <Library/BaseLib.h>\r
+#include "FatLitePeim.h"\r
+\r
+//\r
+// Assumption: 'a' and 'blocksize' are all UINT32 or UINT64.\r
+// If 'a' and 'blocksize' are not the same type, should use DivU64xU32 to calculate.\r
+//\r
+#define EFI_SIZE_TO_BLOCKS(a, blocksize)  (((a) / (blocksize)) + (((a) % (blocksize)) ? 1 : 0))\r
+\r
+//\r
+// GPT Partition Entry Status\r
+//\r
+typedef struct {\r
+  BOOLEAN OutOfRange;\r
+  BOOLEAN Overlap;\r
+  BOOLEAN OsSpecific;\r
+} EFI_PARTITION_ENTRY_STATUS;\r
+\r
+/**\r
+  Check if the CRC field in the Partition table header is valid.\r
+\r
+  @param[in]  PartHeader  Partition table header structure\r
+\r
+  @retval TRUE      the CRC is valid\r
+  @retval FALSE     the CRC is invalid\r
+\r
+**/\r
+BOOLEAN\r
+PartitionCheckGptHeaderCRC (\r
+  IN  EFI_PARTITION_TABLE_HEADER  *PartHeader\r
+  )\r
+{\r
+  UINT32      GptHdrCrc;\r
+  UINT32      Crc;\r
+\r
+  GptHdrCrc = PartHeader->Header.CRC32;\r
+\r
+  //\r
+  // Set CRC field to zero when doing calcuation\r
+  //\r
+  PartHeader->Header.CRC32 = 0;\r
+\r
+  Crc = CalculateCrc32 (PartHeader, PartHeader->Header.HeaderSize);\r
+\r
+  //\r
+  // Restore Header CRC\r
+  //\r
+  PartHeader->Header.CRC32 = GptHdrCrc;\r
+\r
+  return (GptHdrCrc == Crc);\r
+}\r
+\r
+\r
+/**\r
+  Check if the CRC field in the Partition table header is valid\r
+  for Partition entry array.\r
+\r
+  @param[in]  PartHeader  Partition table header structure\r
+  @param[in]  PartEntry   The partition entry array\r
+\r
+  @retval TRUE      the CRC is valid\r
+  @retval FALSE     the CRC is invalid\r
+\r
+**/\r
+BOOLEAN\r
+PartitionCheckGptEntryArrayCRC (\r
+  IN  EFI_PARTITION_TABLE_HEADER *PartHeader,\r
+  IN  EFI_PARTITION_ENTRY        *PartEntry\r
+  )\r
+{\r
+  UINT32      Crc;\r
+  UINTN       Size;\r
+\r
+  Size = (UINTN)MultU64x32(PartHeader->NumberOfPartitionEntries, PartHeader->SizeOfPartitionEntry);\r
+  Crc  = CalculateCrc32 (PartEntry, Size);\r
+\r
+  return (BOOLEAN) (PartHeader->PartitionEntryArrayCRC32 == Crc);\r
+}\r
+\r
+/**\r
+  The function is used for valid GPT table. Both for Primary and Backup GPT header.\r
+\r
+  @param[in]  PrivateData       The global memory map\r
+  @param[in]  ParentBlockDevNo  The parent block device\r
+  @param[in]  IsPrimaryHeader   Indicate to which header will be checked.\r
+  @param[in]  PartHdr           Stores the partition table that is read\r
+\r
+  @retval TRUE      The partition table is valid\r
+  @retval FALSE     The partition table is not valid\r
+\r
+**/\r
+BOOLEAN\r
+PartitionCheckGptHeader (\r
+  IN  PEI_FAT_PRIVATE_DATA        *PrivateData,\r
+  IN  UINTN                       ParentBlockDevNo,\r
+  IN  BOOLEAN                     IsPrimaryHeader,\r
+  IN  EFI_PARTITION_TABLE_HEADER  *PartHdr\r
+  )\r
+{\r
+  PEI_FAT_BLOCK_DEVICE            *ParentBlockDev;\r
+  EFI_PEI_LBA                     Lba;\r
+  EFI_PEI_LBA                     AlternateLba;\r
+  EFI_PEI_LBA                     EntryArrayLastLba;\r
+\r
+  UINT64                          PartitionEntryArraySize;\r
+  UINT64                          PartitionEntryBlockNumb;\r
+  UINT32                          EntryArraySizeRemainder;\r
+\r
+  ParentBlockDev = &(PrivateData->BlockDevice[ParentBlockDevNo]);\r
+\r
+  if (IsPrimaryHeader) {\r
+    Lba          = PRIMARY_PART_HEADER_LBA;\r
+    AlternateLba = ParentBlockDev->LastBlock;\r
+  } else {\r
+    Lba          = ParentBlockDev->LastBlock;\r
+    AlternateLba = PRIMARY_PART_HEADER_LBA;\r
+  }\r
+\r
+  if ( (PartHdr->Header.Signature != EFI_PTAB_HEADER_ID) ||\r
+       (PartHdr->Header.Revision != 0x00010000) ||\r
+       (PartHdr->Header.HeaderSize < 92) ||\r
+       (PartHdr->Header.HeaderSize > ParentBlockDev->BlockSize) ||\r
+       (!PartitionCheckGptHeaderCRC (PartHdr)) ||\r
+       (PartHdr->Header.Reserved != 0)\r
+     ) {\r
+    DEBUG ((DEBUG_ERROR, "Invalid efi partition table header\n"));\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // |    Block0    |    Block1    |Block2 ~ FirstUsableLBA - 1|FirstUsableLBA, ... ,LastUsableLBA|LastUsableLBA+1 ~ LastBlock-1|  LastBlock  |\r
+  // |Protective MBR|Primary Header|Entry Array(At Least 16384)|             Partition            | Entry Array(At Least 16384) |BackUp Header|\r
+  //\r
+  // 1. Protective MBR is fixed at Block 0.\r
+  // 2. Primary Header is fixed at Block 1.\r
+  // 3. Backup Header is fixed at LastBlock.\r
+  // 4. Must be remain 128*128 bytes for primary entry array.\r
+  // 5. Must be remain 128*128 bytes for backup entry array.\r
+  // 6. SizeOfPartitionEntry must be equals to 128 * 2^n.\r
+  //\r
+  if ( (PartHdr->MyLBA != Lba) ||\r
+       (PartHdr->AlternateLBA != AlternateLba) ||\r
+       (PartHdr->FirstUsableLBA < 2 + EFI_SIZE_TO_BLOCKS (EFI_GPT_PART_ENTRY_MIN_SIZE, ParentBlockDev->BlockSize)) ||\r
+       (PartHdr->LastUsableLBA  > ParentBlockDev->LastBlock - 1 - EFI_SIZE_TO_BLOCKS (EFI_GPT_PART_ENTRY_MIN_SIZE, ParentBlockDev->BlockSize)) ||\r
+       (PartHdr->FirstUsableLBA > PartHdr->LastUsableLBA) ||\r
+       (PartHdr->PartitionEntryLBA < 2) ||\r
+       (PartHdr->PartitionEntryLBA > ParentBlockDev->LastBlock - 1) ||\r
+       (PartHdr->PartitionEntryLBA >= PartHdr->FirstUsableLBA && PartHdr->PartitionEntryLBA <= PartHdr->LastUsableLBA) ||\r
+       (PartHdr->SizeOfPartitionEntry%128 != 0) ||\r
+       (PartHdr->SizeOfPartitionEntry != sizeof (EFI_PARTITION_ENTRY))\r
+     ) {\r
+    DEBUG ((DEBUG_ERROR, "Invalid efi partition table header\n"));\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Ensure the NumberOfPartitionEntries * SizeOfPartitionEntry doesn't overflow.\r
+  //\r
+  if (PartHdr->NumberOfPartitionEntries > DivU64x32 (MAX_UINTN, PartHdr->SizeOfPartitionEntry)) {\r
+    DEBUG ((DEBUG_ERROR, "Memory overflow in GPT Entry Array\n"));\r
+    return FALSE;\r
+  }\r
+\r
+  PartitionEntryArraySize = MultU64x32 (PartHdr->NumberOfPartitionEntries, PartHdr->SizeOfPartitionEntry);\r
+  EntryArraySizeRemainder = 0;\r
+  PartitionEntryBlockNumb = DivU64x32Remainder (PartitionEntryArraySize, ParentBlockDev->BlockSize, &EntryArraySizeRemainder);\r
+  if (EntryArraySizeRemainder != 0) {\r
+    PartitionEntryBlockNumb++;\r
+  }\r
+\r
+  if (IsPrimaryHeader) {\r
+    EntryArrayLastLba = PartHdr->FirstUsableLBA;\r
+  } else {\r
+    EntryArrayLastLba = ParentBlockDev->LastBlock;\r
+  }\r
+\r
+  //\r
+  // Make sure partition entry array not overlaps with partition area or the LastBlock.\r
+  //\r
+  if (PartHdr->PartitionEntryLBA + PartitionEntryBlockNumb > EntryArrayLastLba) {\r
+    DEBUG ((DEBUG_ERROR, "GPT Partition Entry Array Error!\n"));\r
+    DEBUG ((DEBUG_ERROR, "PartitionEntryArraySize = %lu.\n", PartitionEntryArraySize));\r
+    DEBUG ((DEBUG_ERROR, "PartitionEntryLBA = %lu.\n", PartHdr->PartitionEntryLBA));\r
+    DEBUG ((DEBUG_ERROR, "PartitionEntryBlockNumb = %lu.\n", PartitionEntryBlockNumb));\r
+    DEBUG ((DEBUG_ERROR, "EntryArrayLastLba = %lu.\n", EntryArrayLastLba));\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  This function is used to verify each partition in block device.\r
+\r
+  @param[in]  PrivateData       The global memory map\r
+  @param[in]  ParentBlockDevNo  The parent block device\r
+  @param[in]  PartHdr           Stores the partition table that is read\r
+\r
+  @retval TRUE      The partition is valid\r
+  @retval FALSE     The partition is not valid\r
+\r
+**/\r
+BOOLEAN\r
+PartitionCheckGptEntryArray (\r
+  IN  PEI_FAT_PRIVATE_DATA        *PrivateData,\r
+  IN  UINTN                       ParentBlockDevNo,\r
+  IN  EFI_PARTITION_TABLE_HEADER  *PartHdr\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  PEI_FAT_BLOCK_DEVICE            *ParentBlockDev;\r
+  PEI_FAT_BLOCK_DEVICE            *BlockDevPtr;\r
+\r
+  UINT64                          PartitionEntryArraySize;\r
+  UINT64                          PartitionEntryBlockNumb;\r
+  UINT32                          EntryArraySizeRemainder;\r
+\r
+  EFI_PARTITION_ENTRY             *PartitionEntryBuffer;\r
+  EFI_PARTITION_ENTRY_STATUS      *PartitionEntryStatus;\r
+\r
+  BOOLEAN                         Found;\r
+  EFI_LBA                         StartingLBA;\r
+  EFI_LBA                         EndingLBA;\r
+  UINTN                           Index;\r
+  UINTN                           Index1;\r
+  UINTN                           Index2;\r
+  EFI_PARTITION_ENTRY             *Entry;\r
+\r
+  ParentBlockDev  = &(PrivateData->BlockDevice[ParentBlockDevNo]);\r
+  Found           = FALSE;\r
+\r
+  PartitionEntryArraySize = MultU64x32 (PartHdr->NumberOfPartitionEntries, PartHdr->SizeOfPartitionEntry);\r
+  EntryArraySizeRemainder = 0;\r
+  PartitionEntryBlockNumb = DivU64x32Remainder (PartitionEntryArraySize, ParentBlockDev->BlockSize, &EntryArraySizeRemainder);\r
+  if (EntryArraySizeRemainder != 0) {\r
+    PartitionEntryBlockNumb++;\r
+  }\r
+  PartitionEntryArraySize = MultU64x32 (PartitionEntryBlockNumb, ParentBlockDev->BlockSize);\r
+\r
+  PartitionEntryBuffer = (EFI_PARTITION_ENTRY *) AllocatePages (EFI_SIZE_TO_PAGES ((UINTN)PartitionEntryArraySize));\r
+  if (PartitionEntryBuffer == NULL) {\r
+    DEBUG ((DEBUG_ERROR, "Allocate memory error!\n"));\r
+    goto EXIT;\r
+  }\r
+\r
+  PartitionEntryStatus = (EFI_PARTITION_ENTRY_STATUS *) AllocatePages (EFI_SIZE_TO_PAGES (PartHdr->NumberOfPartitionEntries * sizeof (EFI_PARTITION_ENTRY_STATUS)));\r
+  if (PartitionEntryStatus == NULL) {\r
+    DEBUG ((DEBUG_ERROR, "Allocate memory error!\n"));\r
+    goto EXIT;\r
+  }\r
+  ZeroMem (PartitionEntryStatus, PartHdr->NumberOfPartitionEntries * sizeof (EFI_PARTITION_ENTRY_STATUS));\r
+\r
+  Status = FatReadBlock (\r
+             PrivateData,\r
+             ParentBlockDevNo,\r
+             PartHdr->PartitionEntryLBA,\r
+             (UINTN)PartitionEntryArraySize,\r
+             PartitionEntryBuffer\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "Read partition entry array error!\n"));\r
+    goto EXIT;\r
+  }\r
+\r
+  if (!PartitionCheckGptEntryArrayCRC (PartHdr, PartitionEntryBuffer)) {\r
+    DEBUG ((DEBUG_ERROR, "Partition entries CRC check fail\n"));\r
+    goto EXIT;\r
+  }\r
+\r
+  for (Index1 = 0; Index1 < PartHdr->NumberOfPartitionEntries; Index1++) {\r
+    Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartitionEntryBuffer + Index1 * PartHdr->SizeOfPartitionEntry);\r
+    if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {\r
+      continue;\r
+    }\r
+\r
+    StartingLBA = Entry->StartingLBA;\r
+    EndingLBA   = Entry->EndingLBA;\r
+    if (StartingLBA > EndingLBA ||\r
+        StartingLBA < PartHdr->FirstUsableLBA ||\r
+        StartingLBA > PartHdr->LastUsableLBA ||\r
+        EndingLBA < PartHdr->FirstUsableLBA ||\r
+        EndingLBA > PartHdr->LastUsableLBA\r
+        ) {\r
+      PartitionEntryStatus[Index1].OutOfRange = TRUE;\r
+      continue;\r
+    }\r
+\r
+    if ((Entry->Attributes & BIT1) != 0) {\r
+      //\r
+      // If Bit 1 is set, this indicate that this is an OS specific GUID partition.\r
+      //\r
+      PartitionEntryStatus[Index1].OsSpecific = TRUE;\r
+    }\r
+\r
+    for (Index2 = Index1 + 1; Index2 < PartHdr->NumberOfPartitionEntries; Index2++) {\r
+      Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartitionEntryBuffer + Index2 * PartHdr->SizeOfPartitionEntry);\r
+      if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {\r
+        continue;\r
+      }\r
+\r
+      if (Entry->EndingLBA >= StartingLBA && Entry->StartingLBA <= EndingLBA) {\r
+        //\r
+        // This region overlaps with the Index1'th region\r
+        //\r
+        PartitionEntryStatus[Index1].Overlap  = TRUE;\r
+        PartitionEntryStatus[Index2].Overlap  = TRUE;\r
+        continue;\r
+      }\r
+    }\r
+  }\r
+\r
+  for (Index = 0; Index < PartHdr->NumberOfPartitionEntries; Index++) {\r
+    if (CompareGuid (&PartitionEntryBuffer[Index].PartitionTypeGUID, &gEfiPartTypeUnusedGuid)||\r
+        PartitionEntryStatus[Index].OutOfRange ||\r
+        PartitionEntryStatus[Index].Overlap ||\r
+        PartitionEntryStatus[Index].OsSpecific) {\r
+      //\r
+      // Don't use null EFI Partition Entries, Invalid Partition Entries or OS specific\r
+      // partition Entries\r
+      //\r
+      continue;\r
+    }\r
+\r
+    if (PrivateData->BlockDeviceCount >= PEI_FAT_MAX_BLOCK_DEVICE) {\r
+      break;\r
+    }\r
+\r
+    Found                         = TRUE;\r
+    BlockDevPtr                   = &(PrivateData->BlockDevice[PrivateData->BlockDeviceCount]);\r
+\r
+    BlockDevPtr->BlockSize        = ParentBlockDev->BlockSize;\r
+    BlockDevPtr->LastBlock        = PartitionEntryBuffer[Index].EndingLBA;\r
+    BlockDevPtr->IoAlign          = ParentBlockDev->IoAlign;\r
+    BlockDevPtr->Logical          = TRUE;\r
+    BlockDevPtr->PartitionChecked = FALSE;\r
+    BlockDevPtr->StartingPos      = MultU64x32 (\r
+                                      PartitionEntryBuffer[Index].StartingLBA,\r
+                                      ParentBlockDev->BlockSize\r
+                                      );\r
+    BlockDevPtr->ParentDevNo      = ParentBlockDevNo;\r
+\r
+    PrivateData->BlockDeviceCount++;\r
+\r
+    DEBUG ((DEBUG_INFO, "Find GPT Partition [0x%lx",  PartitionEntryBuffer[Index].StartingLBA, BlockDevPtr->LastBlock));\r
+    DEBUG ((DEBUG_INFO, ", 0x%lx]\n", BlockDevPtr->LastBlock));\r
+    DEBUG ((DEBUG_INFO, "         BlockSize %x\n",  BlockDevPtr->BlockSize));\r
+  }\r
+\r
+EXIT:\r
+  if (PartitionEntryBuffer != NULL) {\r
+    FreePages (PartitionEntryBuffer, EFI_SIZE_TO_PAGES ((UINTN)PartitionEntryArraySize));\r
+  }\r
+\r
+  if (PartitionEntryStatus != NULL) {\r
+    FreePages (PartitionEntryStatus, EFI_SIZE_TO_PAGES (PartHdr->NumberOfPartitionEntries * sizeof (EFI_PARTITION_ENTRY_STATUS)));\r
+  }\r
+\r
+  return Found;\r
+}\r
+\r
+/**\r
+  The function is used to check GPT structure, include GPT header and GPT entry array.\r
+\r
+  1. Check GPT header.\r
+  2. Check partition entry array.\r
+  3. Check each partitions.\r
+\r
+  @param[in]  PrivateData       The global memory map\r
+  @param[in]  ParentBlockDevNo  The parent block device\r
+  @param[in]  IsPrimary         Indicate primary or backup to be check\r
+\r
+  @retval TRUE              Primary or backup GPT structure is valid.\r
+  @retval FALSE             Both primary and backup are invalid.\r
+\r
+**/\r
+BOOLEAN\r
+PartitionCheckGptStructure (\r
+  IN  PEI_FAT_PRIVATE_DATA      *PrivateData,\r
+  IN  UINTN                     ParentBlockDevNo,\r
+  IN  BOOLEAN                   IsPrimary\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  PEI_FAT_BLOCK_DEVICE          *ParentBlockDev;\r
+  EFI_PARTITION_TABLE_HEADER    *PartHdr;\r
+  EFI_PEI_LBA                   GptHeaderLBA;\r
+\r
+  ParentBlockDev  = &(PrivateData->BlockDevice[ParentBlockDevNo]);\r
+  PartHdr         = (EFI_PARTITION_TABLE_HEADER *) PrivateData->BlockData;\r
+\r
+  if (IsPrimary) {\r
+    GptHeaderLBA = PRIMARY_PART_HEADER_LBA;\r
+  } else {\r
+    GptHeaderLBA = ParentBlockDev->LastBlock;\r
+  }\r
+\r
+  Status = FatReadBlock (\r
+             PrivateData,\r
+             ParentBlockDevNo,\r
+             GptHeaderLBA,\r
+             ParentBlockDev->BlockSize,\r
+             PartHdr\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return FALSE;\r
+  }\r
+\r
+  if (!PartitionCheckGptHeader (PrivateData, ParentBlockDevNo, IsPrimary, PartHdr)) {\r
+    return FALSE;\r
+  }\r
+\r
+  if (!PartitionCheckGptEntryArray (PrivateData, ParentBlockDevNo, PartHdr)) {\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  This function is used to check protective MBR structure before checking GPT.\r
+\r
+  @param[in]  PrivateData       The global memory map\r
+  @param[in]  ParentBlockDevNo  The parent block device\r
+\r
+  @retval TRUE              Valid protective MBR\r
+  @retval FALSE             Invalid MBR\r
+**/\r
+BOOLEAN\r
+PartitionCheckProtectiveMbr (\r
+  IN  PEI_FAT_PRIVATE_DATA    *PrivateData,\r
+  IN  UINTN                   ParentBlockDevNo\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  MASTER_BOOT_RECORD          *ProtectiveMbr;\r
+  MBR_PARTITION_RECORD        *MbrPartition;\r
+  PEI_FAT_BLOCK_DEVICE        *ParentBlockDev;\r
+  UINTN                       Index;\r
+\r
+  ProtectiveMbr   = (MASTER_BOOT_RECORD *) PrivateData->BlockData;\r
+  ParentBlockDev  = &(PrivateData->BlockDevice[ParentBlockDevNo]);\r
+\r
+  //\r
+  // Read Protective MBR\r
+  //\r
+  Status = FatReadBlock (\r
+             PrivateData,\r
+             ParentBlockDevNo,\r
+             0,\r
+             ParentBlockDev->BlockSize,\r
+             ProtectiveMbr\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "GPT Error When Read Protective Mbr From Partition!\n"));\r
+    return FALSE;\r
+  }\r
+\r
+  if (ProtectiveMbr->Signature != MBR_SIGNATURE) {\r
+    DEBUG ((DEBUG_ERROR, "Protective Mbr Signature is invalid!\n"));\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // The partition define in UEFI Spec Table 17.\r
+  // Boot Code, Unique MBR Disk Signature, Unknown.\r
+  // These parts will not be used by UEFI, so we skip to check them.\r
+  //\r
+  for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {\r
+    MbrPartition = (MBR_PARTITION_RECORD *)&ProtectiveMbr->Partition[Index];\r
+    if (MbrPartition->BootIndicator   == 0x00 &&\r
+        MbrPartition->StartSector     == 0x02 &&\r
+        MbrPartition->OSIndicator     == PMBR_GPT_PARTITION &&\r
+        UNPACK_UINT32 (MbrPartition->StartingLBA) == 1\r
+       ) {\r
+      return TRUE;\r
+    }\r
+  }\r
+\r
+  DEBUG ((DEBUG_ERROR, "Protective Mbr, All Partition Entry Are Empty!\n"));\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  This function is used for finding GPT partition on block device.\r
+  As follow UEFI spec we should check protective MBR first and then\r
+  try to check both primary/backup GPT structures.\r
+\r
+  @param[in]  PrivateData       The global memory map\r
+  @param[in]  ParentBlockDevNo  The parent block device\r
+\r
+  @retval TRUE              New partitions are detected and logical block devices\r
+                            are added to block device array\r
+  @retval FALSE             No new partitions are added\r
+\r
+**/\r
+BOOLEAN\r
+FatFindGptPartitions (\r
+  IN  PEI_FAT_PRIVATE_DATA *PrivateData,\r
+  IN  UINTN                ParentBlockDevNo\r
+  )\r
+{\r
+  BOOLEAN                      Found;\r
+  PEI_FAT_BLOCK_DEVICE         *ParentBlockDev;\r
+\r
+  if (ParentBlockDevNo > PEI_FAT_MAX_BLOCK_DEVICE - 1) {\r
+    return FALSE;\r
+  }\r
+\r
+  ParentBlockDev  = &(PrivateData->BlockDevice[ParentBlockDevNo]);\r
+  if (ParentBlockDev->BlockSize > PEI_FAT_MAX_BLOCK_SIZE) {\r
+    DEBUG ((DEBUG_ERROR, "Device BlockSize %x exceed FAT_MAX_BLOCK_SIZE\n", ParentBlockDev->BlockSize));\r
+    return FALSE;\r
+  }\r
+\r
+  if (!PartitionCheckProtectiveMbr (PrivateData, ParentBlockDevNo)) {\r
+    return FALSE;\r
+  }\r
+\r
+  Found = PartitionCheckGptStructure (PrivateData, ParentBlockDevNo, TRUE);\r
+  if (!Found) {\r
+    DEBUG ((DEBUG_ERROR, "Primary GPT Header Error, Try to Check Backup GPT Header!\n"));\r
+    Found = PartitionCheckGptStructure (PrivateData, ParentBlockDevNo, FALSE);\r
+  }\r
+\r
+  if (Found) {\r
+    ParentBlockDev->PartitionChecked = TRUE;\r
+  }\r
+\r
+  return Found;\r
+}\r
index 8a54e56f5ae6c452003fea6e6de9f0cc741a44a8..9b49eccf4e3b09aedbc202339b4f5d4f3a1325a2 100644 (file)
@@ -52,6 +52,25 @@ FatFindMbrPartitions (
   IN  UINTN                ParentBlockDevNo\r
   );\r
 \r
+/**\r
+  This function is used for finding GPT partition on block device.\r
+  As follow UEFI spec we should check protective MBR first and then\r
+  try to check both primary/backup GPT structures.\r
+\r
+  @param[in]  PrivateData       The global memory map\r
+  @param[in]  ParentBlockDevNo  The parent block device\r
+\r
+  @retval TRUE              New partitions are detected and logical block devices\r
+                            are added to block device array\r
+  @retval FALSE             No new partitions are added\r
+\r
+**/\r
+BOOLEAN\r
+FatFindGptPartitions (\r
+  IN  PEI_FAT_PRIVATE_DATA *PrivateData,\r
+  IN  UINTN                ParentBlockDevNo\r
+  );\r
+\r
 /**\r
   This function finds partitions (logical devices) in physical block devices.\r
 \r
@@ -71,12 +90,21 @@ FatFindPartitions (
 \r
     for (Index = 0; Index < PrivateData->BlockDeviceCount; Index++) {\r
       if (!PrivateData->BlockDevice[Index].PartitionChecked) {\r
-        Found = FatFindMbrPartitions (PrivateData, Index);\r
-        if (!Found) {\r
-          Found = FatFindEltoritoPartitions (PrivateData, Index);\r
+        if (FatFindGptPartitions (PrivateData, Index)) {\r
+          Found = TRUE;\r
+          continue;\r
+        }\r
+\r
+        if (FatFindMbrPartitions (PrivateData, Index)) {\r
+          Found = TRUE;\r
+          continue;\r
+        }\r
+\r
+        if (FatFindEltoritoPartitions (PrivateData, Index)) {\r
+          Found = TRUE;\r
+          continue;\r
         }\r
       }\r
     }\r
   } while (Found && PrivateData->BlockDeviceCount <= PEI_FAT_MAX_BLOCK_DEVICE);\r
 }\r
-\r