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