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.
18 // Include common header file for this module.
20 #include "CommonHeader.h"
22 #include "Partition.h"
26 PartitionValidGptTable (
27 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
28 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
30 OUT EFI_PARTITION_TABLE_HEADER
*PartHeader
35 PartitionCheckGptEntryArrayCRC (
36 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
37 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
38 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
43 PartitionRestoreGptTable (
44 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
45 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
46 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
51 PartitionCheckGptEntry (
52 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
,
53 IN EFI_PARTITION_ENTRY
*PartEntry
,
54 OUT EFI_PARTITION_ENTRY_STATUS
*PEntryStatus
59 PartitionCheckCrcAltSize (
62 IN OUT EFI_TABLE_HEADER
*Hdr
69 IN OUT EFI_TABLE_HEADER
*Hdr
74 PartitionSetCrcAltSize (
76 IN OUT EFI_TABLE_HEADER
*Hdr
82 IN OUT EFI_TABLE_HEADER
*Hdr
86 Install child handles if the Handle supports GPT partition structure.
88 @param[in] This - Calling context.
89 @param[in] Handle - Parent Handle
90 @param[in] DiskIo - Parent DiskIo interface
91 @param[in] BlockIo - Parent BlockIo interface
92 @param[in] DevicePath - Parent Device Path
94 @retval EFI_SUCCESS Valid GPT disk
95 @retval EFI_MEDIA_CHANGED Media changed Detected
96 @retval other Not a valid GPT disk
100 PartitionInstallGptChildHandles (
101 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
102 IN EFI_HANDLE Handle
,
103 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
104 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
105 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
111 MASTER_BOOT_RECORD
*ProtectiveMbr
;
112 EFI_PARTITION_TABLE_HEADER
*PrimaryHeader
;
113 EFI_PARTITION_TABLE_HEADER
*BackupHeader
;
114 EFI_PARTITION_ENTRY
*PartEntry
;
115 EFI_PARTITION_ENTRY_STATUS
*PEntryStatus
;
118 HARDDRIVE_DEVICE_PATH HdDev
;
120 ProtectiveMbr
= NULL
;
121 PrimaryHeader
= NULL
;
126 BlockSize
= BlockIo
->Media
->BlockSize
;
127 LastBlock
= BlockIo
->Media
->LastBlock
;
129 DEBUG ((EFI_D_INFO
, " BlockSize : %d \n", BlockSize
));
130 DEBUG ((EFI_D_INFO
, " LastBlock : %x \n", LastBlock
));
132 GptValid
= EFI_NOT_FOUND
;
135 // Allocate a buffer for the Protective MBR
137 ProtectiveMbr
= AllocatePool (BlockSize
);
138 if (ProtectiveMbr
== NULL
) {
139 return EFI_NOT_FOUND
;
143 // Read the Protective MBR from LBA #0
145 Status
= BlockIo
->ReadBlocks (
147 BlockIo
->Media
->MediaId
,
149 BlockIo
->Media
->BlockSize
,
152 if (EFI_ERROR (Status
)) {
157 // Verify that the Protective MBR is valid
159 if (ProtectiveMbr
->Partition
[0].BootIndicator
!= 0x00 ||
160 ProtectiveMbr
->Partition
[0].OSIndicator
!= PMBR_GPT_PARTITION
||
161 UNPACK_UINT32 (ProtectiveMbr
->Partition
[0].StartingLBA
) != 1
167 // Allocate the GPT structures
169 PrimaryHeader
= AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER
));
170 if (PrimaryHeader
== NULL
) {
174 BackupHeader
= AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER
));
176 if (BackupHeader
== NULL
) {
181 // Check primary and backup partition tables
183 if (!PartitionValidGptTable (BlockIo
, DiskIo
, PRIMARY_PART_HEADER_LBA
, PrimaryHeader
)) {
184 DEBUG ((EFI_D_INFO
, " Not Valid primary partition table\n"));
186 if (!PartitionValidGptTable (BlockIo
, DiskIo
, LastBlock
, BackupHeader
)) {
187 DEBUG ((EFI_D_INFO
, " Not Valid backup partition table\n"));
190 DEBUG ((EFI_D_INFO
, " Valid backup partition table\n"));
191 DEBUG ((EFI_D_INFO
, " Restore primary partition table by the backup\n"));
192 if (!PartitionRestoreGptTable (BlockIo
, DiskIo
, BackupHeader
)) {
193 DEBUG ((EFI_D_INFO
, " Restore primary partition table error\n"));
196 if (PartitionValidGptTable (BlockIo
, DiskIo
, BackupHeader
->AlternateLBA
, PrimaryHeader
)) {
197 DEBUG ((EFI_D_INFO
, " Restore backup partition table success\n"));
200 } else if (!PartitionValidGptTable (BlockIo
, DiskIo
, PrimaryHeader
->AlternateLBA
, BackupHeader
)) {
201 DEBUG ((EFI_D_INFO
, " Valid primary and !Valid backup partition table\n"));
202 DEBUG ((EFI_D_INFO
, " Restore backup partition table by the primary\n"));
203 if (!PartitionRestoreGptTable (BlockIo
, DiskIo
, PrimaryHeader
)) {
204 DEBUG ((EFI_D_INFO
, " Restore backup partition table error\n"));
207 if (PartitionValidGptTable (BlockIo
, DiskIo
, PrimaryHeader
->AlternateLBA
, BackupHeader
)) {
208 DEBUG ((EFI_D_INFO
, " Restore backup partition table success\n"));
213 DEBUG ((EFI_D_INFO
, " Valid primary and Valid backup partition table\n"));
216 // Read the EFI Partition Entries
218 PartEntry
= AllocatePool (PrimaryHeader
->NumberOfPartitionEntries
* sizeof (EFI_PARTITION_ENTRY
));
219 if (PartEntry
== NULL
) {
220 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
224 Status
= DiskIo
->ReadDisk (
226 BlockIo
->Media
->MediaId
,
227 MultU64x32(PrimaryHeader
->PartitionEntryLBA
, BlockSize
),
228 PrimaryHeader
->NumberOfPartitionEntries
* (PrimaryHeader
->SizeOfPartitionEntry
),
231 if (EFI_ERROR (Status
)) {
233 DEBUG ((EFI_D_INFO
, " Partition Entry ReadBlocks error\n"));
237 DEBUG ((EFI_D_INFO
, " Partition entries read block success\n"));
239 DEBUG ((EFI_D_INFO
, " Number of partition entries: %d\n", PrimaryHeader
->NumberOfPartitionEntries
));
241 PEntryStatus
= AllocateZeroPool (PrimaryHeader
->NumberOfPartitionEntries
* sizeof (EFI_PARTITION_ENTRY_STATUS
));
242 if (PEntryStatus
== NULL
) {
243 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
248 // Check the integrity of partition entries
250 PartitionCheckGptEntry (PrimaryHeader
, PartEntry
, PEntryStatus
);
253 // If we got this far the GPT layout of the disk is valid and we should return true
255 GptValid
= EFI_SUCCESS
;
258 // Create child device handles
260 for (Index
= 0; Index
< PrimaryHeader
->NumberOfPartitionEntries
; Index
++) {
261 if (CompareGuid (&PartEntry
[Index
].PartitionTypeGUID
, &gEfiPartTypeUnusedGuid
) ||
262 PEntryStatus
[Index
].OutOfRange
||
263 PEntryStatus
[Index
].Overlap
266 // Don't use null EFI Partition Entries or Invalid Partition Entries
271 ZeroMem (&HdDev
, sizeof (HdDev
));
272 HdDev
.Header
.Type
= MEDIA_DEVICE_PATH
;
273 HdDev
.Header
.SubType
= MEDIA_HARDDRIVE_DP
;
274 SetDevicePathNodeLength (&HdDev
.Header
, sizeof (HdDev
));
276 HdDev
.PartitionNumber
= (UINT32
) Index
+ 1;
277 HdDev
.MBRType
= MBR_TYPE_EFI_PARTITION_TABLE_HEADER
;
278 HdDev
.SignatureType
= SIGNATURE_TYPE_GUID
;
279 HdDev
.PartitionStart
= PartEntry
[Index
].StartingLBA
;
280 HdDev
.PartitionSize
= PartEntry
[Index
].EndingLBA
- PartEntry
[Index
].StartingLBA
+ 1;
281 CopyMem (HdDev
.Signature
, &PartEntry
[Index
].UniquePartitionGUID
, sizeof (EFI_GUID
));
283 DEBUG ((EFI_D_INFO
, " Index : %d\n", Index
));
284 DEBUG ((EFI_D_INFO
, " Start LBA : %x\n", HdDev
.PartitionStart
));
285 DEBUG ((EFI_D_INFO
, " End LBA : %x\n", PartEntry
[Index
].EndingLBA
));
286 DEBUG ((EFI_D_INFO
, " Partition size: %x\n", HdDev
.PartitionSize
));
287 DEBUG ((EFI_D_INFO
, " Start : %x", MultU64x32 (PartEntry
[Index
].StartingLBA
, BlockSize
)));
288 DEBUG ((EFI_D_INFO
, " End : %x\n", MultU64x32 (PartEntry
[Index
].EndingLBA
, BlockSize
)));
290 Status
= PartitionInstallChildHandle (
296 (EFI_DEVICE_PATH_PROTOCOL
*) &HdDev
,
297 PartEntry
[Index
].StartingLBA
,
298 PartEntry
[Index
].EndingLBA
,
300 CompareGuid(&PartEntry
[Index
].PartitionTypeGUID
, &gEfiPartTypeSystemPartGuid
)
304 DEBUG ((EFI_D_INFO
, "Prepare to Free Pool\n"));
307 if (ProtectiveMbr
!= NULL
) {
308 FreePool (ProtectiveMbr
);
310 if (PrimaryHeader
!= NULL
) {
311 FreePool (PrimaryHeader
);
313 if (BackupHeader
!= NULL
) {
314 FreePool (BackupHeader
);
316 if (PartEntry
!= NULL
) {
317 FreePool (PartEntry
);
319 if (PEntryStatus
!= NULL
) {
320 FreePool (PEntryStatus
);
328 Install child handles if the Handle supports GPT partition structure.
330 @param[in] BlockIo Parent BlockIo interface
331 @param[in] DiskIo Disk Io protocol.
332 @param[in] Lba The starting Lba of the Partition Table
333 @param[in] PartHeader Stores the partition table that is read
335 @retval TRUE The partition table is valid
336 @retval FALSE The partition table is not valid
340 PartitionValidGptTable (
341 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
342 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
344 OUT EFI_PARTITION_TABLE_HEADER
*PartHeader
349 EFI_PARTITION_TABLE_HEADER
*PartHdr
;
351 BlockSize
= BlockIo
->Media
->BlockSize
;
353 PartHdr
= AllocateZeroPool (BlockSize
);
355 if (PartHdr
== NULL
) {
356 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
360 // Read the EFI Partition Table Header
362 Status
= BlockIo
->ReadBlocks (
364 BlockIo
->Media
->MediaId
,
369 if (EFI_ERROR (Status
)) {
374 if ((PartHdr
->Header
.Signature
== EFI_PTAB_HEADER_ID
) ||
375 !PartitionCheckCrc (BlockSize
, &PartHdr
->Header
) ||
376 PartHdr
->MyLBA
!= Lba
378 DEBUG ((EFI_D_INFO
, " !Valid efi partition table header\n"));
383 CopyMem (PartHeader
, PartHdr
, sizeof (EFI_PARTITION_TABLE_HEADER
));
384 if (!PartitionCheckGptEntryArrayCRC (BlockIo
, DiskIo
, PartHeader
)) {
389 DEBUG ((EFI_D_INFO
, " Valid efi partition table header\n"));
396 Check if the CRC field in the Partition table header is valid
397 for Partition entry array.
399 @param[in] BlockIo Parent BlockIo interface
400 @param[in] DiskIo Disk Io Protocol.
401 @param[in] PartHeader Partition table header structure
403 @retval TRUE the CRC is valid
404 @retval FALSE the CRC is invalid
408 PartitionCheckGptEntryArrayCRC (
409 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
410 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
411 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
420 // Read the EFI Partition Entries
422 Ptr
= AllocatePool (PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
);
424 DEBUG ((EFI_D_ERROR
, " Allocate pool error\n"));
428 Status
= DiskIo
->ReadDisk (
430 BlockIo
->Media
->MediaId
,
431 MultU64x32(PartHeader
->PartitionEntryLBA
, BlockIo
->Media
->BlockSize
),
432 PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
,
435 if (EFI_ERROR (Status
)) {
440 Size
= PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
;
442 Status
= gBS
->CalculateCrc32 (Ptr
, Size
, &Crc
);
443 if (EFI_ERROR (Status
)) {
444 DEBUG ((EFI_D_ERROR
, "CheckPEntryArrayCRC: Crc calculation failed\n"));
451 return (BOOLEAN
) (PartHeader
->PartitionEntryArrayCRC32
== Crc
);
456 Restore Partition Table to its alternate place
457 (Primary -> Backup or Backup -> Primary)
459 @param[in] BlockIo Parent BlockIo interface
460 @param[in] DiskIo Disk Io Protocol.
461 @param[in] PartHeader Partition table header structure
463 @retval TRUE Restoring succeeds
464 @retval FALSE Restoring failed
468 PartitionRestoreGptTable (
469 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
470 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
471 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
476 EFI_PARTITION_TABLE_HEADER
*PartHdr
;
483 BlockSize
= BlockIo
->Media
->BlockSize
;
485 PartHdr
= AllocateZeroPool (BlockSize
);
487 if (PartHdr
== NULL
) {
488 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
492 PEntryLBA
= (PartHeader
->MyLBA
== PRIMARY_PART_HEADER_LBA
) ? \
493 (PartHeader
->LastUsableLBA
+ 1) : \
494 (PRIMARY_PART_HEADER_LBA
+ 1);
496 CopyMem (PartHdr
, PartHeader
, sizeof (EFI_PARTITION_TABLE_HEADER
));
498 PartHdr
->MyLBA
= PartHeader
->AlternateLBA
;
499 PartHdr
->AlternateLBA
= PartHeader
->MyLBA
;
500 PartHdr
->PartitionEntryLBA
= PEntryLBA
;
501 PartitionSetCrc ((EFI_TABLE_HEADER
*) PartHdr
);
503 Status
= BlockIo
->WriteBlocks (BlockIo
, BlockIo
->Media
->MediaId
, PartHdr
->MyLBA
, BlockSize
, PartHdr
);
504 if (EFI_ERROR (Status
)) {
508 Ptr
= AllocatePool (PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
);
510 DEBUG ((EFI_D_ERROR
, " Allocate pool effor\n"));
511 Status
= EFI_OUT_OF_RESOURCES
;
515 Status
= DiskIo
->ReadDisk (
517 BlockIo
->Media
->MediaId
,
518 MultU64x32(PartHeader
->PartitionEntryLBA
, BlockIo
->Media
->BlockSize
),
519 PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
,
522 if (EFI_ERROR (Status
)) {
526 Status
= DiskIo
->WriteDisk (
528 BlockIo
->Media
->MediaId
,
529 MultU64x32(PEntryLBA
, BlockIo
->Media
->BlockSize
),
530 PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
,
538 if (EFI_ERROR (Status
)) {
547 Restore Partition Table to its alternate place
548 (Primary -> Backup or Backup -> Primary)
550 @param[in] PartHeader Partition table header structure
551 @param[in] PartEntry The partition entry array
552 @param[out] PEntryStatus the partition entry status array
553 recording the status of each partition
556 PartitionCheckGptEntry (
557 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
,
558 IN EFI_PARTITION_ENTRY
*PartEntry
,
559 OUT EFI_PARTITION_ENTRY_STATUS
*PEntryStatus
567 DEBUG ((EFI_D_INFO
, " start check partition entries\n"));
568 for (Index1
= 0; Index1
< PartHeader
->NumberOfPartitionEntries
; Index1
++) {
569 if (CompareGuid (&PartEntry
[Index1
].PartitionTypeGUID
, &gEfiPartTypeUnusedGuid
)) {
573 StartingLBA
= PartEntry
[Index1
].StartingLBA
;
574 EndingLBA
= PartEntry
[Index1
].EndingLBA
;
575 if (StartingLBA
> EndingLBA
||
576 StartingLBA
< PartHeader
->FirstUsableLBA
||
577 StartingLBA
> PartHeader
->LastUsableLBA
||
578 EndingLBA
< PartHeader
->FirstUsableLBA
||
579 EndingLBA
> PartHeader
->LastUsableLBA
581 PEntryStatus
[Index1
].OutOfRange
= TRUE
;
585 for (Index2
= Index1
+ 1; Index2
< PartHeader
->NumberOfPartitionEntries
; Index2
++) {
587 if (CompareGuid (&PartEntry
[Index2
].PartitionTypeGUID
, &gEfiPartTypeUnusedGuid
)) {
591 if (PartEntry
[Index2
].EndingLBA
>= StartingLBA
&& PartEntry
[Index2
].StartingLBA
<= EndingLBA
) {
593 // This region overlaps with the Index1'th region
595 PEntryStatus
[Index1
].Overlap
= TRUE
;
596 PEntryStatus
[Index2
].Overlap
= TRUE
;
603 DEBUG ((EFI_D_INFO
, " End check partition entries\n"));
608 Updates the CRC32 value in the table header
610 @param[in,out] Hdr Table to update
615 IN OUT EFI_TABLE_HEADER
*Hdr
618 PartitionSetCrcAltSize (Hdr
->HeaderSize
, Hdr
);
623 Updates the CRC32 value in the table header
625 @param[in] Size The size of the table
626 @param[in,out] Hdr Table to update
630 PartitionSetCrcAltSize (
632 IN OUT EFI_TABLE_HEADER
*Hdr
639 gBS
->CalculateCrc32 ((UINT8
*) Hdr
, Size
, &Crc
);
645 Checks the CRC32 value in the table header
647 @param[in] MaxSize Max Size limit
648 @param[in,out] Hdr Table to check
650 @return TRUE CRC Valid
651 @return FALSE CRC Invalid
657 IN OUT EFI_TABLE_HEADER
*Hdr
660 return PartitionCheckCrcAltSize (MaxSize
, Hdr
->HeaderSize
, Hdr
);
665 Checks the CRC32 value in the table header
667 @param[in] MaxSize Max Size limit
668 @param[in] Size The size of the table
669 @param[in,out] Hdr Table to check
671 @return TRUE CRC Valid
672 @return FALSE CRC Invalid
676 PartitionCheckCrcAltSize (
679 IN OUT EFI_TABLE_HEADER
*Hdr
690 // If header size is 0 CRC will pass so return FALSE here
695 if (MaxSize
&& Size
> MaxSize
) {
696 DEBUG ((EFI_D_ERROR
, "CheckCrc32: Size > MaxSize\n"));
700 // clear old crc from header
705 Status
= gBS
->CalculateCrc32 ((UINT8
*) Hdr
, Size
, &Crc
);
706 if (EFI_ERROR (Status
)) {
707 DEBUG ((EFI_D_ERROR
, "CheckCrc32: Crc calculation failed\n"));
720 DEBUG ((EFI_D_ERROR
, "CheckCrc32: Crc check failed\n"));
724 return (BOOLEAN
) (OrgCrc
== Crc
);