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