Gpt.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. /** @file
  2. Routines supporting partition discovery and
  3. logical device reading
  4. Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
  5. This program and the accompanying materials are licensed and made available
  6. under the terms and conditions of the BSD License which accompanies this
  7. distribution. The full text of the license may be found at
  8. http://opensource.org/licenses/bsd-license.php
  9. THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
  11. **/
  12. #include <IndustryStandard/Mbr.h>
  13. #include <Uefi/UefiGpt.h>
  14. #include <Library/BaseLib.h>
  15. #include "FatLitePeim.h"
  16. //
  17. // Assumption: 'a' and 'blocksize' are all UINT32 or UINT64.
  18. // If 'a' and 'blocksize' are not the same type, should use DivU64xU32 to calculate.
  19. //
  20. #define EFI_SIZE_TO_BLOCKS(a, blocksize) (((a) / (blocksize)) + (((a) % (blocksize)) ? 1 : 0))
  21. //
  22. // GPT Partition Entry Status
  23. //
  24. typedef struct {
  25. BOOLEAN OutOfRange;
  26. BOOLEAN Overlap;
  27. BOOLEAN OsSpecific;
  28. } EFI_PARTITION_ENTRY_STATUS;
  29. /**
  30. Check if the CRC field in the Partition table header is valid.
  31. @param[in] PartHeader Partition table header structure
  32. @retval TRUE the CRC is valid
  33. @retval FALSE the CRC is invalid
  34. **/
  35. BOOLEAN
  36. PartitionCheckGptHeaderCRC (
  37. IN EFI_PARTITION_TABLE_HEADER *PartHeader
  38. )
  39. {
  40. UINT32 GptHdrCrc;
  41. UINT32 Crc;
  42. GptHdrCrc = PartHeader->Header.CRC32;
  43. //
  44. // Set CRC field to zero when doing calcuation
  45. //
  46. PartHeader->Header.CRC32 = 0;
  47. Crc = CalculateCrc32 (PartHeader, PartHeader->Header.HeaderSize);
  48. //
  49. // Restore Header CRC
  50. //
  51. PartHeader->Header.CRC32 = GptHdrCrc;
  52. return (GptHdrCrc == Crc);
  53. }
  54. /**
  55. Check if the CRC field in the Partition table header is valid
  56. for Partition entry array.
  57. @param[in] PartHeader Partition table header structure
  58. @param[in] PartEntry The partition entry array
  59. @retval TRUE the CRC is valid
  60. @retval FALSE the CRC is invalid
  61. **/
  62. BOOLEAN
  63. PartitionCheckGptEntryArrayCRC (
  64. IN EFI_PARTITION_TABLE_HEADER *PartHeader,
  65. IN EFI_PARTITION_ENTRY *PartEntry
  66. )
  67. {
  68. UINT32 Crc;
  69. UINTN Size;
  70. Size = (UINTN)MultU64x32(PartHeader->NumberOfPartitionEntries, PartHeader->SizeOfPartitionEntry);
  71. Crc = CalculateCrc32 (PartEntry, Size);
  72. return (BOOLEAN) (PartHeader->PartitionEntryArrayCRC32 == Crc);
  73. }
  74. /**
  75. The function is used for valid GPT table. Both for Primary and Backup GPT header.
  76. @param[in] PrivateData The global memory map
  77. @param[in] ParentBlockDevNo The parent block device
  78. @param[in] IsPrimaryHeader Indicate to which header will be checked.
  79. @param[in] PartHdr Stores the partition table that is read
  80. @retval TRUE The partition table is valid
  81. @retval FALSE The partition table is not valid
  82. **/
  83. BOOLEAN
  84. PartitionCheckGptHeader (
  85. IN PEI_FAT_PRIVATE_DATA *PrivateData,
  86. IN UINTN ParentBlockDevNo,
  87. IN BOOLEAN IsPrimaryHeader,
  88. IN EFI_PARTITION_TABLE_HEADER *PartHdr
  89. )
  90. {
  91. PEI_FAT_BLOCK_DEVICE *ParentBlockDev;
  92. EFI_PEI_LBA Lba;
  93. EFI_PEI_LBA AlternateLba;
  94. EFI_PEI_LBA EntryArrayLastLba;
  95. UINT64 PartitionEntryArraySize;
  96. UINT64 PartitionEntryBlockNumb;
  97. UINT32 EntryArraySizeRemainder;
  98. ParentBlockDev = &(PrivateData->BlockDevice[ParentBlockDevNo]);
  99. if (IsPrimaryHeader) {
  100. Lba = PRIMARY_PART_HEADER_LBA;
  101. AlternateLba = ParentBlockDev->LastBlock;
  102. } else {
  103. Lba = ParentBlockDev->LastBlock;
  104. AlternateLba = PRIMARY_PART_HEADER_LBA;
  105. }
  106. if ( (PartHdr->Header.Signature != EFI_PTAB_HEADER_ID) ||
  107. (PartHdr->Header.Revision != 0x00010000) ||
  108. (PartHdr->Header.HeaderSize < 92) ||
  109. (PartHdr->Header.HeaderSize > ParentBlockDev->BlockSize) ||
  110. (!PartitionCheckGptHeaderCRC (PartHdr)) ||
  111. (PartHdr->Header.Reserved != 0)
  112. ) {
  113. DEBUG ((DEBUG_ERROR, "Invalid efi partition table header\n"));
  114. return FALSE;
  115. }
  116. //
  117. // | Block0 | Block1 |Block2 ~ FirstUsableLBA - 1|FirstUsableLBA, ... ,LastUsableLBA|LastUsableLBA+1 ~ LastBlock-1| LastBlock |
  118. // |Protective MBR|Primary Header|Entry Array(At Least 16384)| Partition | Entry Array(At Least 16384) |BackUp Header|
  119. //
  120. // 1. Protective MBR is fixed at Block 0.
  121. // 2. Primary Header is fixed at Block 1.
  122. // 3. Backup Header is fixed at LastBlock.
  123. // 4. Must be remain 128*128 bytes for primary entry array.
  124. // 5. Must be remain 128*128 bytes for backup entry array.
  125. // 6. SizeOfPartitionEntry must be equals to 128 * 2^n.
  126. //
  127. if ( (PartHdr->MyLBA != Lba) ||
  128. (PartHdr->AlternateLBA != AlternateLba) ||
  129. (PartHdr->FirstUsableLBA < 2 + EFI_SIZE_TO_BLOCKS (EFI_GPT_PART_ENTRY_MIN_SIZE, ParentBlockDev->BlockSize)) ||
  130. (PartHdr->LastUsableLBA > ParentBlockDev->LastBlock - 1 - EFI_SIZE_TO_BLOCKS (EFI_GPT_PART_ENTRY_MIN_SIZE, ParentBlockDev->BlockSize)) ||
  131. (PartHdr->FirstUsableLBA > PartHdr->LastUsableLBA) ||
  132. (PartHdr->PartitionEntryLBA < 2) ||
  133. (PartHdr->PartitionEntryLBA > ParentBlockDev->LastBlock - 1) ||
  134. (PartHdr->PartitionEntryLBA >= PartHdr->FirstUsableLBA && PartHdr->PartitionEntryLBA <= PartHdr->LastUsableLBA) ||
  135. (PartHdr->SizeOfPartitionEntry%128 != 0) ||
  136. (PartHdr->SizeOfPartitionEntry != sizeof (EFI_PARTITION_ENTRY))
  137. ) {
  138. DEBUG ((DEBUG_ERROR, "Invalid efi partition table header\n"));
  139. return FALSE;
  140. }
  141. //
  142. // Ensure the NumberOfPartitionEntries * SizeOfPartitionEntry doesn't overflow.
  143. //
  144. if (PartHdr->NumberOfPartitionEntries > DivU64x32 (MAX_UINTN, PartHdr->SizeOfPartitionEntry)) {
  145. DEBUG ((DEBUG_ERROR, "Memory overflow in GPT Entry Array\n"));
  146. return FALSE;
  147. }
  148. PartitionEntryArraySize = MultU64x32 (PartHdr->NumberOfPartitionEntries, PartHdr->SizeOfPartitionEntry);
  149. EntryArraySizeRemainder = 0;
  150. PartitionEntryBlockNumb = DivU64x32Remainder (PartitionEntryArraySize, ParentBlockDev->BlockSize, &EntryArraySizeRemainder);
  151. if (EntryArraySizeRemainder != 0) {
  152. PartitionEntryBlockNumb++;
  153. }
  154. if (IsPrimaryHeader) {
  155. EntryArrayLastLba = PartHdr->FirstUsableLBA;
  156. } else {
  157. EntryArrayLastLba = ParentBlockDev->LastBlock;
  158. }
  159. //
  160. // Make sure partition entry array not overlaps with partition area or the LastBlock.
  161. //
  162. if (PartHdr->PartitionEntryLBA + PartitionEntryBlockNumb > EntryArrayLastLba) {
  163. DEBUG ((DEBUG_ERROR, "GPT Partition Entry Array Error!\n"));
  164. DEBUG ((DEBUG_ERROR, "PartitionEntryArraySize = %lu.\n", PartitionEntryArraySize));
  165. DEBUG ((DEBUG_ERROR, "PartitionEntryLBA = %lu.\n", PartHdr->PartitionEntryLBA));
  166. DEBUG ((DEBUG_ERROR, "PartitionEntryBlockNumb = %lu.\n", PartitionEntryBlockNumb));
  167. DEBUG ((DEBUG_ERROR, "EntryArrayLastLba = %lu.\n", EntryArrayLastLba));
  168. return FALSE;
  169. }
  170. return TRUE;
  171. }
  172. /**
  173. This function is used to verify each partition in block device.
  174. @param[in] PrivateData The global memory map
  175. @param[in] ParentBlockDevNo The parent block device
  176. @param[in] PartHdr Stores the partition table that is read
  177. @retval TRUE The partition is valid
  178. @retval FALSE The partition is not valid
  179. **/
  180. BOOLEAN
  181. PartitionCheckGptEntryArray (
  182. IN PEI_FAT_PRIVATE_DATA *PrivateData,
  183. IN UINTN ParentBlockDevNo,
  184. IN EFI_PARTITION_TABLE_HEADER *PartHdr
  185. )
  186. {
  187. EFI_STATUS Status;
  188. PEI_FAT_BLOCK_DEVICE *ParentBlockDev;
  189. PEI_FAT_BLOCK_DEVICE *BlockDevPtr;
  190. UINT64 PartitionEntryArraySize;
  191. UINT64 PartitionEntryBlockNumb;
  192. UINT32 EntryArraySizeRemainder;
  193. EFI_PARTITION_ENTRY *PartitionEntryBuffer;
  194. EFI_PARTITION_ENTRY_STATUS *PartitionEntryStatus;
  195. BOOLEAN Found;
  196. EFI_LBA StartingLBA;
  197. EFI_LBA EndingLBA;
  198. UINTN Index;
  199. UINTN Index1;
  200. UINTN Index2;
  201. EFI_PARTITION_ENTRY *Entry;
  202. PartitionEntryBuffer = NULL;
  203. PartitionEntryStatus = NULL;
  204. ParentBlockDev = &(PrivateData->BlockDevice[ParentBlockDevNo]);
  205. Found = FALSE;
  206. PartitionEntryArraySize = MultU64x32 (PartHdr->NumberOfPartitionEntries, PartHdr->SizeOfPartitionEntry);
  207. EntryArraySizeRemainder = 0;
  208. PartitionEntryBlockNumb = DivU64x32Remainder (PartitionEntryArraySize, ParentBlockDev->BlockSize, &EntryArraySizeRemainder);
  209. if (EntryArraySizeRemainder != 0) {
  210. PartitionEntryBlockNumb++;
  211. }
  212. PartitionEntryArraySize = MultU64x32 (PartitionEntryBlockNumb, ParentBlockDev->BlockSize);
  213. PartitionEntryBuffer = (EFI_PARTITION_ENTRY *) AllocatePages (EFI_SIZE_TO_PAGES ((UINTN)PartitionEntryArraySize));
  214. if (PartitionEntryBuffer == NULL) {
  215. DEBUG ((DEBUG_ERROR, "Allocate memory error!\n"));
  216. goto EXIT;
  217. }
  218. PartitionEntryStatus = (EFI_PARTITION_ENTRY_STATUS *) AllocatePages (EFI_SIZE_TO_PAGES (PartHdr->NumberOfPartitionEntries * sizeof (EFI_PARTITION_ENTRY_STATUS)));
  219. if (PartitionEntryStatus == NULL) {
  220. DEBUG ((DEBUG_ERROR, "Allocate memory error!\n"));
  221. goto EXIT;
  222. }
  223. ZeroMem (PartitionEntryStatus, PartHdr->NumberOfPartitionEntries * sizeof (EFI_PARTITION_ENTRY_STATUS));
  224. Status = FatReadBlock (
  225. PrivateData,
  226. ParentBlockDevNo,
  227. PartHdr->PartitionEntryLBA,
  228. (UINTN)PartitionEntryArraySize,
  229. PartitionEntryBuffer
  230. );
  231. if (EFI_ERROR (Status)) {
  232. DEBUG ((DEBUG_ERROR, "Read partition entry array error!\n"));
  233. goto EXIT;
  234. }
  235. if (!PartitionCheckGptEntryArrayCRC (PartHdr, PartitionEntryBuffer)) {
  236. DEBUG ((DEBUG_ERROR, "Partition entries CRC check fail\n"));
  237. goto EXIT;
  238. }
  239. for (Index1 = 0; Index1 < PartHdr->NumberOfPartitionEntries; Index1++) {
  240. Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartitionEntryBuffer + Index1 * PartHdr->SizeOfPartitionEntry);
  241. if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {
  242. continue;
  243. }
  244. StartingLBA = Entry->StartingLBA;
  245. EndingLBA = Entry->EndingLBA;
  246. if (StartingLBA > EndingLBA ||
  247. StartingLBA < PartHdr->FirstUsableLBA ||
  248. StartingLBA > PartHdr->LastUsableLBA ||
  249. EndingLBA < PartHdr->FirstUsableLBA ||
  250. EndingLBA > PartHdr->LastUsableLBA
  251. ) {
  252. PartitionEntryStatus[Index1].OutOfRange = TRUE;
  253. continue;
  254. }
  255. if ((Entry->Attributes & BIT1) != 0) {
  256. //
  257. // If Bit 1 is set, this indicate that this is an OS specific GUID partition.
  258. //
  259. PartitionEntryStatus[Index1].OsSpecific = TRUE;
  260. }
  261. for (Index2 = Index1 + 1; Index2 < PartHdr->NumberOfPartitionEntries; Index2++) {
  262. Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartitionEntryBuffer + Index2 * PartHdr->SizeOfPartitionEntry);
  263. if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {
  264. continue;
  265. }
  266. if (Entry->EndingLBA >= StartingLBA && Entry->StartingLBA <= EndingLBA) {
  267. //
  268. // This region overlaps with the Index1'th region
  269. //
  270. PartitionEntryStatus[Index1].Overlap = TRUE;
  271. PartitionEntryStatus[Index2].Overlap = TRUE;
  272. continue;
  273. }
  274. }
  275. }
  276. for (Index = 0; Index < PartHdr->NumberOfPartitionEntries; Index++) {
  277. if (CompareGuid (&PartitionEntryBuffer[Index].PartitionTypeGUID, &gEfiPartTypeUnusedGuid)||
  278. PartitionEntryStatus[Index].OutOfRange ||
  279. PartitionEntryStatus[Index].Overlap ||
  280. PartitionEntryStatus[Index].OsSpecific) {
  281. //
  282. // Don't use null EFI Partition Entries, Invalid Partition Entries or OS specific
  283. // partition Entries
  284. //
  285. continue;
  286. }
  287. if (PrivateData->BlockDeviceCount >= PEI_FAT_MAX_BLOCK_DEVICE) {
  288. break;
  289. }
  290. Found = TRUE;
  291. BlockDevPtr = &(PrivateData->BlockDevice[PrivateData->BlockDeviceCount]);
  292. BlockDevPtr->BlockSize = ParentBlockDev->BlockSize;
  293. BlockDevPtr->LastBlock = PartitionEntryBuffer[Index].EndingLBA;
  294. BlockDevPtr->IoAlign = ParentBlockDev->IoAlign;
  295. BlockDevPtr->Logical = TRUE;
  296. BlockDevPtr->PartitionChecked = FALSE;
  297. BlockDevPtr->StartingPos = MultU64x32 (
  298. PartitionEntryBuffer[Index].StartingLBA,
  299. ParentBlockDev->BlockSize
  300. );
  301. BlockDevPtr->ParentDevNo = ParentBlockDevNo;
  302. PrivateData->BlockDeviceCount++;
  303. DEBUG ((DEBUG_INFO, "Find GPT Partition [0x%lx", PartitionEntryBuffer[Index].StartingLBA, BlockDevPtr->LastBlock));
  304. DEBUG ((DEBUG_INFO, ", 0x%lx]\n", BlockDevPtr->LastBlock));
  305. DEBUG ((DEBUG_INFO, " BlockSize %x\n", BlockDevPtr->BlockSize));
  306. }
  307. EXIT:
  308. if (PartitionEntryBuffer != NULL) {
  309. FreePages (PartitionEntryBuffer, EFI_SIZE_TO_PAGES ((UINTN)PartitionEntryArraySize));
  310. }
  311. if (PartitionEntryStatus != NULL) {
  312. FreePages (PartitionEntryStatus, EFI_SIZE_TO_PAGES (PartHdr->NumberOfPartitionEntries * sizeof (EFI_PARTITION_ENTRY_STATUS)));
  313. }
  314. return Found;
  315. }
  316. /**
  317. The function is used to check GPT structure, include GPT header and GPT entry array.
  318. 1. Check GPT header.
  319. 2. Check partition entry array.
  320. 3. Check each partitions.
  321. @param[in] PrivateData The global memory map
  322. @param[in] ParentBlockDevNo The parent block device
  323. @param[in] IsPrimary Indicate primary or backup to be check
  324. @retval TRUE Primary or backup GPT structure is valid.
  325. @retval FALSE Both primary and backup are invalid.
  326. **/
  327. BOOLEAN
  328. PartitionCheckGptStructure (
  329. IN PEI_FAT_PRIVATE_DATA *PrivateData,
  330. IN UINTN ParentBlockDevNo,
  331. IN BOOLEAN IsPrimary
  332. )
  333. {
  334. EFI_STATUS Status;
  335. PEI_FAT_BLOCK_DEVICE *ParentBlockDev;
  336. EFI_PARTITION_TABLE_HEADER *PartHdr;
  337. EFI_PEI_LBA GptHeaderLBA;
  338. ParentBlockDev = &(PrivateData->BlockDevice[ParentBlockDevNo]);
  339. PartHdr = (EFI_PARTITION_TABLE_HEADER *) PrivateData->BlockData;
  340. if (IsPrimary) {
  341. GptHeaderLBA = PRIMARY_PART_HEADER_LBA;
  342. } else {
  343. GptHeaderLBA = ParentBlockDev->LastBlock;
  344. }
  345. Status = FatReadBlock (
  346. PrivateData,
  347. ParentBlockDevNo,
  348. GptHeaderLBA,
  349. ParentBlockDev->BlockSize,
  350. PartHdr
  351. );
  352. if (EFI_ERROR (Status)) {
  353. return FALSE;
  354. }
  355. if (!PartitionCheckGptHeader (PrivateData, ParentBlockDevNo, IsPrimary, PartHdr)) {
  356. return FALSE;
  357. }
  358. if (!PartitionCheckGptEntryArray (PrivateData, ParentBlockDevNo, PartHdr)) {
  359. return FALSE;
  360. }
  361. return TRUE;
  362. }
  363. /**
  364. This function is used to check protective MBR structure before checking GPT.
  365. @param[in] PrivateData The global memory map
  366. @param[in] ParentBlockDevNo The parent block device
  367. @retval TRUE Valid protective MBR
  368. @retval FALSE Invalid MBR
  369. **/
  370. BOOLEAN
  371. PartitionCheckProtectiveMbr (
  372. IN PEI_FAT_PRIVATE_DATA *PrivateData,
  373. IN UINTN ParentBlockDevNo
  374. )
  375. {
  376. EFI_STATUS Status;
  377. MASTER_BOOT_RECORD *ProtectiveMbr;
  378. MBR_PARTITION_RECORD *MbrPartition;
  379. PEI_FAT_BLOCK_DEVICE *ParentBlockDev;
  380. UINTN Index;
  381. ProtectiveMbr = (MASTER_BOOT_RECORD *) PrivateData->BlockData;
  382. ParentBlockDev = &(PrivateData->BlockDevice[ParentBlockDevNo]);
  383. //
  384. // Read Protective MBR
  385. //
  386. Status = FatReadBlock (
  387. PrivateData,
  388. ParentBlockDevNo,
  389. 0,
  390. ParentBlockDev->BlockSize,
  391. ProtectiveMbr
  392. );
  393. if (EFI_ERROR (Status)) {
  394. DEBUG ((DEBUG_ERROR, "GPT Error When Read Protective Mbr From Partition!\n"));
  395. return FALSE;
  396. }
  397. if (ProtectiveMbr->Signature != MBR_SIGNATURE) {
  398. DEBUG ((DEBUG_ERROR, "Protective Mbr Signature is invalid!\n"));
  399. return FALSE;
  400. }
  401. //
  402. // The partition define in UEFI Spec Table 17.
  403. // Boot Code, Unique MBR Disk Signature, Unknown.
  404. // These parts will not be used by UEFI, so we skip to check them.
  405. //
  406. for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
  407. MbrPartition = (MBR_PARTITION_RECORD *)&ProtectiveMbr->Partition[Index];
  408. if (MbrPartition->BootIndicator == 0x00 &&
  409. MbrPartition->StartSector == 0x02 &&
  410. MbrPartition->OSIndicator == PMBR_GPT_PARTITION &&
  411. UNPACK_UINT32 (MbrPartition->StartingLBA) == 1
  412. ) {
  413. return TRUE;
  414. }
  415. }
  416. DEBUG ((DEBUG_ERROR, "Protective Mbr, All Partition Entry Are Empty!\n"));
  417. return FALSE;
  418. }
  419. /**
  420. This function is used for finding GPT partition on block device.
  421. As follow UEFI spec we should check protective MBR first and then
  422. try to check both primary/backup GPT structures.
  423. @param[in] PrivateData The global memory map
  424. @param[in] ParentBlockDevNo The parent block device
  425. @retval TRUE New partitions are detected and logical block devices
  426. are added to block device array
  427. @retval FALSE No new partitions are added
  428. **/
  429. BOOLEAN
  430. FatFindGptPartitions (
  431. IN PEI_FAT_PRIVATE_DATA *PrivateData,
  432. IN UINTN ParentBlockDevNo
  433. )
  434. {
  435. BOOLEAN Found;
  436. PEI_FAT_BLOCK_DEVICE *ParentBlockDev;
  437. if (ParentBlockDevNo > PEI_FAT_MAX_BLOCK_DEVICE - 1) {
  438. return FALSE;
  439. }
  440. ParentBlockDev = &(PrivateData->BlockDevice[ParentBlockDevNo]);
  441. if (ParentBlockDev->BlockSize > PEI_FAT_MAX_BLOCK_SIZE) {
  442. DEBUG ((DEBUG_ERROR, "Device BlockSize %x exceed FAT_MAX_BLOCK_SIZE\n", ParentBlockDev->BlockSize));
  443. return FALSE;
  444. }
  445. if (!PartitionCheckProtectiveMbr (PrivateData, ParentBlockDevNo)) {
  446. return FALSE;
  447. }
  448. Found = PartitionCheckGptStructure (PrivateData, ParentBlockDevNo, TRUE);
  449. if (!Found) {
  450. DEBUG ((DEBUG_ERROR, "Primary GPT Header Error, Try to Check Backup GPT Header!\n"));
  451. Found = PartitionCheckGptStructure (PrivateData, ParentBlockDevNo, FALSE);
  452. }
  453. if (Found) {
  454. ParentBlockDev->PartitionChecked = TRUE;
  455. }
  456. return Found;
  457. }