TianoCore EDK2 master
Loading...
Searching...
No Matches
Gpt.c
Go to the documentation of this file.
1
12#include <Uefi/UefiGpt.h>
13#include <Library/BaseLib.h>
14#include "FatLitePeim.h"
15
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//
23// GPT Partition Entry Status
24//
25typedef struct {
26 BOOLEAN OutOfRange;
27 BOOLEAN Overlap;
28 BOOLEAN OsSpecific;
30
40BOOLEAN
43 )
44{
45 UINT32 GptHdrCrc;
46 UINT32 Crc;
47
48 GptHdrCrc = PartHeader->Header.CRC32;
49
50 //
51 // Set CRC field to zero when doing calculation
52 //
53 PartHeader->Header.CRC32 = 0;
54
55 Crc = CalculateCrc32 (PartHeader, PartHeader->Header.HeaderSize);
56
57 //
58 // Restore Header CRC
59 //
60 PartHeader->Header.CRC32 = GptHdrCrc;
61
62 return (GptHdrCrc == Crc);
63}
64
76BOOLEAN
79 IN EFI_PARTITION_ENTRY *PartEntry
80 )
81{
82 UINT32 Crc;
83 UINTN Size;
84
85 Size = (UINTN)MultU64x32 (PartHeader->NumberOfPartitionEntries, PartHeader->SizeOfPartitionEntry);
86 Crc = CalculateCrc32 (PartEntry, Size);
87
88 return (BOOLEAN)(PartHeader->PartitionEntryArrayCRC32 == Crc);
89}
90
103BOOLEAN
105 IN PEI_FAT_PRIVATE_DATA *PrivateData,
106 IN UINTN ParentBlockDevNo,
107 IN BOOLEAN IsPrimaryHeader,
109 )
110{
111 PEI_FAT_BLOCK_DEVICE *ParentBlockDev;
112 EFI_PEI_LBA Lba;
113 EFI_PEI_LBA EntryArrayLastLba;
114
115 UINT64 PartitionEntryArraySize;
116 UINT64 PartitionEntryBlockNumb;
117 UINT32 EntryArraySizeRemainder;
118
119 ParentBlockDev = &(PrivateData->BlockDevice[ParentBlockDevNo]);
120
121 if (IsPrimaryHeader) {
123 } else {
124 Lba = ParentBlockDev->LastBlock;
125 }
126
127 if ((PartHdr->Header.Signature != EFI_PTAB_HEADER_ID) ||
128 (!PartitionCheckGptHeaderCRC (PartHdr)) ||
129 (PartHdr->MyLBA != Lba) ||
130 (PartHdr->SizeOfPartitionEntry < sizeof (EFI_PARTITION_ENTRY))
131 )
132 {
133 DEBUG ((DEBUG_ERROR, "Invalid efi partition table header\n"));
134 return FALSE;
135 }
136
137 //
138 // Ensure the NumberOfPartitionEntries * SizeOfPartitionEntry doesn't overflow.
139 //
140 if (PartHdr->NumberOfPartitionEntries > DivU64x32 (MAX_UINTN, PartHdr->SizeOfPartitionEntry)) {
141 DEBUG ((DEBUG_ERROR, "Memory overflow in GPT Entry Array\n"));
142 return FALSE;
143 }
144
145 PartitionEntryArraySize = MultU64x32 (PartHdr->NumberOfPartitionEntries, PartHdr->SizeOfPartitionEntry);
146 EntryArraySizeRemainder = 0;
147 PartitionEntryBlockNumb = DivU64x32Remainder (PartitionEntryArraySize, ParentBlockDev->BlockSize, &EntryArraySizeRemainder);
148 if (EntryArraySizeRemainder != 0) {
149 PartitionEntryBlockNumb++;
150 }
151
152 if (IsPrimaryHeader) {
153 EntryArrayLastLba = PartHdr->FirstUsableLBA;
154 } else {
155 EntryArrayLastLba = ParentBlockDev->LastBlock;
156 }
157
158 //
159 // Make sure partition entry array not overlaps with partition area or the LastBlock.
160 //
161 if (PartHdr->PartitionEntryLBA + PartitionEntryBlockNumb > EntryArrayLastLba) {
162 DEBUG ((DEBUG_ERROR, "GPT Partition Entry Array Error!\n"));
163 DEBUG ((DEBUG_ERROR, "PartitionEntryArraySize = %lu.\n", PartitionEntryArraySize));
164 DEBUG ((DEBUG_ERROR, "PartitionEntryLBA = %lu.\n", PartHdr->PartitionEntryLBA));
165 DEBUG ((DEBUG_ERROR, "PartitionEntryBlockNumb = %lu.\n", PartitionEntryBlockNumb));
166 DEBUG ((DEBUG_ERROR, "EntryArrayLastLba = %lu.\n", EntryArrayLastLba));
167 return FALSE;
168 }
169
170 return TRUE;
171}
172
184BOOLEAN
186 IN PEI_FAT_PRIVATE_DATA *PrivateData,
187 IN UINTN ParentBlockDevNo,
189 )
190{
191 EFI_STATUS Status;
192 PEI_FAT_BLOCK_DEVICE *ParentBlockDev;
193 PEI_FAT_BLOCK_DEVICE *BlockDevPtr;
194
195 UINT64 PartitionEntryArraySize;
196 UINT64 PartitionEntryBlockNumb;
197 UINT32 EntryArraySizeRemainder;
198
199 EFI_PARTITION_ENTRY *PartitionEntryBuffer;
200 EFI_PARTITION_ENTRY_STATUS *PartitionEntryStatus;
201
202 BOOLEAN Found;
203 EFI_LBA StartingLBA;
204 EFI_LBA EndingLBA;
205 UINTN Index;
206 UINTN Index1;
207 UINTN Index2;
208 EFI_PARTITION_ENTRY *Entry;
209
210 PartitionEntryBuffer = NULL;
211 PartitionEntryStatus = NULL;
212
213 ParentBlockDev = &(PrivateData->BlockDevice[ParentBlockDevNo]);
214 Found = FALSE;
215
216 PartitionEntryArraySize = MultU64x32 (PartHdr->NumberOfPartitionEntries, PartHdr->SizeOfPartitionEntry);
217 EntryArraySizeRemainder = 0;
218 PartitionEntryBlockNumb = DivU64x32Remainder (PartitionEntryArraySize, ParentBlockDev->BlockSize, &EntryArraySizeRemainder);
219 if (EntryArraySizeRemainder != 0) {
220 PartitionEntryBlockNumb++;
221 }
222
223 PartitionEntryArraySize = MultU64x32 (PartitionEntryBlockNumb, ParentBlockDev->BlockSize);
224
225 PartitionEntryBuffer = (EFI_PARTITION_ENTRY *)AllocatePages (EFI_SIZE_TO_PAGES ((UINTN)PartitionEntryArraySize));
226 if (PartitionEntryBuffer == NULL) {
227 DEBUG ((DEBUG_ERROR, "Allocate memory error!\n"));
228 goto EXIT;
229 }
230
231 PartitionEntryStatus = (EFI_PARTITION_ENTRY_STATUS *)AllocatePages (EFI_SIZE_TO_PAGES (PartHdr->NumberOfPartitionEntries * sizeof (EFI_PARTITION_ENTRY_STATUS)));
232 if (PartitionEntryStatus == NULL) {
233 DEBUG ((DEBUG_ERROR, "Allocate memory error!\n"));
234 goto EXIT;
235 }
236
237 ZeroMem (PartitionEntryStatus, PartHdr->NumberOfPartitionEntries * sizeof (EFI_PARTITION_ENTRY_STATUS));
238
239 Status = FatReadBlock (
240 PrivateData,
241 ParentBlockDevNo,
242 PartHdr->PartitionEntryLBA,
243 (UINTN)PartitionEntryArraySize,
244 PartitionEntryBuffer
245 );
246 if (EFI_ERROR (Status)) {
247 DEBUG ((DEBUG_ERROR, "Read partition entry array error!\n"));
248 goto EXIT;
249 }
250
251 if (!PartitionCheckGptEntryArrayCRC (PartHdr, PartitionEntryBuffer)) {
252 DEBUG ((DEBUG_ERROR, "Partition entries CRC check fail\n"));
253 goto EXIT;
254 }
255
256 for (Index1 = 0; Index1 < PartHdr->NumberOfPartitionEntries; Index1++) {
257 Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntryBuffer + Index1 * PartHdr->SizeOfPartitionEntry);
258 if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {
259 continue;
260 }
261
262 StartingLBA = Entry->StartingLBA;
263 EndingLBA = Entry->EndingLBA;
264 if ((StartingLBA > EndingLBA) ||
265 (StartingLBA < PartHdr->FirstUsableLBA) ||
266 (StartingLBA > PartHdr->LastUsableLBA) ||
267 (EndingLBA < PartHdr->FirstUsableLBA) ||
268 (EndingLBA > PartHdr->LastUsableLBA)
269 )
270 {
271 PartitionEntryStatus[Index1].OutOfRange = TRUE;
272 continue;
273 }
274
275 if ((Entry->Attributes & BIT1) != 0) {
276 //
277 // If Bit 1 is set, this indicate that this is an OS specific GUID partition.
278 //
279 PartitionEntryStatus[Index1].OsSpecific = TRUE;
280 }
281
282 for (Index2 = Index1 + 1; Index2 < PartHdr->NumberOfPartitionEntries; Index2++) {
283 Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntryBuffer + Index2 * PartHdr->SizeOfPartitionEntry);
284 if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {
285 continue;
286 }
287
288 if ((Entry->EndingLBA >= StartingLBA) && (Entry->StartingLBA <= EndingLBA)) {
289 //
290 // This region overlaps with the Index1'th region
291 //
292 PartitionEntryStatus[Index1].Overlap = TRUE;
293 PartitionEntryStatus[Index2].Overlap = TRUE;
294 continue;
295 }
296 }
297 }
298
299 for (Index = 0; Index < PartHdr->NumberOfPartitionEntries; Index++) {
300 if (CompareGuid (&PartitionEntryBuffer[Index].PartitionTypeGUID, &gEfiPartTypeUnusedGuid) ||
301 PartitionEntryStatus[Index].OutOfRange ||
302 PartitionEntryStatus[Index].Overlap ||
303 PartitionEntryStatus[Index].OsSpecific)
304 {
305 //
306 // Don't use null EFI Partition Entries, Invalid Partition Entries or OS specific
307 // partition Entries
308 //
309 continue;
310 }
311
312 if (PrivateData->BlockDeviceCount >= PEI_FAT_MAX_BLOCK_DEVICE) {
313 break;
314 }
315
316 Found = TRUE;
317 BlockDevPtr = &(PrivateData->BlockDevice[PrivateData->BlockDeviceCount]);
318
319 BlockDevPtr->BlockSize = ParentBlockDev->BlockSize;
320 BlockDevPtr->LastBlock = PartitionEntryBuffer[Index].EndingLBA;
321 BlockDevPtr->IoAlign = ParentBlockDev->IoAlign;
322 BlockDevPtr->Logical = TRUE;
323 BlockDevPtr->PartitionChecked = FALSE;
324 BlockDevPtr->StartingPos = MultU64x32 (
325 PartitionEntryBuffer[Index].StartingLBA,
326 ParentBlockDev->BlockSize
327 );
328 BlockDevPtr->ParentDevNo = ParentBlockDevNo;
329
330 PrivateData->BlockDeviceCount++;
331
332 DEBUG ((DEBUG_INFO, "Find GPT Partition [0x%lx", PartitionEntryBuffer[Index].StartingLBA));
333 DEBUG ((DEBUG_INFO, ", 0x%lx]\n", BlockDevPtr->LastBlock));
334 DEBUG ((DEBUG_INFO, " BlockSize %x\n", BlockDevPtr->BlockSize));
335 }
336
337EXIT:
338 if (PartitionEntryBuffer != NULL) {
339 FreePages (PartitionEntryBuffer, EFI_SIZE_TO_PAGES ((UINTN)PartitionEntryArraySize));
340 }
341
342 if (PartitionEntryStatus != NULL) {
343 FreePages (PartitionEntryStatus, EFI_SIZE_TO_PAGES (PartHdr->NumberOfPartitionEntries * sizeof (EFI_PARTITION_ENTRY_STATUS)));
344 }
345
346 return Found;
347}
348
364BOOLEAN
366 IN PEI_FAT_PRIVATE_DATA *PrivateData,
367 IN UINTN ParentBlockDevNo,
368 IN BOOLEAN IsPrimary
369 )
370{
371 EFI_STATUS Status;
372 PEI_FAT_BLOCK_DEVICE *ParentBlockDev;
374 EFI_PEI_LBA GptHeaderLBA;
375
376 ParentBlockDev = &(PrivateData->BlockDevice[ParentBlockDevNo]);
377 PartHdr = (EFI_PARTITION_TABLE_HEADER *)PrivateData->BlockData;
378
379 if (IsPrimary) {
380 GptHeaderLBA = PRIMARY_PART_HEADER_LBA;
381 } else {
382 GptHeaderLBA = ParentBlockDev->LastBlock;
383 }
384
385 Status = FatReadBlock (
386 PrivateData,
387 ParentBlockDevNo,
388 GptHeaderLBA,
389 ParentBlockDev->BlockSize,
390 PartHdr
391 );
392 if (EFI_ERROR (Status)) {
393 return FALSE;
394 }
395
396 if (!PartitionCheckGptHeader (PrivateData, ParentBlockDevNo, IsPrimary, PartHdr)) {
397 return FALSE;
398 }
399
400 if (!PartitionCheckGptEntryArray (PrivateData, ParentBlockDevNo, PartHdr)) {
401 return FALSE;
402 }
403
404 return TRUE;
405}
406
416BOOLEAN
418 IN PEI_FAT_PRIVATE_DATA *PrivateData,
419 IN UINTN ParentBlockDevNo
420 )
421{
422 EFI_STATUS Status;
423 MASTER_BOOT_RECORD *ProtectiveMbr;
424 MBR_PARTITION_RECORD *MbrPartition;
425 PEI_FAT_BLOCK_DEVICE *ParentBlockDev;
426 UINTN Index;
427
428 ProtectiveMbr = (MASTER_BOOT_RECORD *)PrivateData->BlockData;
429 ParentBlockDev = &(PrivateData->BlockDevice[ParentBlockDevNo]);
430
431 //
432 // Read Protective MBR
433 //
434 Status = FatReadBlock (
435 PrivateData,
436 ParentBlockDevNo,
437 0,
438 ParentBlockDev->BlockSize,
439 ProtectiveMbr
440 );
441 if (EFI_ERROR (Status)) {
442 DEBUG ((DEBUG_ERROR, "GPT Error When Read Protective Mbr From Partition!\n"));
443 return FALSE;
444 }
445
446 if (ProtectiveMbr->Signature != MBR_SIGNATURE) {
447 DEBUG ((DEBUG_ERROR, "Protective Mbr Signature is invalid!\n"));
448 return FALSE;
449 }
450
451 //
452 // The partition define in UEFI Spec Table 17.
453 // Boot Code, Unique MBR Disk Signature, Unknown.
454 // These parts will not be used by UEFI, so we skip to check them.
455 //
456 for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
457 MbrPartition = (MBR_PARTITION_RECORD *)&ProtectiveMbr->Partition[Index];
458 if ((MbrPartition->BootIndicator == 0x00) &&
459 (MbrPartition->StartSector == 0x02) &&
460 (MbrPartition->OSIndicator == PMBR_GPT_PARTITION) &&
461 (UNPACK_UINT32 (MbrPartition->StartingLBA) == 1)
462 )
463 {
464 return TRUE;
465 }
466 }
467
468 DEBUG ((DEBUG_ERROR, "Protective Mbr, All Partition Entry Are Empty!\n"));
469 return FALSE;
470}
471
485BOOLEAN
487 IN PEI_FAT_PRIVATE_DATA *PrivateData,
488 IN UINTN ParentBlockDevNo
489 )
490{
491 BOOLEAN Found;
492 PEI_FAT_BLOCK_DEVICE *ParentBlockDev;
493
494 if (ParentBlockDevNo > PEI_FAT_MAX_BLOCK_DEVICE - 1) {
495 return FALSE;
496 }
497
498 ParentBlockDev = &(PrivateData->BlockDevice[ParentBlockDevNo]);
499 if (ParentBlockDev->BlockSize > PEI_FAT_MAX_BLOCK_SIZE) {
500 DEBUG ((DEBUG_ERROR, "Device BlockSize %x exceed FAT_MAX_BLOCK_SIZE\n", ParentBlockDev->BlockSize));
501 return FALSE;
502 }
503
504 if (!PartitionCheckProtectiveMbr (PrivateData, ParentBlockDevNo)) {
505 return FALSE;
506 }
507
508 Found = PartitionCheckGptStructure (PrivateData, ParentBlockDevNo, TRUE);
509 if (!Found) {
510 DEBUG ((DEBUG_ERROR, "Primary GPT Header Error, Try to Check Backup GPT Header!\n"));
511 Found = PartitionCheckGptStructure (PrivateData, ParentBlockDevNo, FALSE);
512 }
513
514 if (Found) {
515 ParentBlockDev->PartitionChecked = TRUE;
516 }
517
518 return Found;
519}
UINT64 UINTN
UINT64 EFIAPI DivU64x32(IN UINT64 Dividend, IN UINT32 Divisor)
Definition: DivU64x32.c:29
UINT32 EFIAPI CalculateCrc32(IN VOID *Buffer, IN UINTN Length)
Definition: CheckSum.c:600
UINT64 EFIAPI MultU64x32(IN UINT64 Multiplicand, IN UINT32 Multiplier)
Definition: MultU64x32.c:27
UINT64 EFIAPI DivU64x32Remainder(IN UINT64 Dividend, IN UINT32 Divisor, OUT UINT32 *Remainder OPTIONAL)
BOOLEAN EFIAPI CompareGuid(IN CONST GUID *Guid1, IN CONST GUID *Guid2)
Definition: MemLibGuid.c:73
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
VOID EFIAPI FreePages(IN VOID *Buffer, IN UINTN Pages)
EFI_STATUS FatReadBlock(IN PEI_FAT_PRIVATE_DATA *PrivateData, IN UINTN BlockDeviceNo, IN EFI_PEI_LBA Lba, IN UINTN BufferSize, OUT VOID *Buffer)
Definition: FatLiteLib.c:54
BOOLEAN PartitionCheckGptHeader(IN PEI_FAT_PRIVATE_DATA *PrivateData, IN UINTN ParentBlockDevNo, IN BOOLEAN IsPrimaryHeader, IN EFI_PARTITION_TABLE_HEADER *PartHdr)
Definition: Gpt.c:104
BOOLEAN PartitionCheckGptStructure(IN PEI_FAT_PRIVATE_DATA *PrivateData, IN UINTN ParentBlockDevNo, IN BOOLEAN IsPrimary)
Definition: Gpt.c:365
BOOLEAN PartitionCheckGptEntryArrayCRC(IN EFI_PARTITION_TABLE_HEADER *PartHeader, IN EFI_PARTITION_ENTRY *PartEntry)
Definition: Gpt.c:77
BOOLEAN PartitionCheckGptHeaderCRC(IN EFI_PARTITION_TABLE_HEADER *PartHeader)
Definition: Gpt.c:41
BOOLEAN PartitionCheckGptEntryArray(IN PEI_FAT_PRIVATE_DATA *PrivateData, IN UINTN ParentBlockDevNo, IN EFI_PARTITION_TABLE_HEADER *PartHdr)
Definition: Gpt.c:185
BOOLEAN PartitionCheckProtectiveMbr(IN PEI_FAT_PRIVATE_DATA *PrivateData, IN UINTN ParentBlockDevNo)
Definition: Gpt.c:417
BOOLEAN FatFindGptPartitions(IN PEI_FAT_PRIVATE_DATA *PrivateData, IN UINTN ParentBlockDevNo)
Definition: Gpt.c:486
#define NULL
Definition: Base.h:319
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define DEBUG(Expression)
Definition: DebugLib.h:434
UINT64 EFI_PEI_LBA
Definition: BlockIo.h:41
VOID *EFIAPI AllocatePages(IN UINTN Pages)
UINT64 EFI_LBA
Definition: UefiBaseType.h:45
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SIZE_TO_PAGES(Size)
Definition: UefiBaseType.h:200
#define PRIMARY_PART_HEADER_LBA
Definition: UefiGpt.h:16
#define EFI_PTAB_HEADER_ID
Definition: UefiGpt.h:20
EFI_LBA EndingLBA
Definition: UefiGpt.h:105