]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Disk/PartitionDxe/Gpt.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Universal / Disk / PartitionDxe / Gpt.c
1 /** @file
2 Decode a hard disk partitioned with the GPT scheme in the UEFI 2.0
3 specification.
4
5 Caution: This file requires additional review when modified.
6 This driver will have external input - disk partition.
7 This external input must be validated carefully to avoid security issue like
8 buffer overflow, integer overflow.
9
10 PartitionInstallGptChildHandles() routine will read disk partition content and
11 do basic validation before PartitionInstallChildHandle().
12
13 PartitionValidGptTable(), PartitionCheckGptEntry() routine will accept disk
14 partition content and validate the GPT table and GPT entry.
15
16 Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
17 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
18 SPDX-License-Identifier: BSD-2-Clause-Patent
19
20 **/
21
22 #include "Partition.h"
23
24 /**
25 Install child handles if the Handle supports GPT partition structure.
26
27 Caution: This function may receive untrusted input.
28 The GPT partition table header is external input, so this routine
29 will do basic validation for GPT partition table header before return.
30
31 @param[in] BlockIo Parent BlockIo interface.
32 @param[in] DiskIo Disk Io protocol.
33 @param[in] Lba The starting Lba of the Partition Table
34 @param[out] PartHeader Stores the partition table that is read
35
36 @retval TRUE The partition table is valid
37 @retval FALSE The partition table is not valid
38
39 **/
40 BOOLEAN
41 PartitionValidGptTable (
42 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
43 IN EFI_DISK_IO_PROTOCOL *DiskIo,
44 IN EFI_LBA Lba,
45 OUT EFI_PARTITION_TABLE_HEADER *PartHeader
46 );
47
48 /**
49 Check if the CRC field in the Partition table header is valid
50 for Partition entry array.
51
52 @param[in] BlockIo Parent BlockIo interface
53 @param[in] DiskIo Disk Io Protocol.
54 @param[in] PartHeader Partition table header structure
55
56 @retval TRUE the CRC is valid
57 @retval FALSE the CRC is invalid
58
59 **/
60 BOOLEAN
61 PartitionCheckGptEntryArrayCRC (
62 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
63 IN EFI_DISK_IO_PROTOCOL *DiskIo,
64 IN EFI_PARTITION_TABLE_HEADER *PartHeader
65 );
66
67 /**
68 Restore Partition Table to its alternate place
69 (Primary -> Backup or Backup -> Primary).
70
71 @param[in] BlockIo Parent BlockIo interface.
72 @param[in] DiskIo Disk Io Protocol.
73 @param[in] PartHeader Partition table header structure.
74
75 @retval TRUE Restoring succeeds
76 @retval FALSE Restoring failed
77
78 **/
79 BOOLEAN
80 PartitionRestoreGptTable (
81 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
82 IN EFI_DISK_IO_PROTOCOL *DiskIo,
83 IN EFI_PARTITION_TABLE_HEADER *PartHeader
84 );
85
86 /**
87 This routine will check GPT partition entry and return entry status.
88
89 Caution: This function may receive untrusted input.
90 The GPT partition entry is external input, so this routine
91 will do basic validation for GPT partition entry and report status.
92
93 @param[in] PartHeader Partition table header structure
94 @param[in] PartEntry The partition entry array
95 @param[out] PEntryStatus the partition entry status array
96 recording the status of each partition
97
98 **/
99 VOID
100 PartitionCheckGptEntry (
101 IN EFI_PARTITION_TABLE_HEADER *PartHeader,
102 IN EFI_PARTITION_ENTRY *PartEntry,
103 OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus
104 );
105
106 /**
107 Checks the CRC32 value in the table header.
108
109 @param MaxSize Max Size limit
110 @param Size The size of the table
111 @param Hdr Table to check
112
113 @return TRUE CRC Valid
114 @return FALSE CRC Invalid
115
116 **/
117 BOOLEAN
118 PartitionCheckCrcAltSize (
119 IN UINTN MaxSize,
120 IN UINTN Size,
121 IN OUT EFI_TABLE_HEADER *Hdr
122 );
123
124 /**
125 Checks the CRC32 value in the table header.
126
127 @param MaxSize Max Size limit
128 @param Hdr Table to check
129
130 @return TRUE CRC Valid
131 @return FALSE CRC Invalid
132
133 **/
134 BOOLEAN
135 PartitionCheckCrc (
136 IN UINTN MaxSize,
137 IN OUT EFI_TABLE_HEADER *Hdr
138 );
139
140 /**
141 Updates the CRC32 value in the table header.
142
143 @param Size The size of the table
144 @param Hdr Table to update
145
146 **/
147 VOID
148 PartitionSetCrcAltSize (
149 IN UINTN Size,
150 IN OUT EFI_TABLE_HEADER *Hdr
151 );
152
153 /**
154 Updates the CRC32 value in the table header.
155
156 @param Hdr Table to update
157
158 **/
159 VOID
160 PartitionSetCrc (
161 IN OUT EFI_TABLE_HEADER *Hdr
162 );
163
164 /**
165 Install child handles if the Handle supports GPT partition structure.
166
167 Caution: This function may receive untrusted input.
168 The GPT partition table is external input, so this routine
169 will do basic validation for GPT partition table before install
170 child handle for each GPT partition.
171
172 @param[in] This Calling context.
173 @param[in] Handle Parent Handle.
174 @param[in] DiskIo Parent DiskIo interface.
175 @param[in] DiskIo2 Parent DiskIo2 interface.
176 @param[in] BlockIo Parent BlockIo interface.
177 @param[in] BlockIo2 Parent BlockIo2 interface.
178 @param[in] DevicePath Parent Device Path.
179
180 @retval EFI_SUCCESS Valid GPT disk.
181 @retval EFI_MEDIA_CHANGED Media changed Detected.
182 @retval other Not a valid GPT disk.
183
184 **/
185 EFI_STATUS
186 PartitionInstallGptChildHandles (
187 IN EFI_DRIVER_BINDING_PROTOCOL *This,
188 IN EFI_HANDLE Handle,
189 IN EFI_DISK_IO_PROTOCOL *DiskIo,
190 IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
191 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
192 IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
193 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
194 )
195 {
196 EFI_STATUS Status;
197 UINT32 BlockSize;
198 EFI_LBA LastBlock;
199 MASTER_BOOT_RECORD *ProtectiveMbr;
200 EFI_PARTITION_TABLE_HEADER *PrimaryHeader;
201 EFI_PARTITION_TABLE_HEADER *BackupHeader;
202 EFI_PARTITION_ENTRY *PartEntry;
203 EFI_PARTITION_ENTRY *Entry;
204 EFI_PARTITION_ENTRY_STATUS *PEntryStatus;
205 UINTN Index;
206 EFI_STATUS GptValidStatus;
207 HARDDRIVE_DEVICE_PATH HdDev;
208 UINT32 MediaId;
209 EFI_PARTITION_INFO_PROTOCOL PartitionInfo;
210
211 ProtectiveMbr = NULL;
212 PrimaryHeader = NULL;
213 BackupHeader = NULL;
214 PartEntry = NULL;
215 PEntryStatus = NULL;
216
217 BlockSize = BlockIo->Media->BlockSize;
218 LastBlock = BlockIo->Media->LastBlock;
219 MediaId = BlockIo->Media->MediaId;
220
221 DEBUG ((DEBUG_INFO, " BlockSize : %d \n", BlockSize));
222 DEBUG ((DEBUG_INFO, " LastBlock : %lx \n", LastBlock));
223
224 GptValidStatus = EFI_NOT_FOUND;
225
226 //
227 // Ensure the block size can hold the MBR
228 //
229 if (BlockSize < sizeof (MASTER_BOOT_RECORD)) {
230 return EFI_NOT_FOUND;
231 }
232
233 //
234 // Allocate a buffer for the Protective MBR
235 //
236 ProtectiveMbr = AllocatePool (BlockSize);
237 if (ProtectiveMbr == NULL) {
238 return EFI_NOT_FOUND;
239 }
240
241 //
242 // Read the Protective MBR from LBA #0
243 //
244 Status = DiskIo->ReadDisk (
245 DiskIo,
246 MediaId,
247 0,
248 BlockSize,
249 ProtectiveMbr
250 );
251 if (EFI_ERROR (Status)) {
252 GptValidStatus = Status;
253 goto Done;
254 }
255
256 //
257 // Verify that the Protective MBR is valid
258 //
259 for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
260 if ((ProtectiveMbr->Partition[Index].OSIndicator == PMBR_GPT_PARTITION) &&
261 (UNPACK_UINT32 (ProtectiveMbr->Partition[Index].StartingLBA) == 1)
262 )
263 {
264 break;
265 }
266 }
267
268 if (Index == MAX_MBR_PARTITIONS) {
269 goto Done;
270 }
271
272 //
273 // Allocate the GPT structures
274 //
275 PrimaryHeader = AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER));
276 if (PrimaryHeader == NULL) {
277 goto Done;
278 }
279
280 BackupHeader = AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER));
281 if (BackupHeader == NULL) {
282 goto Done;
283 }
284
285 //
286 // Check primary and backup partition tables
287 //
288 if (!PartitionValidGptTable (BlockIo, DiskIo, PRIMARY_PART_HEADER_LBA, PrimaryHeader)) {
289 DEBUG ((DEBUG_INFO, " Not Valid primary partition table\n"));
290
291 if (!PartitionValidGptTable (BlockIo, DiskIo, LastBlock, BackupHeader)) {
292 DEBUG ((DEBUG_INFO, " Not Valid backup partition table\n"));
293 goto Done;
294 } else {
295 DEBUG ((DEBUG_INFO, " Valid backup partition table\n"));
296 DEBUG ((DEBUG_INFO, " Restore primary partition table by the backup\n"));
297 if (!PartitionRestoreGptTable (BlockIo, DiskIo, BackupHeader)) {
298 DEBUG ((DEBUG_INFO, " Restore primary partition table error\n"));
299 }
300
301 if (PartitionValidGptTable (BlockIo, DiskIo, BackupHeader->AlternateLBA, PrimaryHeader)) {
302 DEBUG ((DEBUG_INFO, " Restore backup partition table success\n"));
303 }
304 }
305 } else if (!PartitionValidGptTable (BlockIo, DiskIo, PrimaryHeader->AlternateLBA, BackupHeader)) {
306 DEBUG ((DEBUG_INFO, " Valid primary and !Valid backup partition table\n"));
307 DEBUG ((DEBUG_INFO, " Restore backup partition table by the primary\n"));
308 if (!PartitionRestoreGptTable (BlockIo, DiskIo, PrimaryHeader)) {
309 DEBUG ((DEBUG_INFO, " Restore backup partition table error\n"));
310 }
311
312 if (PartitionValidGptTable (BlockIo, DiskIo, PrimaryHeader->AlternateLBA, BackupHeader)) {
313 DEBUG ((DEBUG_INFO, " Restore backup partition table success\n"));
314 }
315 }
316
317 DEBUG ((DEBUG_INFO, " Valid primary and Valid backup partition table\n"));
318
319 //
320 // Read the EFI Partition Entries
321 //
322 PartEntry = AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry);
323 if (PartEntry == NULL) {
324 DEBUG ((DEBUG_ERROR, "Allocate pool error\n"));
325 goto Done;
326 }
327
328 Status = DiskIo->ReadDisk (
329 DiskIo,
330 MediaId,
331 MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockSize),
332 PrimaryHeader->NumberOfPartitionEntries * (PrimaryHeader->SizeOfPartitionEntry),
333 PartEntry
334 );
335 if (EFI_ERROR (Status)) {
336 GptValidStatus = Status;
337 DEBUG ((DEBUG_ERROR, " Partition Entry ReadDisk error\n"));
338 goto Done;
339 }
340
341 DEBUG ((DEBUG_INFO, " Partition entries read block success\n"));
342
343 DEBUG ((DEBUG_INFO, " Number of partition entries: %d\n", PrimaryHeader->NumberOfPartitionEntries));
344
345 PEntryStatus = AllocateZeroPool (PrimaryHeader->NumberOfPartitionEntries * sizeof (EFI_PARTITION_ENTRY_STATUS));
346 if (PEntryStatus == NULL) {
347 DEBUG ((DEBUG_ERROR, "Allocate pool error\n"));
348 goto Done;
349 }
350
351 //
352 // Check the integrity of partition entries
353 //
354 PartitionCheckGptEntry (PrimaryHeader, PartEntry, PEntryStatus);
355
356 //
357 // If we got this far the GPT layout of the disk is valid and we should return true
358 //
359 GptValidStatus = EFI_SUCCESS;
360
361 //
362 // Create child device handles
363 //
364 for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {
365 Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index * PrimaryHeader->SizeOfPartitionEntry);
366 if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid) ||
367 PEntryStatus[Index].OutOfRange ||
368 PEntryStatus[Index].Overlap ||
369 PEntryStatus[Index].OsSpecific
370 )
371 {
372 //
373 // Don't use null EFI Partition Entries, Invalid Partition Entries or OS specific
374 // partition Entries
375 //
376 continue;
377 }
378
379 ZeroMem (&HdDev, sizeof (HdDev));
380 HdDev.Header.Type = MEDIA_DEVICE_PATH;
381 HdDev.Header.SubType = MEDIA_HARDDRIVE_DP;
382 SetDevicePathNodeLength (&HdDev.Header, sizeof (HdDev));
383
384 HdDev.PartitionNumber = (UINT32)Index + 1;
385 HdDev.MBRType = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
386 HdDev.SignatureType = SIGNATURE_TYPE_GUID;
387 HdDev.PartitionStart = Entry->StartingLBA;
388 HdDev.PartitionSize = Entry->EndingLBA - Entry->StartingLBA + 1;
389 CopyMem (HdDev.Signature, &Entry->UniquePartitionGUID, sizeof (EFI_GUID));
390
391 ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
392 PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
393 PartitionInfo.Type = PARTITION_TYPE_GPT;
394 if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeSystemPartGuid)) {
395 PartitionInfo.System = 1;
396 }
397
398 CopyMem (&PartitionInfo.Info.Gpt, Entry, sizeof (EFI_PARTITION_ENTRY));
399
400 DEBUG ((DEBUG_INFO, " Index : %d\n", (UINT32)Index));
401 DEBUG ((DEBUG_INFO, " Start LBA : %lx\n", (UINT64)HdDev.PartitionStart));
402 DEBUG ((DEBUG_INFO, " End LBA : %lx\n", (UINT64)Entry->EndingLBA));
403 DEBUG ((DEBUG_INFO, " Partition size: %lx\n", (UINT64)HdDev.PartitionSize));
404 DEBUG ((DEBUG_INFO, " Start : %lx", MultU64x32 (Entry->StartingLBA, BlockSize)));
405 DEBUG ((DEBUG_INFO, " End : %lx\n", MultU64x32 (Entry->EndingLBA, BlockSize)));
406
407 Status = PartitionInstallChildHandle (
408 This,
409 Handle,
410 DiskIo,
411 DiskIo2,
412 BlockIo,
413 BlockIo2,
414 DevicePath,
415 (EFI_DEVICE_PATH_PROTOCOL *)&HdDev,
416 &PartitionInfo,
417 Entry->StartingLBA,
418 Entry->EndingLBA,
419 BlockSize,
420 &Entry->PartitionTypeGUID
421 );
422 }
423
424 DEBUG ((DEBUG_INFO, "Prepare to Free Pool\n"));
425
426 Done:
427 if (ProtectiveMbr != NULL) {
428 FreePool (ProtectiveMbr);
429 }
430
431 if (PrimaryHeader != NULL) {
432 FreePool (PrimaryHeader);
433 }
434
435 if (BackupHeader != NULL) {
436 FreePool (BackupHeader);
437 }
438
439 if (PartEntry != NULL) {
440 FreePool (PartEntry);
441 }
442
443 if (PEntryStatus != NULL) {
444 FreePool (PEntryStatus);
445 }
446
447 return GptValidStatus;
448 }
449
450 /**
451 This routine will read GPT partition table header and return it.
452
453 Caution: This function may receive untrusted input.
454 The GPT partition table header is external input, so this routine
455 will do basic validation for GPT partition table header before return.
456
457 @param[in] BlockIo Parent BlockIo interface.
458 @param[in] DiskIo Disk Io protocol.
459 @param[in] Lba The starting Lba of the Partition Table
460 @param[out] PartHeader Stores the partition table that is read
461
462 @retval TRUE The partition table is valid
463 @retval FALSE The partition table is not valid
464
465 **/
466 BOOLEAN
467 PartitionValidGptTable (
468 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
469 IN EFI_DISK_IO_PROTOCOL *DiskIo,
470 IN EFI_LBA Lba,
471 OUT EFI_PARTITION_TABLE_HEADER *PartHeader
472 )
473 {
474 EFI_STATUS Status;
475 UINT32 BlockSize;
476 EFI_PARTITION_TABLE_HEADER *PartHdr;
477 UINT32 MediaId;
478
479 BlockSize = BlockIo->Media->BlockSize;
480 MediaId = BlockIo->Media->MediaId;
481 PartHdr = AllocateZeroPool (BlockSize);
482
483 if (PartHdr == NULL) {
484 DEBUG ((DEBUG_ERROR, "Allocate pool error\n"));
485 return FALSE;
486 }
487
488 //
489 // Read the EFI Partition Table Header
490 //
491 Status = DiskIo->ReadDisk (
492 DiskIo,
493 MediaId,
494 MultU64x32 (Lba, BlockSize),
495 BlockSize,
496 PartHdr
497 );
498 if (EFI_ERROR (Status)) {
499 FreePool (PartHdr);
500 return FALSE;
501 }
502
503 if ((PartHdr->Header.Signature != EFI_PTAB_HEADER_ID) ||
504 !PartitionCheckCrc (BlockSize, &PartHdr->Header) ||
505 (PartHdr->MyLBA != Lba) ||
506 (PartHdr->SizeOfPartitionEntry < sizeof (EFI_PARTITION_ENTRY))
507 )
508 {
509 DEBUG ((DEBUG_INFO, "Invalid efi partition table header\n"));
510 FreePool (PartHdr);
511 return FALSE;
512 }
513
514 //
515 // Ensure the NumberOfPartitionEntries * SizeOfPartitionEntry doesn't overflow.
516 //
517 if (PartHdr->NumberOfPartitionEntries > DivU64x32 (MAX_UINTN, PartHdr->SizeOfPartitionEntry)) {
518 FreePool (PartHdr);
519 return FALSE;
520 }
521
522 CopyMem (PartHeader, PartHdr, sizeof (EFI_PARTITION_TABLE_HEADER));
523 if (!PartitionCheckGptEntryArrayCRC (BlockIo, DiskIo, PartHeader)) {
524 FreePool (PartHdr);
525 return FALSE;
526 }
527
528 DEBUG ((DEBUG_INFO, " Valid efi partition table header\n"));
529 FreePool (PartHdr);
530 return TRUE;
531 }
532
533 /**
534 Check if the CRC field in the Partition table header is valid
535 for Partition entry array.
536
537 @param[in] BlockIo Parent BlockIo interface
538 @param[in] DiskIo Disk Io Protocol.
539 @param[in] PartHeader Partition table header structure
540
541 @retval TRUE the CRC is valid
542 @retval FALSE the CRC is invalid
543
544 **/
545 BOOLEAN
546 PartitionCheckGptEntryArrayCRC (
547 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
548 IN EFI_DISK_IO_PROTOCOL *DiskIo,
549 IN EFI_PARTITION_TABLE_HEADER *PartHeader
550 )
551 {
552 EFI_STATUS Status;
553 UINT8 *Ptr;
554 UINT32 Crc;
555 UINTN Size;
556
557 //
558 // Read the EFI Partition Entries
559 //
560 Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry);
561 if (Ptr == NULL) {
562 DEBUG ((DEBUG_ERROR, " Allocate pool error\n"));
563 return FALSE;
564 }
565
566 Status = DiskIo->ReadDisk (
567 DiskIo,
568 BlockIo->Media->MediaId,
569 MultU64x32 (PartHeader->PartitionEntryLBA, BlockIo->Media->BlockSize),
570 PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
571 Ptr
572 );
573 if (EFI_ERROR (Status)) {
574 FreePool (Ptr);
575 return FALSE;
576 }
577
578 Size = PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry;
579
580 Status = gBS->CalculateCrc32 (Ptr, Size, &Crc);
581 if (EFI_ERROR (Status)) {
582 DEBUG ((DEBUG_ERROR, "CheckPEntryArrayCRC: Crc calculation failed\n"));
583 FreePool (Ptr);
584 return FALSE;
585 }
586
587 FreePool (Ptr);
588
589 return (BOOLEAN)(PartHeader->PartitionEntryArrayCRC32 == Crc);
590 }
591
592 /**
593 Restore Partition Table to its alternate place
594 (Primary -> Backup or Backup -> Primary).
595
596 @param[in] BlockIo Parent BlockIo interface.
597 @param[in] DiskIo Disk Io Protocol.
598 @param[in] PartHeader Partition table header structure.
599
600 @retval TRUE Restoring succeeds
601 @retval FALSE Restoring failed
602
603 **/
604 BOOLEAN
605 PartitionRestoreGptTable (
606 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
607 IN EFI_DISK_IO_PROTOCOL *DiskIo,
608 IN EFI_PARTITION_TABLE_HEADER *PartHeader
609 )
610 {
611 EFI_STATUS Status;
612 UINTN BlockSize;
613 EFI_PARTITION_TABLE_HEADER *PartHdr;
614 EFI_LBA PEntryLBA;
615 UINT8 *Ptr;
616 UINT32 MediaId;
617
618 PartHdr = NULL;
619 Ptr = NULL;
620
621 BlockSize = BlockIo->Media->BlockSize;
622 MediaId = BlockIo->Media->MediaId;
623
624 PartHdr = AllocateZeroPool (BlockSize);
625
626 if (PartHdr == NULL) {
627 DEBUG ((DEBUG_ERROR, "Allocate pool error\n"));
628 return FALSE;
629 }
630
631 PEntryLBA = (PartHeader->MyLBA == PRIMARY_PART_HEADER_LBA) ? \
632 (PartHeader->LastUsableLBA + 1) : \
633 (PRIMARY_PART_HEADER_LBA + 1);
634
635 CopyMem (PartHdr, PartHeader, sizeof (EFI_PARTITION_TABLE_HEADER));
636
637 PartHdr->MyLBA = PartHeader->AlternateLBA;
638 PartHdr->AlternateLBA = PartHeader->MyLBA;
639 PartHdr->PartitionEntryLBA = PEntryLBA;
640 PartitionSetCrc ((EFI_TABLE_HEADER *)PartHdr);
641
642 Status = DiskIo->WriteDisk (
643 DiskIo,
644 MediaId,
645 MultU64x32 (PartHdr->MyLBA, (UINT32)BlockSize),
646 BlockSize,
647 PartHdr
648 );
649 if (EFI_ERROR (Status)) {
650 goto Done;
651 }
652
653 Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry);
654 if (Ptr == NULL) {
655 DEBUG ((DEBUG_ERROR, " Allocate pool error\n"));
656 Status = EFI_OUT_OF_RESOURCES;
657 goto Done;
658 }
659
660 Status = DiskIo->ReadDisk (
661 DiskIo,
662 MediaId,
663 MultU64x32 (PartHeader->PartitionEntryLBA, (UINT32)BlockSize),
664 PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
665 Ptr
666 );
667 if (EFI_ERROR (Status)) {
668 goto Done;
669 }
670
671 Status = DiskIo->WriteDisk (
672 DiskIo,
673 MediaId,
674 MultU64x32 (PEntryLBA, (UINT32)BlockSize),
675 PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
676 Ptr
677 );
678
679 Done:
680 FreePool (PartHdr);
681
682 if (Ptr != NULL) {
683 FreePool (Ptr);
684 }
685
686 if (EFI_ERROR (Status)) {
687 return FALSE;
688 }
689
690 return TRUE;
691 }
692
693 /**
694 This routine will check GPT partition entry and return entry status.
695
696 Caution: This function may receive untrusted input.
697 The GPT partition entry is external input, so this routine
698 will do basic validation for GPT partition entry and report status.
699
700 @param[in] PartHeader Partition table header structure
701 @param[in] PartEntry The partition entry array
702 @param[out] PEntryStatus the partition entry status array
703 recording the status of each partition
704
705 **/
706 VOID
707 PartitionCheckGptEntry (
708 IN EFI_PARTITION_TABLE_HEADER *PartHeader,
709 IN EFI_PARTITION_ENTRY *PartEntry,
710 OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus
711 )
712 {
713 EFI_LBA StartingLBA;
714 EFI_LBA EndingLBA;
715 EFI_PARTITION_ENTRY *Entry;
716 UINTN Index1;
717 UINTN Index2;
718
719 DEBUG ((DEBUG_INFO, " start check partition entries\n"));
720 for (Index1 = 0; Index1 < PartHeader->NumberOfPartitionEntries; Index1++) {
721 Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index1 * PartHeader->SizeOfPartitionEntry);
722 if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {
723 continue;
724 }
725
726 StartingLBA = Entry->StartingLBA;
727 EndingLBA = Entry->EndingLBA;
728 if ((StartingLBA > EndingLBA) ||
729 (StartingLBA < PartHeader->FirstUsableLBA) ||
730 (StartingLBA > PartHeader->LastUsableLBA) ||
731 (EndingLBA < PartHeader->FirstUsableLBA) ||
732 (EndingLBA > PartHeader->LastUsableLBA)
733 )
734 {
735 PEntryStatus[Index1].OutOfRange = TRUE;
736 continue;
737 }
738
739 if ((Entry->Attributes & BIT1) != 0) {
740 //
741 // If Bit 1 is set, this indicate that this is an OS specific GUID partition.
742 //
743 PEntryStatus[Index1].OsSpecific = TRUE;
744 }
745
746 for (Index2 = Index1 + 1; Index2 < PartHeader->NumberOfPartitionEntries; Index2++) {
747 Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index2 * PartHeader->SizeOfPartitionEntry);
748 if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {
749 continue;
750 }
751
752 if ((Entry->EndingLBA >= StartingLBA) && (Entry->StartingLBA <= EndingLBA)) {
753 //
754 // This region overlaps with the Index1'th region
755 //
756 PEntryStatus[Index1].Overlap = TRUE;
757 PEntryStatus[Index2].Overlap = TRUE;
758 continue;
759 }
760 }
761 }
762
763 DEBUG ((DEBUG_INFO, " End check partition entries\n"));
764 }
765
766 /**
767 Updates the CRC32 value in the table header.
768
769 @param Hdr Table to update
770
771 **/
772 VOID
773 PartitionSetCrc (
774 IN OUT EFI_TABLE_HEADER *Hdr
775 )
776 {
777 PartitionSetCrcAltSize (Hdr->HeaderSize, Hdr);
778 }
779
780 /**
781 Updates the CRC32 value in the table header.
782
783 @param Size The size of the table
784 @param Hdr Table to update
785
786 **/
787 VOID
788 PartitionSetCrcAltSize (
789 IN UINTN Size,
790 IN OUT EFI_TABLE_HEADER *Hdr
791 )
792 {
793 UINT32 Crc;
794
795 Hdr->CRC32 = 0;
796 gBS->CalculateCrc32 ((UINT8 *)Hdr, Size, &Crc);
797 Hdr->CRC32 = Crc;
798 }
799
800 /**
801 Checks the CRC32 value in the table header.
802
803 @param MaxSize Max Size limit
804 @param Hdr Table to check
805
806 @return TRUE CRC Valid
807 @return FALSE CRC Invalid
808
809 **/
810 BOOLEAN
811 PartitionCheckCrc (
812 IN UINTN MaxSize,
813 IN OUT EFI_TABLE_HEADER *Hdr
814 )
815 {
816 return PartitionCheckCrcAltSize (MaxSize, Hdr->HeaderSize, Hdr);
817 }
818
819 /**
820 Checks the CRC32 value in the table header.
821
822 @param MaxSize Max Size limit
823 @param Size The size of the table
824 @param Hdr Table to check
825
826 @return TRUE CRC Valid
827 @return FALSE CRC Invalid
828
829 **/
830 BOOLEAN
831 PartitionCheckCrcAltSize (
832 IN UINTN MaxSize,
833 IN UINTN Size,
834 IN OUT EFI_TABLE_HEADER *Hdr
835 )
836 {
837 UINT32 Crc;
838 UINT32 OrgCrc;
839 EFI_STATUS Status;
840
841 Crc = 0;
842
843 if (Size == 0) {
844 //
845 // If header size is 0 CRC will pass so return FALSE here
846 //
847 return FALSE;
848 }
849
850 if ((MaxSize != 0) && (Size > MaxSize)) {
851 DEBUG ((DEBUG_ERROR, "CheckCrc32: Size > MaxSize\n"));
852 return FALSE;
853 }
854
855 //
856 // clear old crc from header
857 //
858 OrgCrc = Hdr->CRC32;
859 Hdr->CRC32 = 0;
860
861 Status = gBS->CalculateCrc32 ((UINT8 *)Hdr, Size, &Crc);
862 if (EFI_ERROR (Status)) {
863 DEBUG ((DEBUG_ERROR, "CheckCrc32: Crc calculation failed\n"));
864 return FALSE;
865 }
866
867 //
868 // set results
869 //
870 Hdr->CRC32 = Crc;
871
872 //
873 // return status
874 //
875 DEBUG_CODE_BEGIN ();
876 if (OrgCrc != Crc) {
877 DEBUG ((DEBUG_ERROR, "CheckCrc32: Crc check failed\n"));
878 }
879
880 DEBUG_CODE_END ();
881
882 return (BOOLEAN)(OrgCrc == Crc);
883 }