public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH 3/3] FatPkg: Add GPT check in FatPei to support Capsule-on-Disk feature.
@ 2019-01-17  2:03 Chen A Chen
       [not found] ` <734D49CCEBEEF84792F5B80ED585239D5BFC0EC2@SHSMSX103.ccr.corp.intel.com>
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Chen A Chen @ 2019-01-17  2:03 UTC (permalink / raw)
  To: edk2-devel; +Cc: Chen A Chen, Ruiyu Ni, Zhang Chao B

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.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>
---
 FatPkg/FatPei/FatLitePeim.h |   1 +
 FatPkg/FatPei/FatPei.inf    |   3 +
 FatPkg/FatPei/Gpt.c         | 546 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 550 insertions(+)
 create mode 100644 FatPkg/FatPei/Gpt.c

diff --git a/FatPkg/FatPei/FatLitePeim.h b/FatPkg/FatPei/FatLitePeim.h
index fbf887da5f..afb429c56e 100644
--- a/FatPkg/FatPei/FatLitePeim.h
+++ b/FatPkg/FatPei/FatLitePeim.h
@@ -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 829e87fe92..dd0869f7cd 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..d1f4c1c8b5
--- /dev/null
+++ b/FatPkg/FatPei/Gpt.c
@@ -0,0 +1,546 @@
+/** @file
+  Routines supporting partition discovery and
+  logical device reading
+
+Copyright (c) 2006 - 2018, 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 (GPT_PART_ENTRY_MIN_SIZE, ParentBlockDev->BlockSize)) ||
+       (PartHdr->LastUsableLBA  > ParentBlockDev->LastBlock - 1 - EFI_SIZE_TO_BLOCKS (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;
+  }
+
+  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_ENTRY         *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 parst will not used by UEFI, so we skip to check them.
+  //
+  for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
+    MbrPartition = (MBR_PARTITION_ENTRY *)&ProtectiveMbr->Partition[Index];
+    if (MbrPartition->BootIndicator   == 0x00 &&
+        MbrPartition->StartingCHS[0]  == 0x00 &&
+        MbrPartition->StartingCHS[1]  == 0x02 &&
+        MbrPartition->StartingCHS[2]  == 0x00 &&
+        MbrPartition->OSType          == PMBR_GPT_PARTITION &&
+        MbrPartition->StartingLBA     == 0x1
+       ) {
+      return TRUE;
+    }
+  }
+
+  DEBUG ((DEBUG_ERROR, "Protective Mbr, All Partition Entry Are Empty!\n"));
+  return FALSE;
+}
+
+/**
+  This function is used for findg GPT partition on block device.
+  As follow UEFI spec We should check protecive 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;
+}
-- 
2.16.2.windows.1



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 3/3] FatPkg: Add GPT check in FatPei to support Capsule-on-Disk feature.
       [not found] ` <734D49CCEBEEF84792F5B80ED585239D5BFC0EC2@SHSMSX103.ccr.corp.intel.com>
@ 2019-01-23  1:25   ` Wu, Hao A
  2019-01-23  1:27     ` Wu, Hao A
  0 siblings, 1 reply; 6+ messages in thread
From: Wu, Hao A @ 2019-01-23  1:25 UTC (permalink / raw)
  To: Ni, Ray, Chen, Chen A, edk2-devel@lists.01.org; +Cc: Zhang, Chao B

> -----Original Message-----
> From: Ni, Ray
> Sent: Thursday, January 17, 2019 11:50 AM
> To: Chen, Chen A; edk2-devel@lists.01.org; Wu, Hao A
> Cc: Zhang, Chao B
> Subject: RE: [PATCH 3/3] FatPkg: Add GPT check in FatPei to support Capsule-
> on-Disk feature.
> 
> Adding Wu Hao in the reviewer list.

Sorry for the delayed response.
I will try my best to give my comments as soon as possible.

Please help to ping if there is reply within the next two weeks.

Best Regards,
Hao Wu

