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"
28 PartitionValidGptTable (
29 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
30 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
32 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
43 PartitionRestoreGptTable (
44 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
45 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
46 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
50 PartitionCheckGptEntry (
51 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
,
52 IN EFI_PARTITION_ENTRY
*PartEntry
,
53 OUT EFI_PARTITION_ENTRY_STATUS
*PEntryStatus
57 PartitionCheckCrcAltSize (
60 IN OUT EFI_TABLE_HEADER
*Hdr
66 IN OUT EFI_TABLE_HEADER
*Hdr
70 PartitionSetCrcAltSize (
72 IN OUT EFI_TABLE_HEADER
*Hdr
77 IN OUT EFI_TABLE_HEADER
*Hdr
81 PartitionInstallGptChildHandles (
82 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
84 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
85 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
86 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
91 Install child handles if the Handle supports GPT partition structure.
94 This - Calling context.
95 Handle - Parent Handle
96 DiskIo - Parent DiskIo interface
97 BlockIo - Parent BlockIo interface
98 DevicePath - Parent Device Path
101 TRUE - Valid GPT disk
102 FALSE - Not a valid GPT disk
109 MASTER_BOOT_RECORD
*ProtectiveMbr
;
110 EFI_PARTITION_TABLE_HEADER
*PrimaryHeader
;
111 EFI_PARTITION_TABLE_HEADER
*BackupHeader
;
112 EFI_PARTITION_ENTRY
*PartEntry
;
113 EFI_PARTITION_ENTRY_STATUS
*PEntryStatus
;
116 HARDDRIVE_DEVICE_PATH HdDev
;
118 ProtectiveMbr
= NULL
;
119 PrimaryHeader
= NULL
;
124 BlockSize
= BlockIo
->Media
->BlockSize
;
125 LastBlock
= BlockIo
->Media
->LastBlock
;
127 DEBUG ((EFI_D_INFO
, " BlockSize : %d \n", BlockSize
));
128 DEBUG ((EFI_D_INFO
, " LastBlock : %x \n", LastBlock
));
133 // Allocate a buffer for the Protective MBR
135 ProtectiveMbr
= AllocatePool (BlockSize
);
136 if (ProtectiveMbr
== NULL
) {
141 // Read the Protective MBR from LBA #0
143 Status
= BlockIo
->ReadBlocks (
145 BlockIo
->Media
->MediaId
,
147 BlockIo
->Media
->BlockSize
,
150 if (EFI_ERROR (Status
)) {
154 // Verify that the Protective MBR is valid
156 if (ProtectiveMbr
->Partition
[0].BootIndicator
!= 0x00 ||
157 ProtectiveMbr
->Partition
[0].OSIndicator
!= 0xEE ||
158 UNPACK_UINT32 (ProtectiveMbr
->Partition
[0].StartingLBA
) != 1
164 // Allocate the GPT structures
166 PrimaryHeader
= AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER
));
167 if (PrimaryHeader
== NULL
) {
171 BackupHeader
= AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER
));
173 if (BackupHeader
== NULL
) {
178 // Check primary and backup partition tables
180 if (!PartitionValidGptTable (BlockIo
, DiskIo
, PRIMARY_PART_HEADER_LBA
, PrimaryHeader
)) {
181 DEBUG ((EFI_D_INFO
, " Not Valid primary partition table\n"));
183 if (!PartitionValidGptTable (BlockIo
, DiskIo
, LastBlock
, BackupHeader
)) {
184 DEBUG ((EFI_D_INFO
, " Not Valid backup partition table\n"));
187 DEBUG ((EFI_D_INFO
, " Valid backup partition table\n"));
188 DEBUG ((EFI_D_INFO
, " Restore primary partition table by the backup\n"));
189 if (!PartitionRestoreGptTable (BlockIo
, DiskIo
, BackupHeader
)) {
190 DEBUG ((EFI_D_INFO
, " Restore primary partition table error\n"));
193 if (PartitionValidGptTable (BlockIo
, DiskIo
, BackupHeader
->AlternateLBA
, PrimaryHeader
)) {
194 DEBUG ((EFI_D_INFO
, " Restore backup partition table success\n"));
197 } else if (!PartitionValidGptTable (BlockIo
, DiskIo
, PrimaryHeader
->AlternateLBA
, BackupHeader
)) {
198 DEBUG ((EFI_D_INFO
, " Valid primary and !Valid backup partition table\n"));
199 DEBUG ((EFI_D_INFO
, " Restore backup partition table by the primary\n"));
200 if (!PartitionRestoreGptTable (BlockIo
, DiskIo
, PrimaryHeader
)) {
201 DEBUG ((EFI_D_INFO
, " Restore backup partition table error\n"));
204 if (PartitionValidGptTable (BlockIo
, DiskIo
, PrimaryHeader
->AlternateLBA
, BackupHeader
)) {
205 DEBUG ((EFI_D_INFO
, " Restore backup partition table success\n"));
210 DEBUG ((EFI_D_INFO
, " Valid primary and Valid backup partition table\n"));
213 // Read the EFI Partition Entries
215 PartEntry
= AllocatePool (PrimaryHeader
->NumberOfPartitionEntries
* sizeof (EFI_PARTITION_ENTRY
));
216 if (PartEntry
== NULL
) {
217 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
221 Status
= DiskIo
->ReadDisk (
223 BlockIo
->Media
->MediaId
,
224 MultU64x32(PrimaryHeader
->PartitionEntryLBA
, BlockSize
),
225 PrimaryHeader
->NumberOfPartitionEntries
* (PrimaryHeader
->SizeOfPartitionEntry
),
228 if (EFI_ERROR (Status
)) {
229 DEBUG ((EFI_D_INFO
, " Partition Entry ReadBlocks error\n"));
233 DEBUG ((EFI_D_INFO
, " Partition entries read block success\n"));
235 DEBUG ((EFI_D_INFO
, " Number of partition entries: %d\n", PrimaryHeader
->NumberOfPartitionEntries
));
237 PEntryStatus
= AllocateZeroPool (PrimaryHeader
->NumberOfPartitionEntries
* sizeof (EFI_PARTITION_ENTRY_STATUS
));
238 if (PEntryStatus
== NULL
) {
239 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
244 // Check the integrity of partition entries
246 PartitionCheckGptEntry (PrimaryHeader
, PartEntry
, PEntryStatus
);
249 // If we got this far the GPT layout of the disk is valid and we should return true
254 // Create child device handles
256 for (Index
= 0; Index
< PrimaryHeader
->NumberOfPartitionEntries
; Index
++) {
257 if (CompareGuid (&PartEntry
[Index
].PartitionTypeGUID
, &gEfiPartTypeUnusedGuid
) ||
258 PEntryStatus
[Index
].OutOfRange
||
259 PEntryStatus
[Index
].Overlap
262 // Don't use null EFI Partition Entries or Invalid Partition Entries
267 ZeroMem (&HdDev
, sizeof (HdDev
));
268 HdDev
.Header
.Type
= MEDIA_DEVICE_PATH
;
269 HdDev
.Header
.SubType
= MEDIA_HARDDRIVE_DP
;
270 SetDevicePathNodeLength (&HdDev
.Header
, sizeof (HdDev
));
272 HdDev
.PartitionNumber
= (UINT32
) Index
+ 1;
273 HdDev
.MBRType
= MBR_TYPE_EFI_PARTITION_TABLE_HEADER
;
274 HdDev
.SignatureType
= SIGNATURE_TYPE_GUID
;
275 HdDev
.PartitionStart
= PartEntry
[Index
].StartingLBA
;
276 HdDev
.PartitionSize
= PartEntry
[Index
].EndingLBA
- PartEntry
[Index
].StartingLBA
+ 1;
277 CopyMem (HdDev
.Signature
, &PartEntry
[Index
].UniquePartitionGUID
, sizeof (EFI_GUID
));
279 DEBUG ((EFI_D_INFO
, " Index : %d\n", Index
));
280 DEBUG ((EFI_D_INFO
, " Start LBA : %x\n", HdDev
.PartitionStart
));
281 DEBUG ((EFI_D_INFO
, " End LBA : %x\n", PartEntry
[Index
].EndingLBA
));
282 DEBUG ((EFI_D_INFO
, " Partition size: %x\n", HdDev
.PartitionSize
));
283 DEBUG ((EFI_D_INFO
, " Start : %x", MultU64x32 (PartEntry
[Index
].StartingLBA
, BlockSize
)));
284 DEBUG ((EFI_D_INFO
, " End : %x\n", MultU64x32 (PartEntry
[Index
].EndingLBA
, BlockSize
)));
286 Status
= PartitionInstallChildHandle (
292 (EFI_DEVICE_PATH_PROTOCOL
*) &HdDev
,
293 PartEntry
[Index
].StartingLBA
,
294 PartEntry
[Index
].EndingLBA
,
296 CompareGuid(&PartEntry
[Index
].PartitionTypeGUID
, &gEfiPartTypeSystemPartGuid
)
300 DEBUG ((EFI_D_INFO
, "Prepare to Free Pool\n"));
303 if (ProtectiveMbr
!= NULL
) {
304 gBS
->FreePool (ProtectiveMbr
);
306 if (PrimaryHeader
!= NULL
) {
307 gBS
->FreePool (PrimaryHeader
);
309 if (BackupHeader
!= NULL
) {
310 gBS
->FreePool (BackupHeader
);
312 if (PartEntry
!= NULL
) {
313 gBS
->FreePool (PartEntry
);
315 if (PEntryStatus
!= NULL
) {
316 gBS
->FreePool (PEntryStatus
);
323 PartitionValidGptTable (
324 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
325 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
327 OUT EFI_PARTITION_TABLE_HEADER
*PartHeader
332 Check if the GPT partition table is valid
335 BlockIo - Parent BlockIo interface
336 DiskIo - Disk Io protocol.
337 Lba - The starting Lba of the Partition Table
338 PartHeader - Stores the partition table that is read
341 TRUE - The partition table is valid
342 FALSE - The partition table is not valid
348 EFI_PARTITION_TABLE_HEADER
*PartHdr
;
350 BlockSize
= BlockIo
->Media
->BlockSize
;
352 PartHdr
= AllocateZeroPool (BlockSize
);
354 if (PartHdr
== NULL
) {
355 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
359 // Read the EFI Partition Table Header
361 Status
= BlockIo
->ReadBlocks (
363 BlockIo
->Media
->MediaId
,
368 if (EFI_ERROR (Status
)) {
369 gBS
->FreePool (PartHdr
);
373 if (CompareMem (&PartHdr
->Header
.Signature
, EFI_PTAB_HEADER_ID
, sizeof (UINT64
)) != 0 ||
374 !PartitionCheckCrc (BlockSize
, &PartHdr
->Header
) ||
375 PartHdr
->MyLBA
!= Lba
377 DEBUG ((EFI_D_INFO
, " !Valid efi partition table header\n"));
378 gBS
->FreePool (PartHdr
);
382 CopyMem (PartHeader
, PartHdr
, sizeof (EFI_PARTITION_TABLE_HEADER
));
383 if (!PartitionCheckGptEntryArrayCRC (BlockIo
, DiskIo
, PartHeader
)) {
384 gBS
->FreePool (PartHdr
);
388 DEBUG ((EFI_D_INFO
, " Valid efi partition table header\n"));
389 gBS
->FreePool (PartHdr
);
394 PartitionCheckGptEntryArrayCRC (
395 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
396 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
397 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
403 Check if the CRC field in the Partition table header is valid
404 for Partition entry array
408 BlockIo - parent BlockIo interface
409 DiskIo - Disk Io Protocol.
410 PartHeader - Partition table header structure
414 TRUE - the CRC is valid
415 FALSE - the CRC is invalid
425 // Read the EFI Partition Entries
427 Ptr
= AllocatePool (PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
);
429 DEBUG ((EFI_D_ERROR
, " Allocate pool error\n"));
433 Status
= DiskIo
->ReadDisk (
435 BlockIo
->Media
->MediaId
,
436 MultU64x32(PartHeader
->PartitionEntryLBA
, BlockIo
->Media
->BlockSize
),
437 PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
,
440 if (EFI_ERROR (Status
)) {
445 Size
= PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
;
447 Status
= gBS
->CalculateCrc32 (Ptr
, Size
, &Crc
);
448 if (EFI_ERROR (Status
)) {
449 DEBUG ((EFI_D_ERROR
, "CheckPEntryArrayCRC: Crc calculation failed\n"));
456 return (BOOLEAN
) (PartHeader
->PartitionEntryArrayCRC32
== Crc
);
460 PartitionRestoreGptTable (
461 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
462 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
463 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
469 Restore Partition Table to its alternate place
470 (Primary -> Backup or Backup -> Primary)
474 BlockIo - parent BlockIo interface
475 DiskIo - Disk Io Protocol.
476 PartHeader - the source Partition table header structure
480 TRUE - Restoring succeeds
481 FALSE - Restoring failed
487 EFI_PARTITION_TABLE_HEADER
*PartHdr
;
494 BlockSize
= BlockIo
->Media
->BlockSize
;
496 PartHdr
= AllocateZeroPool (BlockSize
);
498 if (PartHdr
== NULL
) {
499 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
503 PEntryLBA
= (PartHeader
->MyLBA
== PRIMARY_PART_HEADER_LBA
) ? \
504 (PartHeader
->LastUsableLBA
+ 1) : \
505 (PRIMARY_PART_HEADER_LBA
+ 1);
507 CopyMem (PartHdr
, PartHeader
, sizeof (EFI_PARTITION_TABLE_HEADER
));
509 PartHdr
->MyLBA
= PartHeader
->AlternateLBA
;
510 PartHdr
->AlternateLBA
= PartHeader
->MyLBA
;
511 PartHdr
->PartitionEntryLBA
= PEntryLBA
;
512 PartitionSetCrc ((EFI_TABLE_HEADER
*) PartHdr
);
514 Status
= BlockIo
->WriteBlocks (BlockIo
, BlockIo
->Media
->MediaId
, PartHdr
->MyLBA
, BlockSize
, PartHdr
);
515 if (EFI_ERROR (Status
)) {
519 Ptr
= AllocatePool (PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
);
521 DEBUG ((EFI_D_ERROR
, " Allocate pool effor\n"));
522 Status
= EFI_OUT_OF_RESOURCES
;
526 Status
= DiskIo
->ReadDisk (
528 BlockIo
->Media
->MediaId
,
529 MultU64x32(PartHeader
->PartitionEntryLBA
, BlockIo
->Media
->BlockSize
),
530 PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
,
533 if (EFI_ERROR (Status
)) {
537 Status
= DiskIo
->WriteDisk (
539 BlockIo
->Media
->MediaId
,
540 MultU64x32(PEntryLBA
, BlockIo
->Media
->BlockSize
),
541 PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
,
546 gBS
->FreePool (PartHdr
);
549 if (EFI_ERROR (Status
)) {
557 PartitionCheckGptEntry (
558 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
,
559 IN EFI_PARTITION_ENTRY
*PartEntry
,
560 OUT EFI_PARTITION_ENTRY_STATUS
*PEntryStatus
566 Check each partition entry for its range
570 PartHeader - the partition table header
571 PartEntry - the partition entry array
572 PEntryStatus - the partition entry status array recording the status of
585 DEBUG ((EFI_D_INFO
, " start check partition entries\n"));
586 for (Index1
= 0; Index1
< PartHeader
->NumberOfPartitionEntries
; Index1
++) {
587 if (CompareGuid (&PartEntry
[Index1
].PartitionTypeGUID
, &gEfiPartTypeUnusedGuid
)) {
591 StartingLBA
= PartEntry
[Index1
].StartingLBA
;
592 EndingLBA
= PartEntry
[Index1
].EndingLBA
;
593 if (StartingLBA
> EndingLBA
||
594 StartingLBA
< PartHeader
->FirstUsableLBA
||
595 StartingLBA
> PartHeader
->LastUsableLBA
||
596 EndingLBA
< PartHeader
->FirstUsableLBA
||
597 EndingLBA
> PartHeader
->LastUsableLBA
599 PEntryStatus
[Index1
].OutOfRange
= TRUE
;
603 for (Index2
= Index1
+ 1; Index2
< PartHeader
->NumberOfPartitionEntries
; Index2
++) {
605 if (CompareGuid (&PartEntry
[Index2
].PartitionTypeGUID
, &gEfiPartTypeUnusedGuid
)) {
609 if (PartEntry
[Index2
].EndingLBA
>= StartingLBA
&& PartEntry
[Index2
].StartingLBA
<= EndingLBA
) {
611 // This region overlaps with the Index1'th region
613 PEntryStatus
[Index1
].Overlap
= TRUE
;
614 PEntryStatus
[Index2
].Overlap
= TRUE
;
621 DEBUG ((EFI_D_INFO
, " End check partition entries\n"));
626 IN OUT EFI_TABLE_HEADER
*Hdr
632 Updates the CRC32 value in the table header
636 Hdr - The table to update
644 PartitionSetCrcAltSize (Hdr
->HeaderSize
, Hdr
);
648 PartitionSetCrcAltSize (
650 IN OUT EFI_TABLE_HEADER
*Hdr
656 Updates the CRC32 value in the table header
660 Size - The size of the table
661 Hdr - The table to update
672 gBS
->CalculateCrc32 ((UINT8
*) Hdr
, Size
, &Crc
);
679 IN OUT EFI_TABLE_HEADER
*Hdr
685 Checks the CRC32 value in the table header
689 MaxSize - Max Size limit
690 Hdr - The table to check
694 TRUE if the CRC is OK in the table
698 return PartitionCheckCrcAltSize (MaxSize
, Hdr
->HeaderSize
, Hdr
);
702 PartitionCheckCrcAltSize (
705 IN OUT EFI_TABLE_HEADER
*Hdr
711 Checks the CRC32 value in the table header
715 MaxSize - Max Size Limit
716 Size - The size of the table
717 Hdr - The table to check
721 TRUE if the CRC is OK in the table
733 // If header size is 0 CRC will pass so return FALSE here
738 if (MaxSize
&& Size
> MaxSize
) {
739 DEBUG ((EFI_D_ERROR
, "CheckCrc32: Size > MaxSize\n"));
743 // clear old crc from header
748 Status
= gBS
->CalculateCrc32 ((UINT8
*) Hdr
, Size
, &Crc
);
749 if (EFI_ERROR (Status
)) {
750 DEBUG ((EFI_D_ERROR
, "CheckCrc32: Crc calculation failed\n"));
763 DEBUG ((EFI_D_ERROR
, "CheckCrc32: Crc check failed\n"));
767 return (BOOLEAN
) (OrgCrc
== Crc
);