2 Decode a hard disk partitioned with the GPT scheme in the EFI 1.0
5 Copyright (c) 2006 - 2007, Intel Corporation
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 PartitionValidGptTable (
22 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
23 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
25 OUT EFI_PARTITION_TABLE_HEADER
*PartHeader
30 PartitionCheckGptEntryArrayCRC (
31 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
32 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
33 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
38 PartitionRestoreGptTable (
39 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
40 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
41 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
46 PartitionCheckGptEntry (
47 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
,
48 IN EFI_PARTITION_ENTRY
*PartEntry
,
49 OUT EFI_PARTITION_ENTRY_STATUS
*PEntryStatus
54 PartitionCheckCrcAltSize (
57 IN OUT EFI_TABLE_HEADER
*Hdr
64 IN OUT EFI_TABLE_HEADER
*Hdr
69 PartitionSetCrcAltSize (
71 IN OUT EFI_TABLE_HEADER
*Hdr
77 IN OUT EFI_TABLE_HEADER
*Hdr
81 Install child handles if the Handle supports GPT partition structure.
83 @param[in] This - Calling context.
84 @param[in] Handle - Parent Handle
85 @param[in] DiskIo - Parent DiskIo interface
86 @param[in] BlockIo - Parent BlockIo interface
87 @param[in] DevicePath - Parent Device Path
89 @retval EFI_SUCCESS Valid GPT disk
90 @retval EFI_MEDIA_CHANGED Media changed Detected
91 @retval other Not a valid GPT disk
95 PartitionInstallGptChildHandles (
96 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
98 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
99 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
100 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
106 MASTER_BOOT_RECORD
*ProtectiveMbr
;
107 EFI_PARTITION_TABLE_HEADER
*PrimaryHeader
;
108 EFI_PARTITION_TABLE_HEADER
*BackupHeader
;
109 EFI_PARTITION_ENTRY
*PartEntry
;
110 EFI_PARTITION_ENTRY_STATUS
*PEntryStatus
;
113 HARDDRIVE_DEVICE_PATH HdDev
;
115 ProtectiveMbr
= NULL
;
116 PrimaryHeader
= NULL
;
121 BlockSize
= BlockIo
->Media
->BlockSize
;
122 LastBlock
= BlockIo
->Media
->LastBlock
;
124 DEBUG ((EFI_D_INFO
, " BlockSize : %d \n", BlockSize
));
125 DEBUG ((EFI_D_INFO
, " LastBlock : %x \n", LastBlock
));
127 GptValid
= EFI_NOT_FOUND
;
130 // Allocate a buffer for the Protective MBR
132 ProtectiveMbr
= AllocatePool (BlockSize
);
133 if (ProtectiveMbr
== NULL
) {
134 return EFI_NOT_FOUND
;
138 // Read the Protective MBR from LBA #0
140 Status
= BlockIo
->ReadBlocks (
142 BlockIo
->Media
->MediaId
,
144 BlockIo
->Media
->BlockSize
,
147 if (EFI_ERROR (Status
)) {
152 // Verify that the Protective MBR is valid
154 if (ProtectiveMbr
->Partition
[0].BootIndicator
!= 0x00 ||
155 ProtectiveMbr
->Partition
[0].OSIndicator
!= PMBR_GPT_PARTITION
||
156 UNPACK_UINT32 (ProtectiveMbr
->Partition
[0].StartingLBA
) != 1
162 // Allocate the GPT structures
164 PrimaryHeader
= AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER
));
165 if (PrimaryHeader
== NULL
) {
169 BackupHeader
= AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER
));
171 if (BackupHeader
== NULL
) {
176 // Check primary and backup partition tables
178 if (!PartitionValidGptTable (BlockIo
, DiskIo
, PRIMARY_PART_HEADER_LBA
, PrimaryHeader
)) {
179 DEBUG ((EFI_D_INFO
, " Not Valid primary partition table\n"));
181 if (!PartitionValidGptTable (BlockIo
, DiskIo
, LastBlock
, BackupHeader
)) {
182 DEBUG ((EFI_D_INFO
, " Not Valid backup partition table\n"));
185 DEBUG ((EFI_D_INFO
, " Valid backup partition table\n"));
186 DEBUG ((EFI_D_INFO
, " Restore primary partition table by the backup\n"));
187 if (!PartitionRestoreGptTable (BlockIo
, DiskIo
, BackupHeader
)) {
188 DEBUG ((EFI_D_INFO
, " Restore primary partition table error\n"));
191 if (PartitionValidGptTable (BlockIo
, DiskIo
, BackupHeader
->AlternateLBA
, PrimaryHeader
)) {
192 DEBUG ((EFI_D_INFO
, " Restore backup partition table success\n"));
195 } else if (!PartitionValidGptTable (BlockIo
, DiskIo
, PrimaryHeader
->AlternateLBA
, BackupHeader
)) {
196 DEBUG ((EFI_D_INFO
, " Valid primary and !Valid backup partition table\n"));
197 DEBUG ((EFI_D_INFO
, " Restore backup partition table by the primary\n"));
198 if (!PartitionRestoreGptTable (BlockIo
, DiskIo
, PrimaryHeader
)) {
199 DEBUG ((EFI_D_INFO
, " Restore backup partition table error\n"));
202 if (PartitionValidGptTable (BlockIo
, DiskIo
, PrimaryHeader
->AlternateLBA
, BackupHeader
)) {
203 DEBUG ((EFI_D_INFO
, " Restore backup partition table success\n"));
208 DEBUG ((EFI_D_INFO
, " Valid primary and Valid backup partition table\n"));
211 // Read the EFI Partition Entries
213 PartEntry
= AllocatePool (PrimaryHeader
->NumberOfPartitionEntries
* sizeof (EFI_PARTITION_ENTRY
));
214 if (PartEntry
== NULL
) {
215 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
219 Status
= DiskIo
->ReadDisk (
221 BlockIo
->Media
->MediaId
,
222 MultU64x32(PrimaryHeader
->PartitionEntryLBA
, BlockSize
),
223 PrimaryHeader
->NumberOfPartitionEntries
* (PrimaryHeader
->SizeOfPartitionEntry
),
226 if (EFI_ERROR (Status
)) {
228 DEBUG ((EFI_D_INFO
, " Partition Entry ReadBlocks error\n"));
232 DEBUG ((EFI_D_INFO
, " Partition entries read block success\n"));
234 DEBUG ((EFI_D_INFO
, " Number of partition entries: %d\n", PrimaryHeader
->NumberOfPartitionEntries
));
236 PEntryStatus
= AllocateZeroPool (PrimaryHeader
->NumberOfPartitionEntries
* sizeof (EFI_PARTITION_ENTRY_STATUS
));
237 if (PEntryStatus
== NULL
) {
238 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
243 // Check the integrity of partition entries
245 PartitionCheckGptEntry (PrimaryHeader
, PartEntry
, PEntryStatus
);
248 // If we got this far the GPT layout of the disk is valid and we should return true
250 GptValid
= EFI_SUCCESS
;
253 // Create child device handles
255 for (Index
= 0; Index
< PrimaryHeader
->NumberOfPartitionEntries
; Index
++) {
256 if (CompareGuid (&PartEntry
[Index
].PartitionTypeGUID
, &gEfiPartTypeUnusedGuid
) ||
257 PEntryStatus
[Index
].OutOfRange
||
258 PEntryStatus
[Index
].Overlap
261 // Don't use null EFI Partition Entries or Invalid Partition Entries
266 ZeroMem (&HdDev
, sizeof (HdDev
));
267 HdDev
.Header
.Type
= MEDIA_DEVICE_PATH
;
268 HdDev
.Header
.SubType
= MEDIA_HARDDRIVE_DP
;
269 SetDevicePathNodeLength (&HdDev
.Header
, sizeof (HdDev
));
271 HdDev
.PartitionNumber
= (UINT32
) Index
+ 1;
272 HdDev
.MBRType
= MBR_TYPE_EFI_PARTITION_TABLE_HEADER
;
273 HdDev
.SignatureType
= SIGNATURE_TYPE_GUID
;
274 HdDev
.PartitionStart
= PartEntry
[Index
].StartingLBA
;
275 HdDev
.PartitionSize
= PartEntry
[Index
].EndingLBA
- PartEntry
[Index
].StartingLBA
+ 1;
276 CopyMem (HdDev
.Signature
, &PartEntry
[Index
].UniquePartitionGUID
, sizeof (EFI_GUID
));
278 DEBUG ((EFI_D_INFO
, " Index : %d\n", Index
));
279 DEBUG ((EFI_D_INFO
, " Start LBA : %x\n", HdDev
.PartitionStart
));
280 DEBUG ((EFI_D_INFO
, " End LBA : %x\n", PartEntry
[Index
].EndingLBA
));
281 DEBUG ((EFI_D_INFO
, " Partition size: %x\n", HdDev
.PartitionSize
));
282 DEBUG ((EFI_D_INFO
, " Start : %x", MultU64x32 (PartEntry
[Index
].StartingLBA
, BlockSize
)));
283 DEBUG ((EFI_D_INFO
, " End : %x\n", MultU64x32 (PartEntry
[Index
].EndingLBA
, BlockSize
)));
285 Status
= PartitionInstallChildHandle (
291 (EFI_DEVICE_PATH_PROTOCOL
*) &HdDev
,
292 PartEntry
[Index
].StartingLBA
,
293 PartEntry
[Index
].EndingLBA
,
295 CompareGuid(&PartEntry
[Index
].PartitionTypeGUID
, &gEfiPartTypeSystemPartGuid
)
299 DEBUG ((EFI_D_INFO
, "Prepare to Free Pool\n"));
302 if (ProtectiveMbr
!= NULL
) {
303 FreePool (ProtectiveMbr
);
305 if (PrimaryHeader
!= NULL
) {
306 FreePool (PrimaryHeader
);
308 if (BackupHeader
!= NULL
) {
309 FreePool (BackupHeader
);
311 if (PartEntry
!= NULL
) {
312 FreePool (PartEntry
);
314 if (PEntryStatus
!= NULL
) {
315 FreePool (PEntryStatus
);
323 Install child handles if the Handle supports GPT partition structure.
325 @param[in] BlockIo Parent BlockIo interface
326 @param[in] DiskIo Disk Io protocol.
327 @param[in] Lba The starting Lba of the Partition Table
328 @param[in] PartHeader Stores the partition table that is read
330 @retval TRUE The partition table is valid
331 @retval FALSE The partition table is not valid
335 PartitionValidGptTable (
336 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
337 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
339 OUT EFI_PARTITION_TABLE_HEADER
*PartHeader
344 EFI_PARTITION_TABLE_HEADER
*PartHdr
;
346 BlockSize
= BlockIo
->Media
->BlockSize
;
348 PartHdr
= AllocateZeroPool (BlockSize
);
350 if (PartHdr
== NULL
) {
351 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
355 // Read the EFI Partition Table Header
357 Status
= BlockIo
->ReadBlocks (
359 BlockIo
->Media
->MediaId
,
364 if (EFI_ERROR (Status
)) {
369 if ((PartHdr
->Header
.Signature
!= EFI_PTAB_HEADER_ID
) ||
370 !PartitionCheckCrc (BlockSize
, &PartHdr
->Header
) ||
371 PartHdr
->MyLBA
!= Lba
373 DEBUG ((EFI_D_INFO
, " !Valid efi partition table header\n"));
378 CopyMem (PartHeader
, PartHdr
, sizeof (EFI_PARTITION_TABLE_HEADER
));
379 if (!PartitionCheckGptEntryArrayCRC (BlockIo
, DiskIo
, PartHeader
)) {
384 DEBUG ((EFI_D_INFO
, " Valid efi partition table header\n"));
391 Check if the CRC field in the Partition table header is valid
392 for Partition entry array.
394 @param[in] BlockIo Parent BlockIo interface
395 @param[in] DiskIo Disk Io Protocol.
396 @param[in] PartHeader Partition table header structure
398 @retval TRUE the CRC is valid
399 @retval FALSE the CRC is invalid
403 PartitionCheckGptEntryArrayCRC (
404 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
405 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
406 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
415 // Read the EFI Partition Entries
417 Ptr
= AllocatePool (PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
);
419 DEBUG ((EFI_D_ERROR
, " Allocate pool error\n"));
423 Status
= DiskIo
->ReadDisk (
425 BlockIo
->Media
->MediaId
,
426 MultU64x32(PartHeader
->PartitionEntryLBA
, BlockIo
->Media
->BlockSize
),
427 PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
,
430 if (EFI_ERROR (Status
)) {
435 Size
= PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
;
437 Status
= gBS
->CalculateCrc32 (Ptr
, Size
, &Crc
);
438 if (EFI_ERROR (Status
)) {
439 DEBUG ((EFI_D_ERROR
, "CheckPEntryArrayCRC: Crc calculation failed\n"));
446 return (BOOLEAN
) (PartHeader
->PartitionEntryArrayCRC32
== Crc
);
451 Restore Partition Table to its alternate place
452 (Primary -> Backup or Backup -> Primary)
454 @param[in] BlockIo Parent BlockIo interface
455 @param[in] DiskIo Disk Io Protocol.
456 @param[in] PartHeader Partition table header structure
458 @retval TRUE Restoring succeeds
459 @retval FALSE Restoring failed
463 PartitionRestoreGptTable (
464 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
465 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
466 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
471 EFI_PARTITION_TABLE_HEADER
*PartHdr
;
478 BlockSize
= BlockIo
->Media
->BlockSize
;
480 PartHdr
= AllocateZeroPool (BlockSize
);
482 if (PartHdr
== NULL
) {
483 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
487 PEntryLBA
= (PartHeader
->MyLBA
== PRIMARY_PART_HEADER_LBA
) ? \
488 (PartHeader
->LastUsableLBA
+ 1) : \
489 (PRIMARY_PART_HEADER_LBA
+ 1);
491 CopyMem (PartHdr
, PartHeader
, sizeof (EFI_PARTITION_TABLE_HEADER
));
493 PartHdr
->MyLBA
= PartHeader
->AlternateLBA
;
494 PartHdr
->AlternateLBA
= PartHeader
->MyLBA
;
495 PartHdr
->PartitionEntryLBA
= PEntryLBA
;
496 PartitionSetCrc ((EFI_TABLE_HEADER
*) PartHdr
);
498 Status
= BlockIo
->WriteBlocks (BlockIo
, BlockIo
->Media
->MediaId
, PartHdr
->MyLBA
, BlockSize
, PartHdr
);
499 if (EFI_ERROR (Status
)) {
503 Ptr
= AllocatePool (PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
);
505 DEBUG ((EFI_D_ERROR
, " Allocate pool effor\n"));
506 Status
= EFI_OUT_OF_RESOURCES
;
510 Status
= DiskIo
->ReadDisk (
512 BlockIo
->Media
->MediaId
,
513 MultU64x32(PartHeader
->PartitionEntryLBA
, BlockIo
->Media
->BlockSize
),
514 PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
,
517 if (EFI_ERROR (Status
)) {
521 Status
= DiskIo
->WriteDisk (
523 BlockIo
->Media
->MediaId
,
524 MultU64x32(PEntryLBA
, BlockIo
->Media
->BlockSize
),
525 PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
,
533 if (EFI_ERROR (Status
)) {
542 Restore Partition Table to its alternate place
543 (Primary -> Backup or Backup -> Primary)
545 @param[in] PartHeader Partition table header structure
546 @param[in] PartEntry The partition entry array
547 @param[out] PEntryStatus the partition entry status array
548 recording the status of each partition
551 PartitionCheckGptEntry (
552 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
,
553 IN EFI_PARTITION_ENTRY
*PartEntry
,
554 OUT EFI_PARTITION_ENTRY_STATUS
*PEntryStatus
562 DEBUG ((EFI_D_INFO
, " start check partition entries\n"));
563 for (Index1
= 0; Index1
< PartHeader
->NumberOfPartitionEntries
; Index1
++) {
564 if (CompareGuid (&PartEntry
[Index1
].PartitionTypeGUID
, &gEfiPartTypeUnusedGuid
)) {
568 StartingLBA
= PartEntry
[Index1
].StartingLBA
;
569 EndingLBA
= PartEntry
[Index1
].EndingLBA
;
570 if (StartingLBA
> EndingLBA
||
571 StartingLBA
< PartHeader
->FirstUsableLBA
||
572 StartingLBA
> PartHeader
->LastUsableLBA
||
573 EndingLBA
< PartHeader
->FirstUsableLBA
||
574 EndingLBA
> PartHeader
->LastUsableLBA
576 PEntryStatus
[Index1
].OutOfRange
= TRUE
;
580 for (Index2
= Index1
+ 1; Index2
< PartHeader
->NumberOfPartitionEntries
; Index2
++) {
582 if (CompareGuid (&PartEntry
[Index2
].PartitionTypeGUID
, &gEfiPartTypeUnusedGuid
)) {
586 if (PartEntry
[Index2
].EndingLBA
>= StartingLBA
&& PartEntry
[Index2
].StartingLBA
<= EndingLBA
) {
588 // This region overlaps with the Index1'th region
590 PEntryStatus
[Index1
].Overlap
= TRUE
;
591 PEntryStatus
[Index2
].Overlap
= TRUE
;
598 DEBUG ((EFI_D_INFO
, " End check partition entries\n"));
603 Updates the CRC32 value in the table header
605 @param[in,out] Hdr Table to update
610 IN OUT EFI_TABLE_HEADER
*Hdr
613 PartitionSetCrcAltSize (Hdr
->HeaderSize
, Hdr
);
618 Updates the CRC32 value in the table header
620 @param[in] Size The size of the table
621 @param[in,out] Hdr Table to update
625 PartitionSetCrcAltSize (
627 IN OUT EFI_TABLE_HEADER
*Hdr
634 gBS
->CalculateCrc32 ((UINT8
*) Hdr
, Size
, &Crc
);
640 Checks the CRC32 value in the table header
642 @param[in] MaxSize Max Size limit
643 @param[in,out] Hdr Table to check
645 @return TRUE CRC Valid
646 @return FALSE CRC Invalid
652 IN OUT EFI_TABLE_HEADER
*Hdr
655 return PartitionCheckCrcAltSize (MaxSize
, Hdr
->HeaderSize
, Hdr
);
660 Checks the CRC32 value in the table header
662 @param[in] MaxSize Max Size limit
663 @param[in] Size The size of the table
664 @param[in,out] Hdr Table to check
666 @return TRUE CRC Valid
667 @return FALSE CRC Invalid
671 PartitionCheckCrcAltSize (
674 IN OUT EFI_TABLE_HEADER
*Hdr
685 // If header size is 0 CRC will pass so return FALSE here
690 if (MaxSize
&& Size
> MaxSize
) {
691 DEBUG ((EFI_D_ERROR
, "CheckCrc32: Size > MaxSize\n"));
695 // clear old crc from header
700 Status
= gBS
->CalculateCrc32 ((UINT8
*) Hdr
, Size
, &Crc
);
701 if (EFI_ERROR (Status
)) {
702 DEBUG ((EFI_D_ERROR
, "CheckCrc32: Crc calculation failed\n"));
715 DEBUG ((EFI_D_ERROR
, "CheckCrc32: Crc check failed\n"));
719 return (BOOLEAN
) (OrgCrc
== Crc
);