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 <ruiyu...@intel.com>
Cc: Zhang Chao B <chao.b.zh...@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Chen A Chen <chen.a.c...@intel.com>
---
 FatPkg/FatPei/FatLitePeim.h |   3 +-
 FatPkg/FatPei/FatPei.inf    |   3 +
 FatPkg/FatPei/Gpt.c         | 552 ++++++++++++++++++++++++++++++++++++++++++++
 FatPkg/FatPei/Part.c        |  16 +-
 4 files changed, 570 insertions(+), 4 deletions(-)
 create mode 100644 FatPkg/FatPei/Gpt.c

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

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to