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
24 // Include common header file for this module.
26 #include "CommonHeader.h"
28 #include "Partition.h"
32 PartitionValidGptTable (
33 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
34 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
36 OUT EFI_PARTITION_TABLE_HEADER
*PartHeader
41 PartitionCheckGptEntryArrayCRC (
42 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
43 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
44 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
49 PartitionRestoreGptTable (
50 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
51 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
52 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
57 PartitionCheckGptEntry (
58 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
,
59 IN EFI_PARTITION_ENTRY
*PartEntry
,
60 OUT EFI_PARTITION_ENTRY_STATUS
*PEntryStatus
65 PartitionCheckCrcAltSize (
68 IN OUT EFI_TABLE_HEADER
*Hdr
75 IN OUT EFI_TABLE_HEADER
*Hdr
80 PartitionSetCrcAltSize (
82 IN OUT EFI_TABLE_HEADER
*Hdr
88 IN OUT EFI_TABLE_HEADER
*Hdr
92 PartitionInstallGptChildHandles (
93 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
95 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
96 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
97 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
102 Install child handles if the Handle supports GPT partition structure.
105 This - Calling context.
106 Handle - Parent Handle
107 DiskIo - Parent DiskIo interface
108 BlockIo - Parent BlockIo interface
109 DevicePath - Parent Device Path
112 EFI_SUCCESS - Valid GPT disk
113 EFI_MEDIA_CHANGED - Media changed Detected
114 !EFI_SUCCESS - Not a valid GPT disk
121 MASTER_BOOT_RECORD
*ProtectiveMbr
;
122 EFI_PARTITION_TABLE_HEADER
*PrimaryHeader
;
123 EFI_PARTITION_TABLE_HEADER
*BackupHeader
;
124 EFI_PARTITION_ENTRY
*PartEntry
;
125 EFI_PARTITION_ENTRY_STATUS
*PEntryStatus
;
128 HARDDRIVE_DEVICE_PATH HdDev
;
130 ProtectiveMbr
= NULL
;
131 PrimaryHeader
= NULL
;
136 BlockSize
= BlockIo
->Media
->BlockSize
;
137 LastBlock
= BlockIo
->Media
->LastBlock
;
139 DEBUG ((EFI_D_INFO
, " BlockSize : %d \n", BlockSize
));
140 DEBUG ((EFI_D_INFO
, " LastBlock : %x \n", LastBlock
));
142 GptValid
= EFI_NOT_FOUND
;
145 // Allocate a buffer for the Protective MBR
147 ProtectiveMbr
= AllocatePool (BlockSize
);
148 if (ProtectiveMbr
== NULL
) {
149 return EFI_NOT_FOUND
;
153 // Read the Protective MBR from LBA #0
155 Status
= BlockIo
->ReadBlocks (
157 BlockIo
->Media
->MediaId
,
159 BlockIo
->Media
->BlockSize
,
162 if (EFI_ERROR (Status
)) {
167 // Verify that the Protective MBR is valid
169 if (ProtectiveMbr
->Partition
[0].BootIndicator
!= 0x00 ||
170 ProtectiveMbr
->Partition
[0].OSIndicator
!= PMBR_GPT_PARTITION
||
171 UNPACK_UINT32 (ProtectiveMbr
->Partition
[0].StartingLBA
) != 1
177 // Allocate the GPT structures
179 PrimaryHeader
= AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER
));
180 if (PrimaryHeader
== NULL
) {
184 BackupHeader
= AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER
));
186 if (BackupHeader
== NULL
) {
191 // Check primary and backup partition tables
193 if (!PartitionValidGptTable (BlockIo
, DiskIo
, PRIMARY_PART_HEADER_LBA
, PrimaryHeader
)) {
194 DEBUG ((EFI_D_INFO
, " Not Valid primary partition table\n"));
196 if (!PartitionValidGptTable (BlockIo
, DiskIo
, LastBlock
, BackupHeader
)) {
197 DEBUG ((EFI_D_INFO
, " Not Valid backup partition table\n"));
200 DEBUG ((EFI_D_INFO
, " Valid backup partition table\n"));
201 DEBUG ((EFI_D_INFO
, " Restore primary partition table by the backup\n"));
202 if (!PartitionRestoreGptTable (BlockIo
, DiskIo
, BackupHeader
)) {
203 DEBUG ((EFI_D_INFO
, " Restore primary partition table error\n"));
206 if (PartitionValidGptTable (BlockIo
, DiskIo
, BackupHeader
->AlternateLBA
, PrimaryHeader
)) {
207 DEBUG ((EFI_D_INFO
, " Restore backup partition table success\n"));
210 } else if (!PartitionValidGptTable (BlockIo
, DiskIo
, PrimaryHeader
->AlternateLBA
, BackupHeader
)) {
211 DEBUG ((EFI_D_INFO
, " Valid primary and !Valid backup partition table\n"));
212 DEBUG ((EFI_D_INFO
, " Restore backup partition table by the primary\n"));
213 if (!PartitionRestoreGptTable (BlockIo
, DiskIo
, PrimaryHeader
)) {
214 DEBUG ((EFI_D_INFO
, " Restore backup partition table error\n"));
217 if (PartitionValidGptTable (BlockIo
, DiskIo
, PrimaryHeader
->AlternateLBA
, BackupHeader
)) {
218 DEBUG ((EFI_D_INFO
, " Restore backup partition table success\n"));
223 DEBUG ((EFI_D_INFO
, " Valid primary and Valid backup partition table\n"));
226 // Read the EFI Partition Entries
228 PartEntry
= AllocatePool (PrimaryHeader
->NumberOfPartitionEntries
* sizeof (EFI_PARTITION_ENTRY
));
229 if (PartEntry
== NULL
) {
230 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
234 Status
= DiskIo
->ReadDisk (
236 BlockIo
->Media
->MediaId
,
237 MultU64x32(PrimaryHeader
->PartitionEntryLBA
, BlockSize
),
238 PrimaryHeader
->NumberOfPartitionEntries
* (PrimaryHeader
->SizeOfPartitionEntry
),
241 if (EFI_ERROR (Status
)) {
243 DEBUG ((EFI_D_INFO
, " Partition Entry ReadBlocks error\n"));
247 DEBUG ((EFI_D_INFO
, " Partition entries read block success\n"));
249 DEBUG ((EFI_D_INFO
, " Number of partition entries: %d\n", PrimaryHeader
->NumberOfPartitionEntries
));
251 PEntryStatus
= AllocateZeroPool (PrimaryHeader
->NumberOfPartitionEntries
* sizeof (EFI_PARTITION_ENTRY_STATUS
));
252 if (PEntryStatus
== NULL
) {
253 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
258 // Check the integrity of partition entries
260 PartitionCheckGptEntry (PrimaryHeader
, PartEntry
, PEntryStatus
);
263 // If we got this far the GPT layout of the disk is valid and we should return true
265 GptValid
= EFI_SUCCESS
;
268 // Create child device handles
270 for (Index
= 0; Index
< PrimaryHeader
->NumberOfPartitionEntries
; Index
++) {
271 if (CompareGuid (&PartEntry
[Index
].PartitionTypeGUID
, &gEfiPartTypeUnusedGuid
) ||
272 PEntryStatus
[Index
].OutOfRange
||
273 PEntryStatus
[Index
].Overlap
276 // Don't use null EFI Partition Entries or Invalid Partition Entries
281 ZeroMem (&HdDev
, sizeof (HdDev
));
282 HdDev
.Header
.Type
= MEDIA_DEVICE_PATH
;
283 HdDev
.Header
.SubType
= MEDIA_HARDDRIVE_DP
;
284 SetDevicePathNodeLength (&HdDev
.Header
, sizeof (HdDev
));
286 HdDev
.PartitionNumber
= (UINT32
) Index
+ 1;
287 HdDev
.MBRType
= MBR_TYPE_EFI_PARTITION_TABLE_HEADER
;
288 HdDev
.SignatureType
= SIGNATURE_TYPE_GUID
;
289 HdDev
.PartitionStart
= PartEntry
[Index
].StartingLBA
;
290 HdDev
.PartitionSize
= PartEntry
[Index
].EndingLBA
- PartEntry
[Index
].StartingLBA
+ 1;
291 CopyMem (HdDev
.Signature
, &PartEntry
[Index
].UniquePartitionGUID
, sizeof (EFI_GUID
));
293 DEBUG ((EFI_D_INFO
, " Index : %d\n", Index
));
294 DEBUG ((EFI_D_INFO
, " Start LBA : %x\n", HdDev
.PartitionStart
));
295 DEBUG ((EFI_D_INFO
, " End LBA : %x\n", PartEntry
[Index
].EndingLBA
));
296 DEBUG ((EFI_D_INFO
, " Partition size: %x\n", HdDev
.PartitionSize
));
297 DEBUG ((EFI_D_INFO
, " Start : %x", MultU64x32 (PartEntry
[Index
].StartingLBA
, BlockSize
)));
298 DEBUG ((EFI_D_INFO
, " End : %x\n", MultU64x32 (PartEntry
[Index
].EndingLBA
, BlockSize
)));
300 Status
= PartitionInstallChildHandle (
306 (EFI_DEVICE_PATH_PROTOCOL
*) &HdDev
,
307 PartEntry
[Index
].StartingLBA
,
308 PartEntry
[Index
].EndingLBA
,
310 CompareGuid(&PartEntry
[Index
].PartitionTypeGUID
, &gEfiPartTypeSystemPartGuid
)
314 DEBUG ((EFI_D_INFO
, "Prepare to Free Pool\n"));
317 if (ProtectiveMbr
!= NULL
) {
318 FreePool (ProtectiveMbr
);
320 if (PrimaryHeader
!= NULL
) {
321 FreePool (PrimaryHeader
);
323 if (BackupHeader
!= NULL
) {
324 FreePool (BackupHeader
);
326 if (PartEntry
!= NULL
) {
327 FreePool (PartEntry
);
329 if (PEntryStatus
!= NULL
) {
330 FreePool (PEntryStatus
);
338 PartitionValidGptTable (
339 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
340 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
342 OUT EFI_PARTITION_TABLE_HEADER
*PartHeader
347 Check if the GPT partition table is valid
350 BlockIo - Parent BlockIo interface
351 DiskIo - Disk Io protocol.
352 Lba - The starting Lba of the Partition Table
353 PartHeader - Stores the partition table that is read
356 TRUE - The partition table is valid
357 FALSE - The partition table is not valid
363 EFI_PARTITION_TABLE_HEADER
*PartHdr
;
365 BlockSize
= BlockIo
->Media
->BlockSize
;
367 PartHdr
= AllocateZeroPool (BlockSize
);
369 if (PartHdr
== NULL
) {
370 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
374 // Read the EFI Partition Table Header
376 Status
= BlockIo
->ReadBlocks (
378 BlockIo
->Media
->MediaId
,
383 if (EFI_ERROR (Status
)) {
388 if ((PartHdr
->Header
.Signature
== EFI_PTAB_HEADER_ID
) ||
389 !PartitionCheckCrc (BlockSize
, &PartHdr
->Header
) ||
390 PartHdr
->MyLBA
!= Lba
392 DEBUG ((EFI_D_INFO
, " !Valid efi partition table header\n"));
397 CopyMem (PartHeader
, PartHdr
, sizeof (EFI_PARTITION_TABLE_HEADER
));
398 if (!PartitionCheckGptEntryArrayCRC (BlockIo
, DiskIo
, PartHeader
)) {
403 DEBUG ((EFI_D_INFO
, " Valid efi partition table header\n"));
410 PartitionCheckGptEntryArrayCRC (
411 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
412 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
413 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
419 Check if the CRC field in the Partition table header is valid
420 for Partition entry array
424 BlockIo - parent BlockIo interface
425 DiskIo - Disk Io Protocol.
426 PartHeader - Partition table header structure
430 TRUE - the CRC is valid
431 FALSE - the CRC is invalid
441 // Read the EFI Partition Entries
443 Ptr
= AllocatePool (PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
);
445 DEBUG ((EFI_D_ERROR
, " Allocate pool error\n"));
449 Status
= DiskIo
->ReadDisk (
451 BlockIo
->Media
->MediaId
,
452 MultU64x32(PartHeader
->PartitionEntryLBA
, BlockIo
->Media
->BlockSize
),
453 PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
,
456 if (EFI_ERROR (Status
)) {
461 Size
= PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
;
463 Status
= gBS
->CalculateCrc32 (Ptr
, Size
, &Crc
);
464 if (EFI_ERROR (Status
)) {
465 DEBUG ((EFI_D_ERROR
, "CheckPEntryArrayCRC: Crc calculation failed\n"));
472 return (BOOLEAN
) (PartHeader
->PartitionEntryArrayCRC32
== Crc
);
477 PartitionRestoreGptTable (
478 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
479 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
480 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
486 Restore Partition Table to its alternate place
487 (Primary -> Backup or Backup -> Primary)
491 BlockIo - parent BlockIo interface
492 DiskIo - Disk Io Protocol.
493 PartHeader - the source Partition table header structure
497 TRUE - Restoring succeeds
498 FALSE - Restoring failed
504 EFI_PARTITION_TABLE_HEADER
*PartHdr
;
511 BlockSize
= BlockIo
->Media
->BlockSize
;
513 PartHdr
= AllocateZeroPool (BlockSize
);
515 if (PartHdr
== NULL
) {
516 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
520 PEntryLBA
= (PartHeader
->MyLBA
== PRIMARY_PART_HEADER_LBA
) ? \
521 (PartHeader
->LastUsableLBA
+ 1) : \
522 (PRIMARY_PART_HEADER_LBA
+ 1);
524 CopyMem (PartHdr
, PartHeader
, sizeof (EFI_PARTITION_TABLE_HEADER
));
526 PartHdr
->MyLBA
= PartHeader
->AlternateLBA
;
527 PartHdr
->AlternateLBA
= PartHeader
->MyLBA
;
528 PartHdr
->PartitionEntryLBA
= PEntryLBA
;
529 PartitionSetCrc ((EFI_TABLE_HEADER
*) PartHdr
);
531 Status
= BlockIo
->WriteBlocks (BlockIo
, BlockIo
->Media
->MediaId
, PartHdr
->MyLBA
, BlockSize
, PartHdr
);
532 if (EFI_ERROR (Status
)) {
536 Ptr
= AllocatePool (PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
);
538 DEBUG ((EFI_D_ERROR
, " Allocate pool effor\n"));
539 Status
= EFI_OUT_OF_RESOURCES
;
543 Status
= DiskIo
->ReadDisk (
545 BlockIo
->Media
->MediaId
,
546 MultU64x32(PartHeader
->PartitionEntryLBA
, BlockIo
->Media
->BlockSize
),
547 PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
,
550 if (EFI_ERROR (Status
)) {
554 Status
= DiskIo
->WriteDisk (
556 BlockIo
->Media
->MediaId
,
557 MultU64x32(PEntryLBA
, BlockIo
->Media
->BlockSize
),
558 PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
,
566 if (EFI_ERROR (Status
)) {
575 PartitionCheckGptEntry (
576 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
,
577 IN EFI_PARTITION_ENTRY
*PartEntry
,
578 OUT EFI_PARTITION_ENTRY_STATUS
*PEntryStatus
584 Check each partition entry for its range
588 PartHeader - the partition table header
589 PartEntry - the partition entry array
590 PEntryStatus - the partition entry status array recording the status of
603 DEBUG ((EFI_D_INFO
, " start check partition entries\n"));
604 for (Index1
= 0; Index1
< PartHeader
->NumberOfPartitionEntries
; Index1
++) {
605 if (CompareGuid (&PartEntry
[Index1
].PartitionTypeGUID
, &gEfiPartTypeUnusedGuid
)) {
609 StartingLBA
= PartEntry
[Index1
].StartingLBA
;
610 EndingLBA
= PartEntry
[Index1
].EndingLBA
;
611 if (StartingLBA
> EndingLBA
||
612 StartingLBA
< PartHeader
->FirstUsableLBA
||
613 StartingLBA
> PartHeader
->LastUsableLBA
||
614 EndingLBA
< PartHeader
->FirstUsableLBA
||
615 EndingLBA
> PartHeader
->LastUsableLBA
617 PEntryStatus
[Index1
].OutOfRange
= TRUE
;
621 for (Index2
= Index1
+ 1; Index2
< PartHeader
->NumberOfPartitionEntries
; Index2
++) {
623 if (CompareGuid (&PartEntry
[Index2
].PartitionTypeGUID
, &gEfiPartTypeUnusedGuid
)) {
627 if (PartEntry
[Index2
].EndingLBA
>= StartingLBA
&& PartEntry
[Index2
].StartingLBA
<= EndingLBA
) {
629 // This region overlaps with the Index1'th region
631 PEntryStatus
[Index1
].Overlap
= TRUE
;
632 PEntryStatus
[Index2
].Overlap
= TRUE
;
639 DEBUG ((EFI_D_INFO
, " End check partition entries\n"));
645 IN OUT EFI_TABLE_HEADER
*Hdr
651 Updates the CRC32 value in the table header
655 Hdr - The table to update
663 PartitionSetCrcAltSize (Hdr
->HeaderSize
, Hdr
);
668 PartitionSetCrcAltSize (
670 IN OUT EFI_TABLE_HEADER
*Hdr
676 Updates the CRC32 value in the table header
680 Size - The size of the table
681 Hdr - The table to update
692 gBS
->CalculateCrc32 ((UINT8
*) Hdr
, Size
, &Crc
);
700 IN OUT EFI_TABLE_HEADER
*Hdr
706 Checks the CRC32 value in the table header
710 MaxSize - Max Size limit
711 Hdr - The table to check
715 TRUE if the CRC is OK in the table
719 return PartitionCheckCrcAltSize (MaxSize
, Hdr
->HeaderSize
, Hdr
);
724 PartitionCheckCrcAltSize (
727 IN OUT EFI_TABLE_HEADER
*Hdr
733 Checks the CRC32 value in the table header
737 MaxSize - Max Size Limit
738 Size - The size of the table
739 Hdr - The table to check
743 TRUE if the CRC is OK in the table
755 // If header size is 0 CRC will pass so return FALSE here
760 if (MaxSize
&& Size
> MaxSize
) {
761 DEBUG ((EFI_D_ERROR
, "CheckCrc32: Size > MaxSize\n"));
765 // clear old crc from header
770 Status
= gBS
->CalculateCrc32 ((UINT8
*) Hdr
, Size
, &Crc
);
771 if (EFI_ERROR (Status
)) {
772 DEBUG ((EFI_D_ERROR
, "CheckCrc32: Crc calculation failed\n"));
785 DEBUG ((EFI_D_ERROR
, "CheckCrc32: Crc check failed\n"));
789 return (BOOLEAN
) (OrgCrc
== Crc
);