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