> 
> > -----Original Message-----
> > From: Chen, Chen A <chen.a.chen@intel.com>
> > Sent: Thursday, January 17, 2019 10:03 AM
> > To: edk2-devel@lists.01.org
> > Cc: Chen, Chen A <chen.a.chen@intel.com>; Ni, Ray <ray.ni@intel.com>;
> > Zhang, Chao B <chao.b.zhang@intel.com>
> > Subject: [PATCH 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.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>
> > ---
> >  FatPkg/FatPei/FatLitePeim.h |   1 +
> >  FatPkg/FatPei/FatPei.inf    |   3 +
> >  FatPkg/FatPei/Gpt.c         | 546
> > ++++++++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 550 insertions(+)
> >  create mode 100644 FatPkg/FatPei/Gpt.c
> >
> > diff --git a/FatPkg/FatPei/FatLitePeim.h b/FatPkg/FatPei/FatLitePeim.h
> index
> > fbf887da5f..afb429c56e 100644
> > --- a/FatPkg/FatPei/FatLitePeim.h
> > +++ b/FatPkg/FatPei/FatLitePeim.h
> > @@ -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
> > 829e87fe92..dd0869f7cd 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..d1f4c1c8b5
> > --- /dev/null
> > +++ b/FatPkg/FatPei/Gpt.c
> > @@ -0,0 +1,546 @@
> > +/** @file
> > +  Routines supporting partition discovery and
> > +  logical device reading
> > +
> > +Copyright (c) 2006 - 2018, 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
> > (GPT_PART_ENTRY_MIN_SIZE, ParentBlockDev->BlockSize)) ||
> > +       (PartHdr->LastUsableLBA  > ParentBlockDev->LastBlock - 1 -
> > EFI_SIZE_TO_BLOCKS (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;
> > +  }
> > +
> > +  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_ENTRY         *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 parst will not used by UEFI, so we skip to check them.
> > +  //
> > +  for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
> > +    MbrPartition = (MBR_PARTITION_ENTRY *)&ProtectiveMbr-
> > >Partition[Index];
> > +    if (MbrPartition->BootIndicator   == 0x00 &&
> > +        MbrPartition->StartingCHS[0]  == 0x00 &&
> > +        MbrPartition->StartingCHS[1]  == 0x02 &&
> > +        MbrPartition->StartingCHS[2]  == 0x00 &&
> > +        MbrPartition->OSType          == PMBR_GPT_PARTITION &&
> > +        MbrPartition->StartingLBA     == 0x1
> > +       ) {
> > +      return TRUE;
> > +    }
> > +  }
> > +
> > +  DEBUG ((DEBUG_ERROR, "Protective Mbr, All Partition Entry Are
> > +Empty!\n"));
> > +  return FALSE;
> > +}
> > +
> > +/**
> > +  This function is used for findg GPT partition on block device.
> > +  As follow UEFI spec We should check protecive 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;
> > +}
> > --
> > 2.16.2.windows.1



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 3/3] FatPkg: Add GPT check in FatPei to support Capsule-on-Disk feature.
  2019-01-23  1:25   ` Wu, Hao A
@ 2019-01-23  1:27     ` Wu, Hao A
  0 siblings, 0 replies; 6+ messages in thread
From: Wu, Hao A @ 2019-01-23  1:27 UTC (permalink / raw)
  To: Ni, Ray, Chen, Chen A, edk2-devel@lists.01.org; +Cc: Zhang, Chao B

> -----Original Message-----
> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
> Wu, Hao A
> Sent: Wednesday, January 23, 2019 9:25 AM
> To: Ni, Ray; Chen, Chen A; edk2-devel@lists.01.org
> Cc: Zhang, Chao B
> Subject: Re: [edk2] [PATCH 3/3] FatPkg: Add GPT check in FatPei to support
> Capsule-on-Disk feature.
> 
> > -----Original Message-----
> > From: Ni, Ray
> > Sent: Thursday, January 17, 2019 11:50 AM
> > To: Chen, Chen A; edk2-devel@lists.01.org; Wu, Hao A
> > Cc: Zhang, Chao B
> > Subject: RE: [PATCH 3/3] FatPkg: Add GPT check in FatPei to support
> Capsule-
> > on-Disk feature.
> >
> > Adding Wu Hao in the reviewer list.
> 
> Sorry for the delayed response.
> I will try my best to give my comments as soon as possible.
> 
> Please help to ping if there is reply within the next two weeks.

Correction:
Please help to ping if there is no reply within the next two weeks.

> 
> Best Regards,
> Hao Wu
> 
> >
> > > -----Original Message-----
> > > From: Chen, Chen A <chen.a.chen@intel.com>
> > > Sent: Thursday, January 17, 2019 10:03 AM
> > > To: edk2-devel@lists.01.org
> > > Cc: Chen, Chen A <chen.a.chen@intel.com>; Ni, Ray <ray.ni@intel.com>;
> > > Zhang, Chao B <chao.b.zhang@intel.com>
> > > Subject: [PATCH 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.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>
> > > ---
> > >  FatPkg/FatPei/FatLitePeim.h |   1 +
> > >  FatPkg/FatPei/FatPei.inf    |   3 +
> > >  FatPkg/FatPei/Gpt.c         | 546
> > > ++++++++++++++++++++++++++++++++++++++++++++
> > >  3 files changed, 550 insertions(+)
> > >  create mode 100644 FatPkg/FatPei/Gpt.c
> > >
> > > diff --git a/FatPkg/FatPei/FatLitePeim.h b/FatPkg/FatPei/FatLitePeim.h
> > index
> > > fbf887da5f..afb429c56e 100644
> > > --- a/FatPkg/FatPei/FatLitePeim.h
> > > +++ b/FatPkg/FatPei/FatLitePeim.h
> > > @@ -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
> > > 829e87fe92..dd0869f7cd 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..d1f4c1c8b5
> > > --- /dev/null
> > > +++ b/FatPkg/FatPei/Gpt.c
> > > @@ -0,0 +1,546 @@
> > > +/** @file
> > > +  Routines supporting partition discovery and
> > > +  logical device reading
> > > +
> > > +Copyright (c) 2006 - 2018, 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
> > > (GPT_PART_ENTRY_MIN_SIZE, ParentBlockDev->BlockSize)) ||
> > > +       (PartHdr->LastUsableLBA  > ParentBlockDev->LastBlock - 1 -
> > > EFI_SIZE_TO_BLOCKS (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;
> > > +  }
> > > +
> > > +  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_ENTRY         *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 parst will not used by UEFI, so we skip to check them.
> > > +  //
> > > +  for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
> > > +    MbrPartition = (MBR_PARTITION_ENTRY *)&ProtectiveMbr-
> > > >Partition[Index];
> > > +    if (MbrPartition->BootIndicator   == 0x00 &&
> > > +        MbrPartition->StartingCHS[0]  == 0x00 &&
> > > +        MbrPartition->StartingCHS[1]  == 0x02 &&
> > > +        MbrPartition->StartingCHS[2]  == 0x00 &&
> > > +        MbrPartition->OSType          == PMBR_GPT_PARTITION &&
> > > +        MbrPartition->StartingLBA     == 0x1
> > > +       ) {
> > > +      return TRUE;
> > > +    }
> > > +  }
> > > +
> > > +  DEBUG ((DEBUG_ERROR, "Protective Mbr, All Partition Entry Are
> > > +Empty!\n"));
> > > +  return FALSE;
> > > +}
> > > +
> > > +/**
> > > +  This function is used for findg GPT partition on block device.
> > > +  As follow UEFI spec We should check protecive 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;
> > > +}
> > > --
> > > 2.16.2.windows.1
> 
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 3/3] FatPkg: Add GPT check in FatPei to support Capsule-on-Disk feature.
  2019-01-17  2:03 [PATCH 3/3] FatPkg: Add GPT check in FatPei to support Capsule-on-Disk feature Chen A Chen
       [not found] ` <734D49CCEBEEF84792F5B80ED585239D5BFC0EC2@SHSMSX103.ccr.corp.intel.com>
@ 2019-01-23  6:21 ` Zhang, Chao B
  2019-01-23  8:40   ` Chen, Chen A
  2019-01-28  5:10 ` Wu, Hao A
  2 siblings, 1 reply; 6+ messages in thread
From: Zhang, Chao B @ 2019-01-23  6:21 UTC (permalink / raw)
  To: Chen, Chen A, edk2-devel@lists.01.org

Reviewed-by : Chao Zhang <chao.b.zhang@intel.com>

-----Original Message-----
From: Chen, Chen A 
Sent: Thursday, January 17, 2019 10:03 AM
To: edk2-devel@lists.01.org
Cc: Chen, Chen A <chen.a.chen@intel.com>; Ni, Ray <ray.ni@intel.com>; Zhang, Chao B <chao.b.zhang@intel.com>
Subject: [PATCH 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.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>
---
 FatPkg/FatPei/FatLitePeim.h |   1 +
 FatPkg/FatPei/FatPei.inf    |   3 +
 FatPkg/FatPei/Gpt.c         | 546 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 550 insertions(+)
 create mode 100644 FatPkg/FatPei/Gpt.c

diff --git a/FatPkg/FatPei/FatLitePeim.h b/FatPkg/FatPei/FatLitePeim.h index fbf887da5f..afb429c56e 100644
--- a/FatPkg/FatPei/FatLitePeim.h
+++ b/FatPkg/FatPei/FatLitePeim.h
@@ -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 829e87fe92..dd0869f7cd 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..d1f4c1c8b5
--- /dev/null
+++ b/FatPkg/FatPei/Gpt.c
@@ -0,0 +1,546 @@
+/** @file
+  Routines supporting partition discovery and
+  logical device reading
+
+Copyright (c) 2006 - 2018, 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 (GPT_PART_ENTRY_MIN_SIZE, ParentBlockDev->BlockSize)) ||
+       (PartHdr->LastUsableLBA  > ParentBlockDev->LastBlock - 1 - EFI_SIZE_TO_BLOCKS (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;
+  }
+
+  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_ENTRY         *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 parst will not used by UEFI, so we skip to check them.
+  //
+  for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
+    MbrPartition = (MBR_PARTITION_ENTRY *)&ProtectiveMbr->Partition[Index];
+    if (MbrPartition->BootIndicator   == 0x00 &&
+        MbrPartition->StartingCHS[0]  == 0x00 &&
+        MbrPartition->StartingCHS[1]  == 0x02 &&
+        MbrPartition->StartingCHS[2]  == 0x00 &&
+        MbrPartition->OSType          == PMBR_GPT_PARTITION &&
+        MbrPartition->StartingLBA     == 0x1
+       ) {
+      return TRUE;
+    }
+  }
+
+  DEBUG ((DEBUG_ERROR, "Protective Mbr, All Partition Entry Are 
+Empty!\n"));
+  return FALSE;
+}
+
+/**
+  This function is used for findg GPT partition on block device.
+  As follow UEFI spec We should check protecive 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;
+}
--
2.16.2.windows.1



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 3/3] FatPkg: Add GPT check in FatPei to support Capsule-on-Disk feature.
  2019-01-23  6:21 ` Zhang, Chao B
@ 2019-01-23  8:40   ` Chen, Chen A
  0 siblings, 0 replies; 6+ messages in thread
From: Chen, Chen A @ 2019-01-23  8:40 UTC (permalink / raw)
  To: Zhang, Chao B, edk2-devel@lists.01.org; +Cc: Ni, Ray, Wu, Hao A

Hi Ray and Hao

Do you have any comments for this patch?

-----Original Message-----
From: Zhang, Chao B 
Sent: Wednesday, January 23, 2019 2:22 PM
To: Chen, Chen A <chen.a.chen@intel.com>; edk2-devel@lists.01.org
Cc: Ni, Ray <ray.ni@intel.com>
Subject: RE: [PATCH 3/3] FatPkg: Add GPT check in FatPei to support Capsule-on-Disk feature.

Reviewed-by : Chao Zhang <chao.b.zhang@intel.com>

-----Original Message-----
From: Chen, Chen A
Sent: Thursday, January 17, 2019 10:03 AM
To: edk2-devel@lists.01.org
Cc: Chen, Chen A <chen.a.chen@intel.com>; Ni, Ray <ray.ni@intel.com>; Zhang, Chao B <chao.b.zhang@intel.com>
Subject: [PATCH 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.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>
---
 FatPkg/FatPei/FatLitePeim.h |   1 +
 FatPkg/FatPei/FatPei.inf    |   3 +
 FatPkg/FatPei/Gpt.c         | 546 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 550 insertions(+)
 create mode 100644 FatPkg/FatPei/Gpt.c

diff --git a/FatPkg/FatPei/FatLitePeim.h b/FatPkg/FatPei/FatLitePeim.h index fbf887da5f..afb429c56e 100644
--- a/FatPkg/FatPei/FatLitePeim.h
+++ b/FatPkg/FatPei/FatLitePeim.h
@@ -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 829e87fe92..dd0869f7cd 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..d1f4c1c8b5
--- /dev/null
+++ b/FatPkg/FatPei/Gpt.c
@@ -0,0 +1,546 @@
+/** @file
+  Routines supporting partition discovery and
+  logical device reading
+
+Copyright (c) 2006 - 2018, 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 (GPT_PART_ENTRY_MIN_SIZE, ParentBlockDev->BlockSize)) ||
+       (PartHdr->LastUsableLBA  > ParentBlockDev->LastBlock - 1 - EFI_SIZE_TO_BLOCKS (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;
+  }
+
+  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_ENTRY         *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 parst will not used by UEFI, so we skip to check them.
+  //
+  for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
+    MbrPartition = (MBR_PARTITION_ENTRY *)&ProtectiveMbr->Partition[Index];
+    if (MbrPartition->BootIndicator   == 0x00 &&
+        MbrPartition->StartingCHS[0]  == 0x00 &&
+        MbrPartition->StartingCHS[1]  == 0x02 &&
+        MbrPartition->StartingCHS[2]  == 0x00 &&
+        MbrPartition->OSType          == PMBR_GPT_PARTITION &&
+        MbrPartition->StartingLBA     == 0x1
+       ) {
+      return TRUE;
+    }
+  }
+
+  DEBUG ((DEBUG_ERROR, "Protective Mbr, All Partition Entry Are 
+Empty!\n"));
+  return FALSE;
+}
+
+/**
+  This function is used for findg GPT partition on block device.
+  As follow UEFI spec We should check protecive 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;
+}
--
2.16.2.windows.1



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 3/3] FatPkg: Add GPT check in FatPei to support Capsule-on-Disk feature.
  2019-01-17  2:03 [PATCH 3/3] FatPkg: Add GPT check in FatPei to support Capsule-on-Disk feature Chen A Chen
       [not found] ` <734D49CCEBEEF84792F5B80ED585239D5BFC0EC2@SHSMSX103.ccr.corp.intel.com>
  2019-01-23  6:21 ` Zhang, Chao B
@ 2019-01-28  5:10 ` Wu, Hao A
  2 siblings, 0 replies; 6+ messages in thread
From: Wu, Hao A @ 2019-01-28  5:10 UTC (permalink / raw)
  To: Chen, Chen A, edk2-devel@lists.01.org; +Cc: Ni, Ray, Zhang, Chao B

Hello,

A general-level comment:
I saw the implementation of function FatFindGptPartitions() has been added
in this patch. But unlike functions:

FatFindMbrPartitions()
FatFindEltoritoPartitions()

I did not see FatFindGptPartitions() being called within the FatPei
driver. Is it supposed to be added within FatFindPartitions()?

Please help to refer to the inline comments below as well:

> -----Original Message-----
> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
> Chen A Chen
> Sent: Thursday, January 17, 2019 10:03 AM
> To: edk2-devel@lists.01.org
> Cc: Ni, Ray; Zhang, Chao B
> Subject: [edk2] [PATCH 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.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>
> ---
>  FatPkg/FatPei/FatLitePeim.h |   1 +
>  FatPkg/FatPei/FatPei.inf    |   3 +
>  FatPkg/FatPei/Gpt.c         | 546
> ++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 550 insertions(+)
>  create mode 100644 FatPkg/FatPei/Gpt.c
> 
> diff --git a/FatPkg/FatPei/FatLitePeim.h b/FatPkg/FatPei/FatLitePeim.h
> index fbf887da5f..afb429c56e 100644
> --- a/FatPkg/FatPei/FatLitePeim.h
> +++ b/FatPkg/FatPei/FatLitePeim.h
> @@ -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 829e87fe92..dd0869f7cd 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..d1f4c1c8b5
> --- /dev/null
> +++ b/FatPkg/FatPei/Gpt.c
> @@ -0,0 +1,546 @@
> +/** @file
> +  Routines supporting partition discovery and
> +  logical device reading
> +
> +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>

A minor comment here:

Since this is a new file with new codes, I think the copyright year can be
2019 only.

> +
> +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
> (GPT_PART_ENTRY_MIN_SIZE, ParentBlockDev->BlockSize)) ||
> +       (PartHdr->LastUsableLBA  > ParentBlockDev->LastBlock - 1 -
> EFI_SIZE_TO_BLOCKS (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;
> +  }
> +
> +  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_ENTRY         *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 parst will not used by UEFI, so we skip to check them.

'parst' -> 'parts'
'will not used by UEFI' -> 'will not be used by UEFI'

> +  //
> +  for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
> +    MbrPartition = (MBR_PARTITION_ENTRY *)&ProtectiveMbr-
> >Partition[Index];
> +    if (MbrPartition->BootIndicator   == 0x00 &&
> +        MbrPartition->StartingCHS[0]  == 0x00 &&
> +        MbrPartition->StartingCHS[1]  == 0x02 &&
> +        MbrPartition->StartingCHS[2]  == 0x00 &&
> +        MbrPartition->OSType          == PMBR_GPT_PARTITION &&
> +        MbrPartition->StartingLBA     == 0x1

Please help to update the above codes to use the structure
'MBR_PARTITION_RECORD' in file edk2/MdePkg/Include/IndustryStandard/Mbr.h
as the feedbacks for the 2/3 patch.

> +       ) {
> +      return TRUE;
> +    }
> +  }
> +
> +  DEBUG ((DEBUG_ERROR, "Protective Mbr, All Partition Entry Are
> Empty!\n"));
> +  return FALSE;
> +}
> +
> +/**
> +  This function is used for findg GPT partition on block device.

'findg' -> 'finding'

> +  As follow UEFI spec We should check protecive MBR first and then

'We' -> 'we'
'protecive' -> 'protective'

> +  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

Please remove the extra space in 'are  added'.

> +  @retval FALSE             No New partitions are added;

'New' -> 'new'

Best Regards,
Hao Wu

> +
> +**/
> +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;
> +}
> --
> 2.16.2.windows.1
> 
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2019-01-28  5:10 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-01-17  2:03 [PATCH 3/3] FatPkg: Add GPT check in FatPei to support Capsule-on-Disk feature Chen A Chen
     [not found] ` <734D49CCEBEEF84792F5B80ED585239D5BFC0EC2@SHSMSX103.ccr.corp.intel.com>
2019-01-23  1:25   ` Wu, Hao A
2019-01-23  1:27     ` Wu, Hao A
2019-01-23  6:21 ` Zhang, Chao B
2019-01-23  8:40   ` Chen, Chen A
2019-01-28  5:10 ` Wu, Hao A

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox