2 Decode a hard disk partitioned with the GPT scheme in the UEFI 2.0
5 Copyright (c) 2006 - 2008, Intel Corporation. <BR>
6 All rights reserved. This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include "Partition.h"
21 Install child handles if the Handle supports GPT partition structure.
23 @param[in] BlockIo Parent BlockIo interface
24 @param[in] DiskIo Disk Io protocol.
25 @param[in] Lba The starting Lba of the Partition Table
26 @param[out] PartHeader Stores the partition table that is read
28 @retval TRUE The partition table is valid
29 @retval FALSE The partition table is not valid
33 PartitionValidGptTable (
34 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
35 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
37 OUT EFI_PARTITION_TABLE_HEADER
*PartHeader
42 Check if the CRC field in the Partition table header is valid
43 for Partition entry array.
45 @param[in] BlockIo Parent BlockIo interface
46 @param[in] DiskIo Disk Io Protocol.
47 @param[in] PartHeader Partition table header structure
49 @retval TRUE the CRC is valid
50 @retval FALSE the CRC is invalid
54 PartitionCheckGptEntryArrayCRC (
55 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
56 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
57 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
62 Restore Partition Table to its alternate place
63 (Primary -> Backup or Backup -> Primary)
65 @param[in] BlockIo Parent BlockIo interface
66 @param[in] DiskIo Disk Io Protocol.
67 @param[in] PartHeader Partition table header structure
69 @retval TRUE Restoring succeeds
70 @retval FALSE Restoring failed
74 PartitionRestoreGptTable (
75 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
76 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
77 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
82 Restore Partition Table to its alternate place
83 (Primary -> Backup or Backup -> Primary)
85 @param[in] PartHeader Partition table header structure
86 @param[in] PartEntry The partition entry array
87 @param[out] PEntryStatus the partition entry status array
88 recording the status of each partition
92 PartitionCheckGptEntry (
93 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
,
94 IN EFI_PARTITION_ENTRY
*PartEntry
,
95 OUT EFI_PARTITION_ENTRY_STATUS
*PEntryStatus
100 Checks the CRC32 value in the table header
102 @param MaxSize Max Size limit
103 @param Size The size of the table
104 @param Hdr Table to check
106 @return TRUE CRC Valid
107 @return FALSE CRC Invalid
111 PartitionCheckCrcAltSize (
114 IN OUT EFI_TABLE_HEADER
*Hdr
119 Checks the CRC32 value in the table header
121 @param MaxSize Max Size limit
122 @param Hdr Table to check
124 @return TRUE CRC Valid
125 @return FALSE CRC Invalid
131 IN OUT EFI_TABLE_HEADER
*Hdr
136 Updates the CRC32 value in the table header
138 @param Size The size of the table
139 @param Hdr Table to update
143 PartitionSetCrcAltSize (
145 IN OUT EFI_TABLE_HEADER
*Hdr
150 Updates the CRC32 value in the table header
152 @param Hdr Table to update
157 IN OUT EFI_TABLE_HEADER
*Hdr
161 Install child handles if the Handle supports GPT partition structure.
163 @param[in] This - Calling context.
164 @param[in] Handle - Parent Handle
165 @param[in] DiskIo - Parent DiskIo interface
166 @param[in] BlockIo - Parent BlockIo interface
167 @param[in] DevicePath - Parent Device Path
169 @retval EFI_SUCCESS Valid GPT disk
170 @retval EFI_MEDIA_CHANGED Media changed Detected
171 @retval other Not a valid GPT disk
175 PartitionInstallGptChildHandles (
176 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
177 IN EFI_HANDLE Handle
,
178 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
179 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
180 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
186 MASTER_BOOT_RECORD
*ProtectiveMbr
;
187 EFI_PARTITION_TABLE_HEADER
*PrimaryHeader
;
188 EFI_PARTITION_TABLE_HEADER
*BackupHeader
;
189 EFI_PARTITION_ENTRY
*PartEntry
;
190 EFI_PARTITION_ENTRY_STATUS
*PEntryStatus
;
193 HARDDRIVE_DEVICE_PATH HdDev
;
195 ProtectiveMbr
= NULL
;
196 PrimaryHeader
= NULL
;
201 BlockSize
= BlockIo
->Media
->BlockSize
;
202 LastBlock
= BlockIo
->Media
->LastBlock
;
204 DEBUG ((EFI_D_INFO
, " BlockSize : %d \n", BlockSize
));
205 DEBUG ((EFI_D_INFO
, " LastBlock : %x \n", LastBlock
));
207 GptValid
= EFI_NOT_FOUND
;
210 // Allocate a buffer for the Protective MBR
212 ProtectiveMbr
= AllocatePool (BlockSize
);
213 if (ProtectiveMbr
== NULL
) {
214 return EFI_NOT_FOUND
;
218 // Read the Protective MBR from LBA #0
220 Status
= BlockIo
->ReadBlocks (
222 BlockIo
->Media
->MediaId
,
224 BlockIo
->Media
->BlockSize
,
227 if (EFI_ERROR (Status
)) {
232 // Verify that the Protective MBR is valid
234 if (ProtectiveMbr
->Partition
[0].BootIndicator
!= 0x00 ||
235 ProtectiveMbr
->Partition
[0].OSIndicator
!= PMBR_GPT_PARTITION
||
236 UNPACK_UINT32 (ProtectiveMbr
->Partition
[0].StartingLBA
) != 1
242 // Allocate the GPT structures
244 PrimaryHeader
= AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER
));
245 if (PrimaryHeader
== NULL
) {
249 BackupHeader
= AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER
));
251 if (BackupHeader
== NULL
) {
256 // Check primary and backup partition tables
258 if (!PartitionValidGptTable (BlockIo
, DiskIo
, PRIMARY_PART_HEADER_LBA
, PrimaryHeader
)) {
259 DEBUG ((EFI_D_INFO
, " Not Valid primary partition table\n"));
261 if (!PartitionValidGptTable (BlockIo
, DiskIo
, LastBlock
, BackupHeader
)) {
262 DEBUG ((EFI_D_INFO
, " Not Valid backup partition table\n"));
265 DEBUG ((EFI_D_INFO
, " Valid backup partition table\n"));
266 DEBUG ((EFI_D_INFO
, " Restore primary partition table by the backup\n"));
267 if (!PartitionRestoreGptTable (BlockIo
, DiskIo
, BackupHeader
)) {
268 DEBUG ((EFI_D_INFO
, " Restore primary partition table error\n"));
271 if (PartitionValidGptTable (BlockIo
, DiskIo
, BackupHeader
->AlternateLBA
, PrimaryHeader
)) {
272 DEBUG ((EFI_D_INFO
, " Restore backup partition table success\n"));
275 } else if (!PartitionValidGptTable (BlockIo
, DiskIo
, PrimaryHeader
->AlternateLBA
, BackupHeader
)) {
276 DEBUG ((EFI_D_INFO
, " Valid primary and !Valid backup partition table\n"));
277 DEBUG ((EFI_D_INFO
, " Restore backup partition table by the primary\n"));
278 if (!PartitionRestoreGptTable (BlockIo
, DiskIo
, PrimaryHeader
)) {
279 DEBUG ((EFI_D_INFO
, " Restore backup partition table error\n"));
282 if (PartitionValidGptTable (BlockIo
, DiskIo
, PrimaryHeader
->AlternateLBA
, BackupHeader
)) {
283 DEBUG ((EFI_D_INFO
, " Restore backup partition table success\n"));
288 DEBUG ((EFI_D_INFO
, " Valid primary and Valid backup partition table\n"));
291 // Read the EFI Partition Entries
293 PartEntry
= AllocatePool (PrimaryHeader
->NumberOfPartitionEntries
* sizeof (EFI_PARTITION_ENTRY
));
294 if (PartEntry
== NULL
) {
295 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
299 Status
= DiskIo
->ReadDisk (
301 BlockIo
->Media
->MediaId
,
302 MultU64x32(PrimaryHeader
->PartitionEntryLBA
, BlockSize
),
303 PrimaryHeader
->NumberOfPartitionEntries
* (PrimaryHeader
->SizeOfPartitionEntry
),
306 if (EFI_ERROR (Status
)) {
308 DEBUG ((EFI_D_INFO
, " Partition Entry ReadBlocks error\n"));
312 DEBUG ((EFI_D_INFO
, " Partition entries read block success\n"));
314 DEBUG ((EFI_D_INFO
, " Number of partition entries: %d\n", PrimaryHeader
->NumberOfPartitionEntries
));
316 PEntryStatus
= AllocateZeroPool (PrimaryHeader
->NumberOfPartitionEntries
* sizeof (EFI_PARTITION_ENTRY_STATUS
));
317 if (PEntryStatus
== NULL
) {
318 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
323 // Check the integrity of partition entries
325 PartitionCheckGptEntry (PrimaryHeader
, PartEntry
, PEntryStatus
);
328 // If we got this far the GPT layout of the disk is valid and we should return true
330 GptValid
= EFI_SUCCESS
;
333 // Create child device handles
335 for (Index
= 0; Index
< PrimaryHeader
->NumberOfPartitionEntries
; Index
++) {
336 if (CompareGuid (&PartEntry
[Index
].PartitionTypeGUID
, &gEfiPartTypeUnusedGuid
) ||
337 PEntryStatus
[Index
].OutOfRange
||
338 PEntryStatus
[Index
].Overlap
341 // Don't use null EFI Partition Entries or Invalid Partition Entries
346 ZeroMem (&HdDev
, sizeof (HdDev
));
347 HdDev
.Header
.Type
= MEDIA_DEVICE_PATH
;
348 HdDev
.Header
.SubType
= MEDIA_HARDDRIVE_DP
;
349 SetDevicePathNodeLength (&HdDev
.Header
, sizeof (HdDev
));
351 HdDev
.PartitionNumber
= (UINT32
) Index
+ 1;
352 HdDev
.MBRType
= MBR_TYPE_EFI_PARTITION_TABLE_HEADER
;
353 HdDev
.SignatureType
= SIGNATURE_TYPE_GUID
;
354 HdDev
.PartitionStart
= PartEntry
[Index
].StartingLBA
;
355 HdDev
.PartitionSize
= PartEntry
[Index
].EndingLBA
- PartEntry
[Index
].StartingLBA
+ 1;
356 CopyMem (HdDev
.Signature
, &PartEntry
[Index
].UniquePartitionGUID
, sizeof (EFI_GUID
));
358 DEBUG ((EFI_D_INFO
, " Index : %d\n", Index
));
359 DEBUG ((EFI_D_INFO
, " Start LBA : %x\n", HdDev
.PartitionStart
));
360 DEBUG ((EFI_D_INFO
, " End LBA : %x\n", PartEntry
[Index
].EndingLBA
));
361 DEBUG ((EFI_D_INFO
, " Partition size: %x\n", HdDev
.PartitionSize
));
362 DEBUG ((EFI_D_INFO
, " Start : %x", MultU64x32 (PartEntry
[Index
].StartingLBA
, BlockSize
)));
363 DEBUG ((EFI_D_INFO
, " End : %x\n", MultU64x32 (PartEntry
[Index
].EndingLBA
, BlockSize
)));
365 Status
= PartitionInstallChildHandle (
371 (EFI_DEVICE_PATH_PROTOCOL
*) &HdDev
,
372 PartEntry
[Index
].StartingLBA
,
373 PartEntry
[Index
].EndingLBA
,
375 CompareGuid(&PartEntry
[Index
].PartitionTypeGUID
, &gEfiPartTypeSystemPartGuid
)
379 DEBUG ((EFI_D_INFO
, "Prepare to Free Pool\n"));
382 if (ProtectiveMbr
!= NULL
) {
383 FreePool (ProtectiveMbr
);
385 if (PrimaryHeader
!= NULL
) {
386 FreePool (PrimaryHeader
);
388 if (BackupHeader
!= NULL
) {
389 FreePool (BackupHeader
);
391 if (PartEntry
!= NULL
) {
392 FreePool (PartEntry
);
394 if (PEntryStatus
!= NULL
) {
395 FreePool (PEntryStatus
);
403 Install child handles if the Handle supports GPT partition structure.
405 @param[in] BlockIo Parent BlockIo interface
406 @param[in] DiskIo Disk Io protocol.
407 @param[in] Lba The starting Lba of the Partition Table
408 @param[out] PartHeader Stores the partition table that is read
410 @retval TRUE The partition table is valid
411 @retval FALSE The partition table is not valid
415 PartitionValidGptTable (
416 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
417 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
419 OUT EFI_PARTITION_TABLE_HEADER
*PartHeader
424 EFI_PARTITION_TABLE_HEADER
*PartHdr
;
426 BlockSize
= BlockIo
->Media
->BlockSize
;
428 PartHdr
= AllocateZeroPool (BlockSize
);
430 if (PartHdr
== NULL
) {
431 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
435 // Read the EFI Partition Table Header
437 Status
= BlockIo
->ReadBlocks (
439 BlockIo
->Media
->MediaId
,
444 if (EFI_ERROR (Status
)) {
449 if ((PartHdr
->Header
.Signature
!= EFI_PTAB_HEADER_ID
) ||
450 !PartitionCheckCrc (BlockSize
, &PartHdr
->Header
) ||
451 PartHdr
->MyLBA
!= Lba
453 DEBUG ((EFI_D_INFO
, " !Valid efi partition table header\n"));
458 CopyMem (PartHeader
, PartHdr
, sizeof (EFI_PARTITION_TABLE_HEADER
));
459 if (!PartitionCheckGptEntryArrayCRC (BlockIo
, DiskIo
, PartHeader
)) {
464 DEBUG ((EFI_D_INFO
, " Valid efi partition table header\n"));
471 Check if the CRC field in the Partition table header is valid
472 for Partition entry array.
474 @param[in] BlockIo Parent BlockIo interface
475 @param[in] DiskIo Disk Io Protocol.
476 @param[in] PartHeader Partition table header structure
478 @retval TRUE the CRC is valid
479 @retval FALSE the CRC is invalid
483 PartitionCheckGptEntryArrayCRC (
484 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
485 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
486 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
495 // Read the EFI Partition Entries
497 Ptr
= AllocatePool (PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
);
499 DEBUG ((EFI_D_ERROR
, " Allocate pool error\n"));
503 Status
= DiskIo
->ReadDisk (
505 BlockIo
->Media
->MediaId
,
506 MultU64x32(PartHeader
->PartitionEntryLBA
, BlockIo
->Media
->BlockSize
),
507 PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
,
510 if (EFI_ERROR (Status
)) {
515 Size
= PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
;
517 Status
= gBS
->CalculateCrc32 (Ptr
, Size
, &Crc
);
518 if (EFI_ERROR (Status
)) {
519 DEBUG ((EFI_D_ERROR
, "CheckPEntryArrayCRC: Crc calculation failed\n"));
526 return (BOOLEAN
) (PartHeader
->PartitionEntryArrayCRC32
== Crc
);
531 Restore Partition Table to its alternate place
532 (Primary -> Backup or Backup -> Primary)
534 @param[in] BlockIo Parent BlockIo interface
535 @param[in] DiskIo Disk Io Protocol.
536 @param[in] PartHeader Partition table header structure
538 @retval TRUE Restoring succeeds
539 @retval FALSE Restoring failed
543 PartitionRestoreGptTable (
544 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
545 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
546 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
551 EFI_PARTITION_TABLE_HEADER
*PartHdr
;
558 BlockSize
= BlockIo
->Media
->BlockSize
;
560 PartHdr
= AllocateZeroPool (BlockSize
);
562 if (PartHdr
== NULL
) {
563 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
567 PEntryLBA
= (PartHeader
->MyLBA
== PRIMARY_PART_HEADER_LBA
) ? \
568 (PartHeader
->LastUsableLBA
+ 1) : \
569 (PRIMARY_PART_HEADER_LBA
+ 1);
571 CopyMem (PartHdr
, PartHeader
, sizeof (EFI_PARTITION_TABLE_HEADER
));
573 PartHdr
->MyLBA
= PartHeader
->AlternateLBA
;
574 PartHdr
->AlternateLBA
= PartHeader
->MyLBA
;
575 PartHdr
->PartitionEntryLBA
= PEntryLBA
;
576 PartitionSetCrc ((EFI_TABLE_HEADER
*) PartHdr
);
578 Status
= BlockIo
->WriteBlocks (BlockIo
, BlockIo
->Media
->MediaId
, PartHdr
->MyLBA
, BlockSize
, PartHdr
);
579 if (EFI_ERROR (Status
)) {
583 Ptr
= AllocatePool (PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
);
585 DEBUG ((EFI_D_ERROR
, " Allocate pool effor\n"));
586 Status
= EFI_OUT_OF_RESOURCES
;
590 Status
= DiskIo
->ReadDisk (
592 BlockIo
->Media
->MediaId
,
593 MultU64x32(PartHeader
->PartitionEntryLBA
, BlockIo
->Media
->BlockSize
),
594 PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
,
597 if (EFI_ERROR (Status
)) {
601 Status
= DiskIo
->WriteDisk (
603 BlockIo
->Media
->MediaId
,
604 MultU64x32(PEntryLBA
, BlockIo
->Media
->BlockSize
),
605 PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
,
613 if (EFI_ERROR (Status
)) {
622 Restore Partition Table to its alternate place
623 (Primary -> Backup or Backup -> Primary)
625 @param[in] PartHeader Partition table header structure
626 @param[in] PartEntry The partition entry array
627 @param[out] PEntryStatus the partition entry status array
628 recording the status of each partition
632 PartitionCheckGptEntry (
633 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
,
634 IN EFI_PARTITION_ENTRY
*PartEntry
,
635 OUT EFI_PARTITION_ENTRY_STATUS
*PEntryStatus
643 DEBUG ((EFI_D_INFO
, " start check partition entries\n"));
644 for (Index1
= 0; Index1
< PartHeader
->NumberOfPartitionEntries
; Index1
++) {
645 if (CompareGuid (&PartEntry
[Index1
].PartitionTypeGUID
, &gEfiPartTypeUnusedGuid
)) {
649 StartingLBA
= PartEntry
[Index1
].StartingLBA
;
650 EndingLBA
= PartEntry
[Index1
].EndingLBA
;
651 if (StartingLBA
> EndingLBA
||
652 StartingLBA
< PartHeader
->FirstUsableLBA
||
653 StartingLBA
> PartHeader
->LastUsableLBA
||
654 EndingLBA
< PartHeader
->FirstUsableLBA
||
655 EndingLBA
> PartHeader
->LastUsableLBA
657 PEntryStatus
[Index1
].OutOfRange
= TRUE
;
661 for (Index2
= Index1
+ 1; Index2
< PartHeader
->NumberOfPartitionEntries
; Index2
++) {
663 if (CompareGuid (&PartEntry
[Index2
].PartitionTypeGUID
, &gEfiPartTypeUnusedGuid
)) {
667 if (PartEntry
[Index2
].EndingLBA
>= StartingLBA
&& PartEntry
[Index2
].StartingLBA
<= EndingLBA
) {
669 // This region overlaps with the Index1'th region
671 PEntryStatus
[Index1
].Overlap
= TRUE
;
672 PEntryStatus
[Index2
].Overlap
= TRUE
;
679 DEBUG ((EFI_D_INFO
, " End check partition entries\n"));
684 Updates the CRC32 value in the table header
686 @param Hdr Table to update
691 IN OUT EFI_TABLE_HEADER
*Hdr
694 PartitionSetCrcAltSize (Hdr
->HeaderSize
, Hdr
);
699 Updates the CRC32 value in the table header
701 @param Size The size of the table
702 @param Hdr Table to update
706 PartitionSetCrcAltSize (
708 IN OUT EFI_TABLE_HEADER
*Hdr
715 gBS
->CalculateCrc32 ((UINT8
*) Hdr
, Size
, &Crc
);
721 Checks the CRC32 value in the table header
723 @param MaxSize Max Size limit
724 @param Hdr Table to check
726 @return TRUE CRC Valid
727 @return FALSE CRC Invalid
733 IN OUT EFI_TABLE_HEADER
*Hdr
736 return PartitionCheckCrcAltSize (MaxSize
, Hdr
->HeaderSize
, Hdr
);
741 Checks the CRC32 value in the table header
743 @param MaxSize Max Size limit
744 @param Size The size of the table
745 @param Hdr Table to check
747 @return TRUE CRC Valid
748 @return FALSE CRC Invalid
752 PartitionCheckCrcAltSize (
755 IN OUT EFI_TABLE_HEADER
*Hdr
766 // If header size is 0 CRC will pass so return FALSE here
771 if (MaxSize
&& Size
> MaxSize
) {
772 DEBUG ((EFI_D_ERROR
, "CheckCrc32: Size > MaxSize\n"));
776 // clear old crc from header
781 Status
= gBS
->CalculateCrc32 ((UINT8
*) Hdr
, Size
, &Crc
);
782 if (EFI_ERROR (Status
)) {
783 DEBUG ((EFI_D_ERROR
, "CheckCrc32: Crc calculation failed\n"));
796 DEBUG ((EFI_D_ERROR
, "CheckCrc32: Crc check failed\n"));
800 return (BOOLEAN
) (OrgCrc
== Crc
);