3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Decode a hard disk partitioned with the GPT scheme in the EFI 1.0
23 #include "Partition.h"
27 PartitionValidGptTable (
28 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
29 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
31 OUT EFI_PARTITION_TABLE_HEADER
*PartHeader
36 PartitionCheckGptEntryArrayCRC (
37 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
38 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
39 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
44 PartitionRestoreGptTable (
45 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
46 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
47 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
52 PartitionCheckGptEntry (
53 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
,
54 IN EFI_PARTITION_ENTRY
*PartEntry
,
55 OUT EFI_PARTITION_ENTRY_STATUS
*PEntryStatus
60 PartitionCheckCrcAltSize (
63 IN OUT EFI_TABLE_HEADER
*Hdr
70 IN OUT EFI_TABLE_HEADER
*Hdr
75 PartitionSetCrcAltSize (
77 IN OUT EFI_TABLE_HEADER
*Hdr
83 IN OUT EFI_TABLE_HEADER
*Hdr
87 PartitionInstallGptChildHandles (
88 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
90 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
91 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
92 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
97 Install child handles if the Handle supports GPT partition structure.
100 This - Calling context.
101 Handle - Parent Handle
102 DiskIo - Parent DiskIo interface
103 BlockIo - Parent BlockIo interface
104 DevicePath - Parent Device Path
107 EFI_SUCCESS - Valid GPT disk
108 EFI_MEDIA_CHANGED - Media changed Detected
109 !EFI_SUCCESS - Not a valid GPT disk
116 MASTER_BOOT_RECORD
*ProtectiveMbr
;
117 EFI_PARTITION_TABLE_HEADER
*PrimaryHeader
;
118 EFI_PARTITION_TABLE_HEADER
*BackupHeader
;
119 EFI_PARTITION_ENTRY
*PartEntry
;
120 EFI_PARTITION_ENTRY_STATUS
*PEntryStatus
;
123 HARDDRIVE_DEVICE_PATH HdDev
;
125 ProtectiveMbr
= NULL
;
126 PrimaryHeader
= NULL
;
131 BlockSize
= BlockIo
->Media
->BlockSize
;
132 LastBlock
= BlockIo
->Media
->LastBlock
;
134 DEBUG ((EFI_D_INFO
, " BlockSize : %d \n", BlockSize
));
135 DEBUG ((EFI_D_INFO
, " LastBlock : %x \n", LastBlock
));
137 GptValid
= EFI_NOT_FOUND
;
140 // Allocate a buffer for the Protective MBR
142 ProtectiveMbr
= AllocatePool (BlockSize
);
143 if (ProtectiveMbr
== NULL
) {
144 return EFI_NOT_FOUND
;
148 // Read the Protective MBR from LBA #0
150 Status
= BlockIo
->ReadBlocks (
152 BlockIo
->Media
->MediaId
,
154 BlockIo
->Media
->BlockSize
,
157 if (EFI_ERROR (Status
)) {
162 // Verify that the Protective MBR is valid
164 if (ProtectiveMbr
->Partition
[0].BootIndicator
!= 0x00 ||
165 ProtectiveMbr
->Partition
[0].OSIndicator
!= PMBR_GPT_PARTITION
||
166 UNPACK_UINT32 (ProtectiveMbr
->Partition
[0].StartingLBA
) != 1
172 // Allocate the GPT structures
174 PrimaryHeader
= AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER
));
175 if (PrimaryHeader
== NULL
) {
179 BackupHeader
= AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER
));
181 if (BackupHeader
== NULL
) {
186 // Check primary and backup partition tables
188 if (!PartitionValidGptTable (BlockIo
, DiskIo
, PRIMARY_PART_HEADER_LBA
, PrimaryHeader
)) {
189 DEBUG ((EFI_D_INFO
, " Not Valid primary partition table\n"));
191 if (!PartitionValidGptTable (BlockIo
, DiskIo
, LastBlock
, BackupHeader
)) {
192 DEBUG ((EFI_D_INFO
, " Not Valid backup partition table\n"));
195 DEBUG ((EFI_D_INFO
, " Valid backup partition table\n"));
196 DEBUG ((EFI_D_INFO
, " Restore primary partition table by the backup\n"));
197 if (!PartitionRestoreGptTable (BlockIo
, DiskIo
, BackupHeader
)) {
198 DEBUG ((EFI_D_INFO
, " Restore primary partition table error\n"));
201 if (PartitionValidGptTable (BlockIo
, DiskIo
, BackupHeader
->AlternateLBA
, PrimaryHeader
)) {
202 DEBUG ((EFI_D_INFO
, " Restore backup partition table success\n"));
205 } else if (!PartitionValidGptTable (BlockIo
, DiskIo
, PrimaryHeader
->AlternateLBA
, BackupHeader
)) {
206 DEBUG ((EFI_D_INFO
, " Valid primary and !Valid backup partition table\n"));
207 DEBUG ((EFI_D_INFO
, " Restore backup partition table by the primary\n"));
208 if (!PartitionRestoreGptTable (BlockIo
, DiskIo
, PrimaryHeader
)) {
209 DEBUG ((EFI_D_INFO
, " Restore backup partition table error\n"));
212 if (PartitionValidGptTable (BlockIo
, DiskIo
, PrimaryHeader
->AlternateLBA
, BackupHeader
)) {
213 DEBUG ((EFI_D_INFO
, " Restore backup partition table success\n"));
218 DEBUG ((EFI_D_INFO
, " Valid primary and Valid backup partition table\n"));
221 // Read the EFI Partition Entries
223 PartEntry
= AllocatePool (PrimaryHeader
->NumberOfPartitionEntries
* sizeof (EFI_PARTITION_ENTRY
));
224 if (PartEntry
== NULL
) {
225 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
229 Status
= DiskIo
->ReadDisk (
231 BlockIo
->Media
->MediaId
,
232 MultU64x32(PrimaryHeader
->PartitionEntryLBA
, BlockSize
),
233 PrimaryHeader
->NumberOfPartitionEntries
* (PrimaryHeader
->SizeOfPartitionEntry
),
236 if (EFI_ERROR (Status
)) {
238 DEBUG ((EFI_D_INFO
, " Partition Entry ReadBlocks error\n"));
242 DEBUG ((EFI_D_INFO
, " Partition entries read block success\n"));
244 DEBUG ((EFI_D_INFO
, " Number of partition entries: %d\n", PrimaryHeader
->NumberOfPartitionEntries
));
246 PEntryStatus
= AllocateZeroPool (PrimaryHeader
->NumberOfPartitionEntries
* sizeof (EFI_PARTITION_ENTRY_STATUS
));
247 if (PEntryStatus
== NULL
) {
248 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
253 // Check the integrity of partition entries
255 PartitionCheckGptEntry (PrimaryHeader
, PartEntry
, PEntryStatus
);
258 // If we got this far the GPT layout of the disk is valid and we should return true
260 GptValid
= EFI_SUCCESS
;
263 // Create child device handles
265 for (Index
= 0; Index
< PrimaryHeader
->NumberOfPartitionEntries
; Index
++) {
266 if (CompareGuid (&PartEntry
[Index
].PartitionTypeGUID
, &gEfiPartTypeUnusedGuid
) ||
267 PEntryStatus
[Index
].OutOfRange
||
268 PEntryStatus
[Index
].Overlap
271 // Don't use null EFI Partition Entries or Invalid Partition Entries
276 ZeroMem (&HdDev
, sizeof (HdDev
));
277 HdDev
.Header
.Type
= MEDIA_DEVICE_PATH
;
278 HdDev
.Header
.SubType
= MEDIA_HARDDRIVE_DP
;
279 SetDevicePathNodeLength (&HdDev
.Header
, sizeof (HdDev
));
281 HdDev
.PartitionNumber
= (UINT32
) Index
+ 1;
282 HdDev
.MBRType
= MBR_TYPE_EFI_PARTITION_TABLE_HEADER
;
283 HdDev
.SignatureType
= SIGNATURE_TYPE_GUID
;
284 HdDev
.PartitionStart
= PartEntry
[Index
].StartingLBA
;
285 HdDev
.PartitionSize
= PartEntry
[Index
].EndingLBA
- PartEntry
[Index
].StartingLBA
+ 1;
286 CopyMem (HdDev
.Signature
, &PartEntry
[Index
].UniquePartitionGUID
, sizeof (EFI_GUID
));
288 DEBUG ((EFI_D_INFO
, " Index : %d\n", Index
));
289 DEBUG ((EFI_D_INFO
, " Start LBA : %x\n", HdDev
.PartitionStart
));
290 DEBUG ((EFI_D_INFO
, " End LBA : %x\n", PartEntry
[Index
].EndingLBA
));
291 DEBUG ((EFI_D_INFO
, " Partition size: %x\n", HdDev
.PartitionSize
));
292 DEBUG ((EFI_D_INFO
, " Start : %x", MultU64x32 (PartEntry
[Index
].StartingLBA
, BlockSize
)));
293 DEBUG ((EFI_D_INFO
, " End : %x\n", MultU64x32 (PartEntry
[Index
].EndingLBA
, BlockSize
)));
295 Status
= PartitionInstallChildHandle (
301 (EFI_DEVICE_PATH_PROTOCOL
*) &HdDev
,
302 PartEntry
[Index
].StartingLBA
,
303 PartEntry
[Index
].EndingLBA
,
305 CompareGuid(&PartEntry
[Index
].PartitionTypeGUID
, &gEfiPartTypeSystemPartGuid
)
309 DEBUG ((EFI_D_INFO
, "Prepare to Free Pool\n"));
312 if (ProtectiveMbr
!= NULL
) {
313 FreePool (ProtectiveMbr
);
315 if (PrimaryHeader
!= NULL
) {
316 FreePool (PrimaryHeader
);
318 if (BackupHeader
!= NULL
) {
319 FreePool (BackupHeader
);
321 if (PartEntry
!= NULL
) {
322 FreePool (PartEntry
);
324 if (PEntryStatus
!= NULL
) {
325 FreePool (PEntryStatus
);
333 PartitionValidGptTable (
334 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
335 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
337 OUT EFI_PARTITION_TABLE_HEADER
*PartHeader
342 Check if the GPT partition table is valid
345 BlockIo - Parent BlockIo interface
346 DiskIo - Disk Io protocol.
347 Lba - The starting Lba of the Partition Table
348 PartHeader - Stores the partition table that is read
351 TRUE - The partition table is valid
352 FALSE - The partition table is not valid
358 EFI_PARTITION_TABLE_HEADER
*PartHdr
;
360 BlockSize
= BlockIo
->Media
->BlockSize
;
362 PartHdr
= AllocateZeroPool (BlockSize
);
364 if (PartHdr
== NULL
) {
365 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
369 // Read the EFI Partition Table Header
371 Status
= BlockIo
->ReadBlocks (
373 BlockIo
->Media
->MediaId
,
378 if (EFI_ERROR (Status
)) {
383 if (CompareMem (&PartHdr
->Header
.Signature
, EFI_PTAB_HEADER_ID
, sizeof (UINT64
)) != 0 ||
384 !PartitionCheckCrc (BlockSize
, &PartHdr
->Header
) ||
385 PartHdr
->MyLBA
!= Lba
387 DEBUG ((EFI_D_INFO
, " !Valid efi partition table header\n"));
392 CopyMem (PartHeader
, PartHdr
, sizeof (EFI_PARTITION_TABLE_HEADER
));
393 if (!PartitionCheckGptEntryArrayCRC (BlockIo
, DiskIo
, PartHeader
)) {
398 DEBUG ((EFI_D_INFO
, " Valid efi partition table header\n"));
405 PartitionCheckGptEntryArrayCRC (
406 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
407 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
408 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
414 Check if the CRC field in the Partition table header is valid
415 for Partition entry array
419 BlockIo - parent BlockIo interface
420 DiskIo - Disk Io Protocol.
421 PartHeader - Partition table header structure
425 TRUE - the CRC is valid
426 FALSE - the CRC is invalid
436 // Read the EFI Partition Entries
438 Ptr
= AllocatePool (PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
);
440 DEBUG ((EFI_D_ERROR
, " Allocate pool error\n"));
444 Status
= DiskIo
->ReadDisk (
446 BlockIo
->Media
->MediaId
,
447 MultU64x32(PartHeader
->PartitionEntryLBA
, BlockIo
->Media
->BlockSize
),
448 PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
,
451 if (EFI_ERROR (Status
)) {
456 Size
= PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
;
458 Status
= gBS
->CalculateCrc32 (Ptr
, Size
, &Crc
);
459 if (EFI_ERROR (Status
)) {
460 DEBUG ((EFI_D_ERROR
, "CheckPEntryArrayCRC: Crc calculation failed\n"));
467 return (BOOLEAN
) (PartHeader
->PartitionEntryArrayCRC32
== Crc
);
472 PartitionRestoreGptTable (
473 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
474 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
475 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
481 Restore Partition Table to its alternate place
482 (Primary -> Backup or Backup -> Primary)
486 BlockIo - parent BlockIo interface
487 DiskIo - Disk Io Protocol.
488 PartHeader - the source Partition table header structure
492 TRUE - Restoring succeeds
493 FALSE - Restoring failed
499 EFI_PARTITION_TABLE_HEADER
*PartHdr
;
506 BlockSize
= BlockIo
->Media
->BlockSize
;
508 PartHdr
= AllocateZeroPool (BlockSize
);
510 if (PartHdr
== NULL
) {
511 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
515 PEntryLBA
= (PartHeader
->MyLBA
== PRIMARY_PART_HEADER_LBA
) ? \
516 (PartHeader
->LastUsableLBA
+ 1) : \
517 (PRIMARY_PART_HEADER_LBA
+ 1);
519 CopyMem (PartHdr
, PartHeader
, sizeof (EFI_PARTITION_TABLE_HEADER
));
521 PartHdr
->MyLBA
= PartHeader
->AlternateLBA
;
522 PartHdr
->AlternateLBA
= PartHeader
->MyLBA
;
523 PartHdr
->PartitionEntryLBA
= PEntryLBA
;
524 PartitionSetCrc ((EFI_TABLE_HEADER
*) PartHdr
);
526 Status
= BlockIo
->WriteBlocks (BlockIo
, BlockIo
->Media
->MediaId
, PartHdr
->MyLBA
, BlockSize
, PartHdr
);
527 if (EFI_ERROR (Status
)) {
531 Ptr
= AllocatePool (PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
);
533 DEBUG ((EFI_D_ERROR
, " Allocate pool effor\n"));
534 Status
= EFI_OUT_OF_RESOURCES
;
538 Status
= DiskIo
->ReadDisk (
540 BlockIo
->Media
->MediaId
,
541 MultU64x32(PartHeader
->PartitionEntryLBA
, BlockIo
->Media
->BlockSize
),
542 PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
,
545 if (EFI_ERROR (Status
)) {
549 Status
= DiskIo
->WriteDisk (
551 BlockIo
->Media
->MediaId
,
552 MultU64x32(PEntryLBA
, BlockIo
->Media
->BlockSize
),
553 PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
,
561 if (EFI_ERROR (Status
)) {
570 PartitionCheckGptEntry (
571 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
,
572 IN EFI_PARTITION_ENTRY
*PartEntry
,
573 OUT EFI_PARTITION_ENTRY_STATUS
*PEntryStatus
579 Check each partition entry for its range
583 PartHeader - the partition table header
584 PartEntry - the partition entry array
585 PEntryStatus - the partition entry status array recording the status of
598 DEBUG ((EFI_D_INFO
, " start check partition entries\n"));
599 for (Index1
= 0; Index1
< PartHeader
->NumberOfPartitionEntries
; Index1
++) {
600 if (CompareGuid (&PartEntry
[Index1
].PartitionTypeGUID
, &gEfiPartTypeUnusedGuid
)) {
604 StartingLBA
= PartEntry
[Index1
].StartingLBA
;
605 EndingLBA
= PartEntry
[Index1
].EndingLBA
;
606 if (StartingLBA
> EndingLBA
||
607 StartingLBA
< PartHeader
->FirstUsableLBA
||
608 StartingLBA
> PartHeader
->LastUsableLBA
||
609 EndingLBA
< PartHeader
->FirstUsableLBA
||
610 EndingLBA
> PartHeader
->LastUsableLBA
612 PEntryStatus
[Index1
].OutOfRange
= TRUE
;
616 for (Index2
= Index1
+ 1; Index2
< PartHeader
->NumberOfPartitionEntries
; Index2
++) {
618 if (CompareGuid (&PartEntry
[Index2
].PartitionTypeGUID
, &gEfiPartTypeUnusedGuid
)) {
622 if (PartEntry
[Index2
].EndingLBA
>= StartingLBA
&& PartEntry
[Index2
].StartingLBA
<= EndingLBA
) {
624 // This region overlaps with the Index1'th region
626 PEntryStatus
[Index1
].Overlap
= TRUE
;
627 PEntryStatus
[Index2
].Overlap
= TRUE
;
634 DEBUG ((EFI_D_INFO
, " End check partition entries\n"));
640 IN OUT EFI_TABLE_HEADER
*Hdr
646 Updates the CRC32 value in the table header
650 Hdr - The table to update
658 PartitionSetCrcAltSize (Hdr
->HeaderSize
, Hdr
);
663 PartitionSetCrcAltSize (
665 IN OUT EFI_TABLE_HEADER
*Hdr
671 Updates the CRC32 value in the table header
675 Size - The size of the table
676 Hdr - The table to update
687 gBS
->CalculateCrc32 ((UINT8
*) Hdr
, Size
, &Crc
);
695 IN OUT EFI_TABLE_HEADER
*Hdr
701 Checks the CRC32 value in the table header
705 MaxSize - Max Size limit
706 Hdr - The table to check
710 TRUE if the CRC is OK in the table
714 return PartitionCheckCrcAltSize (MaxSize
, Hdr
->HeaderSize
, Hdr
);
719 PartitionCheckCrcAltSize (
722 IN OUT EFI_TABLE_HEADER
*Hdr
728 Checks the CRC32 value in the table header
732 MaxSize - Max Size Limit
733 Size - The size of the table
734 Hdr - The table to check
738 TRUE if the CRC is OK in the table
750 // If header size is 0 CRC will pass so return FALSE here
755 if (MaxSize
&& Size
> MaxSize
) {
756 DEBUG ((EFI_D_ERROR
, "CheckCrc32: Size > MaxSize\n"));
760 // clear old crc from header
765 Status
= gBS
->CalculateCrc32 ((UINT8
*) Hdr
, Size
, &Crc
);
766 if (EFI_ERROR (Status
)) {
767 DEBUG ((EFI_D_ERROR
, "CheckCrc32: Crc calculation failed\n"));
780 DEBUG ((EFI_D_ERROR
, "CheckCrc32: Crc check failed\n"));
784 return (BOOLEAN
) (OrgCrc
== Crc
);