]> 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
 /** @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
 \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/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
 #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
 \r
 [Sources]\r
   Mbr.c\r
+  Gpt.c\r
   Eltorito.c\r
   Part.c\r
   FatLiteApi.c\r
   Eltorito.c\r
   Part.c\r
   FatLiteApi.c\r
@@ -49,6 +50,7 @@
 [LibraryClasses]\r
   PcdLib\r
   BaseMemoryLib\r
 [LibraryClasses]\r
   PcdLib\r
   BaseMemoryLib\r
+  MemoryAllocationLib\r
   PeimEntryPoint\r
   BaseLib\r
   DebugLib\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
   gRecoveryOnFatIdeDiskGuid                   ## SOMETIMES_CONSUMES   ## UNDEFINED\r
   gRecoveryOnFatFloppyDiskGuid                ## SOMETIMES_CONSUMES   ## UNDEFINED\r
   gRecoveryOnFatNvmeDiskGuid                  ## SOMETIMES_CONSUMES   ## UNDEFINED\r
+  gEfiPartTypeUnusedGuid                      ## SOMETIMES_CONSUMES   ## UNDEFINED\r
 \r
 \r
 [Ppis]\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
   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
 /**\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
 \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
       }\r
     }\r
   } while (Found && PrivateData->BlockDeviceCount <= PEI_FAT_MAX_BLOCK_DEVICE);\r
 }\r
-\r