> -----Original Message-----
> From: edk2-devel [mailto:edk2-devel-boun...@lists.01.org] On Behalf Of Chen
> A Chen
> Sent: Tuesday, January 29, 2019 1:28 PM
> To: edk2-devel@lists.01.org
> Cc: Ni, Ray; Zhang, Chao B
> Subject: [edk2] [PATCH v3 3/3] FatPkg: Add GPT check in FatPei to support
> Capsule-on-Disk feature.
> 
> 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>
> Reviewed-by: Hao Wu <hao.a...@intel.com>
> ---
>  FatPkg/FatPei/FatLitePeim.h |   3 +-
>  FatPkg/FatPei/FatPei.inf    |   3 +
>  FatPkg/FatPei/Gpt.c         | 548
> ++++++++++++++++++++++++++++++++++++++++++++
>  FatPkg/FatPei/Part.c        |  36 ++-
>  4 files changed, 585 insertions(+), 5 deletions(-)
>  create mode 100644 FatPkg/FatPei/Gpt.c
> 
> diff --git a/FatPkg/FatPei/FatLitePeim.h b/FatPkg/FatPei/FatLitePeim.h
> index fbf887da5f..82ab045f2a 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 57312a9047..050bc4e157 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..c3afb668d7
> --- /dev/null
> +++ b/FatPkg/FatPei/Gpt.c
> @@ -0,0 +1,548 @@
> +/** @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]  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]  PartHeader  Partition table header structure
> +  @param[in]  PartEntry   The partition entry array
> +
> +  @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 ((DEBUG_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[in]  PrivateData       The global memory map
> +  @param[in]  ParentBlockDevNo  The parent block device
> +  @param[in]  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[in]  PrivateData       The global memory map
> +  @param[in]  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[in]  PrivateData       The global memory map
> +  @param[in]  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 8a54e56f5a..9b49eccf4e 100644
> --- a/FatPkg/FatPei/Part.c
> +++ b/FatPkg/FatPei/Part.c
> @@ -52,6 +52,25 @@ FatFindMbrPartitions (
>    IN  UINTN                ParentBlockDevNo
>    );
> 
> +/**
> +  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[in]  PrivateData       The global memory map
> +  @param[in]  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
> +  );
> +
>  /**
>    This function finds partitions (logical devices) in physical block devices.
> 
> @@ -71,12 +90,21 @@ 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;
>          }

Reviewed-by: Hao Wu <hao.a...@intel.com>

Best Regards,
Hao Wu

>        }
>      }
>    } while (Found && PrivateData->BlockDeviceCount <=
> PEI_FAT_MAX_BLOCK_DEVICE);
>  }
> -
> --
> 2.16.2.windows.1
> 
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to