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