2 Decode a hard disk partitioned with the GPT scheme in the UEFI 2.0
5 Copyright (c) 2006 - 2008, Intel Corporation. <BR>
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 Install child handles if the Handle supports GPT partition structure.
23 @param[in] BlockIo Parent BlockIo interface
24 @param[in] DiskIo Disk Io protocol.
25 @param[in] Lba The starting Lba of the Partition Table
26 @param[out] PartHeader Stores the partition table that is read
28 @retval TRUE The partition table is valid
29 @retval FALSE The partition table is not valid
33 PartitionValidGptTable (
34 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
35 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
37 OUT EFI_PARTITION_TABLE_HEADER
*PartHeader
42 Check if the CRC field in the Partition table header is valid
43 for Partition entry array.
45 @param[in] BlockIo Parent BlockIo interface
46 @param[in] DiskIo Disk Io Protocol.
47 @param[in] PartHeader Partition table header structure
49 @retval TRUE the CRC is valid
50 @retval FALSE the CRC is invalid
54 PartitionCheckGptEntryArrayCRC (
55 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
56 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
57 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
62 Restore Partition Table to its alternate place
63 (Primary -> Backup or Backup -> Primary)
65 @param[in] BlockIo Parent BlockIo interface
66 @param[in] DiskIo Disk Io Protocol.
67 @param[in] PartHeader Partition table header structure
69 @retval TRUE Restoring succeeds
70 @retval FALSE Restoring failed
74 PartitionRestoreGptTable (
75 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
76 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
77 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
82 Restore Partition Table to its alternate place.
83 (Primary -> Backup or Backup -> Primary)
85 @param[in] PartHeader Partition table header structure
86 @param[in] PartEntry The partition entry array
87 @param[out] PEntryStatus the partition entry status array
88 recording the status of each partition
92 PartitionCheckGptEntry (
93 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
,
94 IN EFI_PARTITION_ENTRY
*PartEntry
,
95 OUT EFI_PARTITION_ENTRY_STATUS
*PEntryStatus
100 Checks the CRC32 value in the table header.
102 @param MaxSize Max Size limit
103 @param Size The size of the table
104 @param Hdr Table to check
106 @return TRUE CRC Valid
107 @return FALSE CRC Invalid
111 PartitionCheckCrcAltSize (
114 IN OUT EFI_TABLE_HEADER
*Hdr
119 Checks the CRC32 value in the table header.
121 @param MaxSize Max Size limit
122 @param Hdr Table to check
124 @return TRUE CRC Valid
125 @return FALSE CRC Invalid
131 IN OUT EFI_TABLE_HEADER
*Hdr
136 Updates the CRC32 value in the table header.
138 @param Size The size of the table
139 @param Hdr Table to update
143 PartitionSetCrcAltSize (
145 IN OUT EFI_TABLE_HEADER
*Hdr
150 Updates the CRC32 value in the table header.
152 @param Hdr Table to update
157 IN OUT EFI_TABLE_HEADER
*Hdr
161 Install child handles if the Handle supports GPT partition structure.
163 @param[in] This - Calling context.
164 @param[in] Handle - Parent Handle
165 @param[in] DiskIo - Parent DiskIo interface
166 @param[in] BlockIo - Parent BlockIo interface
167 @param[in] DevicePath - Parent Device Path
169 @retval EFI_SUCCESS Valid GPT disk
170 @retval EFI_MEDIA_CHANGED Media changed Detected
171 @retval other Not a valid GPT disk
175 PartitionInstallGptChildHandles (
176 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
177 IN EFI_HANDLE Handle
,
178 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
179 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
180 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
186 MASTER_BOOT_RECORD
*ProtectiveMbr
;
187 EFI_PARTITION_TABLE_HEADER
*PrimaryHeader
;
188 EFI_PARTITION_TABLE_HEADER
*BackupHeader
;
189 EFI_PARTITION_ENTRY
*PartEntry
;
190 EFI_PARTITION_ENTRY_STATUS
*PEntryStatus
;
192 EFI_STATUS GptValidStatus
;
193 HARDDRIVE_DEVICE_PATH HdDev
;
195 ProtectiveMbr
= NULL
;
196 PrimaryHeader
= NULL
;
201 BlockSize
= BlockIo
->Media
->BlockSize
;
202 LastBlock
= BlockIo
->Media
->LastBlock
;
204 DEBUG ((EFI_D_INFO
, " BlockSize : %d \n", BlockSize
));
205 DEBUG ((EFI_D_INFO
, " LastBlock : %lx \n", LastBlock
));
207 GptValidStatus
= EFI_NOT_FOUND
;
210 // Allocate a buffer for the Protective MBR
212 ProtectiveMbr
= AllocatePool (BlockSize
);
213 if (ProtectiveMbr
== NULL
) {
214 return EFI_NOT_FOUND
;
218 // Read the Protective MBR from LBA #0
220 Status
= BlockIo
->ReadBlocks (
222 BlockIo
->Media
->MediaId
,
224 BlockIo
->Media
->BlockSize
,
227 if (EFI_ERROR (Status
)) {
228 GptValidStatus
= Status
;
232 // Verify that the Protective MBR is valid
234 if (ProtectiveMbr
->Partition
[0].BootIndicator
!= 0x00 ||
235 ProtectiveMbr
->Partition
[0].OSIndicator
!= PMBR_GPT_PARTITION
||
236 UNPACK_UINT32 (ProtectiveMbr
->Partition
[0].StartingLBA
) != 1
242 // Allocate the GPT structures
244 PrimaryHeader
= AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER
));
245 if (PrimaryHeader
== NULL
) {
249 BackupHeader
= AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER
));
250 if (BackupHeader
== NULL
) {
255 // Check primary and backup partition tables
257 if (!PartitionValidGptTable (BlockIo
, DiskIo
, PRIMARY_PART_HEADER_LBA
, PrimaryHeader
)) {
258 DEBUG ((EFI_D_INFO
, " Not Valid primary partition table\n"));
260 if (!PartitionValidGptTable (BlockIo
, DiskIo
, LastBlock
, BackupHeader
)) {
261 DEBUG ((EFI_D_INFO
, " Not Valid backup partition table\n"));
264 DEBUG ((EFI_D_INFO
, " Valid backup partition table\n"));
265 DEBUG ((EFI_D_INFO
, " Restore primary partition table by the backup\n"));
266 if (!PartitionRestoreGptTable (BlockIo
, DiskIo
, BackupHeader
)) {
267 DEBUG ((EFI_D_INFO
, " Restore primary partition table error\n"));
270 if (PartitionValidGptTable (BlockIo
, DiskIo
, BackupHeader
->AlternateLBA
, PrimaryHeader
)) {
271 DEBUG ((EFI_D_INFO
, " Restore backup partition table success\n"));
274 } else if (!PartitionValidGptTable (BlockIo
, DiskIo
, PrimaryHeader
->AlternateLBA
, BackupHeader
)) {
275 DEBUG ((EFI_D_INFO
, " Valid primary and !Valid backup partition table\n"));
276 DEBUG ((EFI_D_INFO
, " Restore backup partition table by the primary\n"));
277 if (!PartitionRestoreGptTable (BlockIo
, DiskIo
, PrimaryHeader
)) {
278 DEBUG ((EFI_D_INFO
, " Restore backup partition table error\n"));
281 if (PartitionValidGptTable (BlockIo
, DiskIo
, PrimaryHeader
->AlternateLBA
, BackupHeader
)) {
282 DEBUG ((EFI_D_INFO
, " Restore backup partition table success\n"));
287 DEBUG ((EFI_D_INFO
, " Valid primary and Valid backup partition table\n"));
290 // Read the EFI Partition Entries
292 PartEntry
= AllocatePool (PrimaryHeader
->NumberOfPartitionEntries
* sizeof (EFI_PARTITION_ENTRY
));
293 if (PartEntry
== NULL
) {
294 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
298 Status
= DiskIo
->ReadDisk (
300 BlockIo
->Media
->MediaId
,
301 MultU64x32(PrimaryHeader
->PartitionEntryLBA
, BlockSize
),
302 PrimaryHeader
->NumberOfPartitionEntries
* (PrimaryHeader
->SizeOfPartitionEntry
),
305 if (EFI_ERROR (Status
)) {
306 GptValidStatus
= Status
;
307 DEBUG ((EFI_D_ERROR
, " Partition Entry ReadBlocks error\n"));
311 DEBUG ((EFI_D_INFO
, " Partition entries read block success\n"));
313 DEBUG ((EFI_D_INFO
, " Number of partition entries: %d\n", PrimaryHeader
->NumberOfPartitionEntries
));
315 PEntryStatus
= AllocateZeroPool (PrimaryHeader
->NumberOfPartitionEntries
* sizeof (EFI_PARTITION_ENTRY_STATUS
));
316 if (PEntryStatus
== NULL
) {
317 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
322 // Check the integrity of partition entries
324 PartitionCheckGptEntry (PrimaryHeader
, PartEntry
, PEntryStatus
);
327 // If we got this far the GPT layout of the disk is valid and we should return true
329 GptValidStatus
= EFI_SUCCESS
;
332 // Create child device handles
334 for (Index
= 0; Index
< PrimaryHeader
->NumberOfPartitionEntries
; Index
++) {
335 if (CompareGuid (&PartEntry
[Index
].PartitionTypeGUID
, &gEfiPartTypeUnusedGuid
) ||
336 PEntryStatus
[Index
].OutOfRange
||
337 PEntryStatus
[Index
].Overlap
340 // Don't use null EFI Partition Entries or Invalid Partition Entries
345 ZeroMem (&HdDev
, sizeof (HdDev
));
346 HdDev
.Header
.Type
= MEDIA_DEVICE_PATH
;
347 HdDev
.Header
.SubType
= MEDIA_HARDDRIVE_DP
;
348 SetDevicePathNodeLength (&HdDev
.Header
, sizeof (HdDev
));
350 HdDev
.PartitionNumber
= (UINT32
) Index
+ 1;
351 HdDev
.MBRType
= MBR_TYPE_EFI_PARTITION_TABLE_HEADER
;
352 HdDev
.SignatureType
= SIGNATURE_TYPE_GUID
;
353 HdDev
.PartitionStart
= PartEntry
[Index
].StartingLBA
;
354 HdDev
.PartitionSize
= PartEntry
[Index
].EndingLBA
- PartEntry
[Index
].StartingLBA
+ 1;
355 CopyMem (HdDev
.Signature
, &PartEntry
[Index
].UniquePartitionGUID
, sizeof (EFI_GUID
));
357 DEBUG ((EFI_D_INFO
, " Index : %d\n", (UINT32
) Index
));
358 DEBUG ((EFI_D_INFO
, " Start LBA : %lx\n", (UINT64
) HdDev
.PartitionStart
));
359 DEBUG ((EFI_D_INFO
, " End LBA : %lx\n", (UINT64
) PartEntry
[Index
].EndingLBA
));
360 DEBUG ((EFI_D_INFO
, " Partition size: %lx\n", (UINT64
) HdDev
.PartitionSize
));
361 DEBUG ((EFI_D_INFO
, " Start : %lx", MultU64x32 (PartEntry
[Index
].StartingLBA
, BlockSize
)));
362 DEBUG ((EFI_D_INFO
, " End : %lx\n", MultU64x32 (PartEntry
[Index
].EndingLBA
, BlockSize
)));
364 Status
= PartitionInstallChildHandle (
370 (EFI_DEVICE_PATH_PROTOCOL
*) &HdDev
,
371 PartEntry
[Index
].StartingLBA
,
372 PartEntry
[Index
].EndingLBA
,
374 CompareGuid(&PartEntry
[Index
].PartitionTypeGUID
, &gEfiPartTypeSystemPartGuid
)
378 DEBUG ((EFI_D_INFO
, "Prepare to Free Pool\n"));
381 if (ProtectiveMbr
!= NULL
) {
382 FreePool (ProtectiveMbr
);
384 if (PrimaryHeader
!= NULL
) {
385 FreePool (PrimaryHeader
);
387 if (BackupHeader
!= NULL
) {
388 FreePool (BackupHeader
);
390 if (PartEntry
!= NULL
) {
391 FreePool (PartEntry
);
393 if (PEntryStatus
!= NULL
) {
394 FreePool (PEntryStatus
);
397 return GptValidStatus
;
402 Install child handles if the Handle supports GPT partition structure.
404 @param[in] BlockIo Parent BlockIo interface
405 @param[in] DiskIo Disk Io protocol.
406 @param[in] Lba The starting Lba of the Partition Table
407 @param[out] PartHeader Stores the partition table that is read
409 @retval TRUE The partition table is valid
410 @retval FALSE The partition table is not valid
414 PartitionValidGptTable (
415 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
416 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
418 OUT EFI_PARTITION_TABLE_HEADER
*PartHeader
423 EFI_PARTITION_TABLE_HEADER
*PartHdr
;
425 BlockSize
= BlockIo
->Media
->BlockSize
;
427 PartHdr
= AllocateZeroPool (BlockSize
);
429 if (PartHdr
== NULL
) {
430 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
434 // Read the EFI Partition Table Header
436 Status
= BlockIo
->ReadBlocks (
438 BlockIo
->Media
->MediaId
,
443 if (EFI_ERROR (Status
)) {
448 if ((PartHdr
->Header
.Signature
!= EFI_PTAB_HEADER_ID
) ||
449 !PartitionCheckCrc (BlockSize
, &PartHdr
->Header
) ||
450 PartHdr
->MyLBA
!= Lba
452 DEBUG ((EFI_D_INFO
, "Invalid efi partition table header\n"));
457 CopyMem (PartHeader
, PartHdr
, sizeof (EFI_PARTITION_TABLE_HEADER
));
458 if (!PartitionCheckGptEntryArrayCRC (BlockIo
, DiskIo
, PartHeader
)) {
463 DEBUG ((EFI_D_INFO
, " Valid efi partition table header\n"));
470 Check if the CRC field in the Partition table header is valid
471 for Partition entry array.
473 @param[in] BlockIo Parent BlockIo interface
474 @param[in] DiskIo Disk Io Protocol.
475 @param[in] PartHeader Partition table header structure
477 @retval TRUE the CRC is valid
478 @retval FALSE the CRC is invalid
482 PartitionCheckGptEntryArrayCRC (
483 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
484 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
485 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
494 // Read the EFI Partition Entries
496 Ptr
= AllocatePool (PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
);
498 DEBUG ((EFI_D_ERROR
, " Allocate pool error\n"));
502 Status
= DiskIo
->ReadDisk (
504 BlockIo
->Media
->MediaId
,
505 MultU64x32(PartHeader
->PartitionEntryLBA
, BlockIo
->Media
->BlockSize
),
506 PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
,
509 if (EFI_ERROR (Status
)) {
514 Size
= PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
;
516 Status
= gBS
->CalculateCrc32 (Ptr
, Size
, &Crc
);
517 if (EFI_ERROR (Status
)) {
518 DEBUG ((EFI_D_ERROR
, "CheckPEntryArrayCRC: Crc calculation failed\n"));
525 return (BOOLEAN
) (PartHeader
->PartitionEntryArrayCRC32
== Crc
);
530 Restore Partition Table to its alternate place
531 (Primary -> Backup or Backup -> Primary)
533 @param[in] BlockIo Parent BlockIo interface
534 @param[in] DiskIo Disk Io Protocol.
535 @param[in] PartHeader Partition table header structure
537 @retval TRUE Restoring succeeds
538 @retval FALSE Restoring failed
542 PartitionRestoreGptTable (
543 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
544 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
545 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
550 EFI_PARTITION_TABLE_HEADER
*PartHdr
;
557 BlockSize
= BlockIo
->Media
->BlockSize
;
559 PartHdr
= AllocateZeroPool (BlockSize
);
561 if (PartHdr
== NULL
) {
562 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
566 PEntryLBA
= (PartHeader
->MyLBA
== PRIMARY_PART_HEADER_LBA
) ? \
567 (PartHeader
->LastUsableLBA
+ 1) : \
568 (PRIMARY_PART_HEADER_LBA
+ 1);
570 CopyMem (PartHdr
, PartHeader
, sizeof (EFI_PARTITION_TABLE_HEADER
));
572 PartHdr
->MyLBA
= PartHeader
->AlternateLBA
;
573 PartHdr
->AlternateLBA
= PartHeader
->MyLBA
;
574 PartHdr
->PartitionEntryLBA
= PEntryLBA
;
575 PartitionSetCrc ((EFI_TABLE_HEADER
*) PartHdr
);
577 Status
= BlockIo
->WriteBlocks (BlockIo
, BlockIo
->Media
->MediaId
, PartHdr
->MyLBA
, BlockSize
, PartHdr
);
578 if (EFI_ERROR (Status
)) {
582 Ptr
= AllocatePool (PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
);
584 DEBUG ((EFI_D_ERROR
, " Allocate pool effor\n"));
585 Status
= EFI_OUT_OF_RESOURCES
;
589 Status
= DiskIo
->ReadDisk (
591 BlockIo
->Media
->MediaId
,
592 MultU64x32(PartHeader
->PartitionEntryLBA
, BlockIo
->Media
->BlockSize
),
593 PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
,
596 if (EFI_ERROR (Status
)) {
600 Status
= DiskIo
->WriteDisk (
602 BlockIo
->Media
->MediaId
,
603 MultU64x32(PEntryLBA
, BlockIo
->Media
->BlockSize
),
604 PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
,
615 if (EFI_ERROR (Status
)) {
624 Restore Partition Table to its alternate place.
625 (Primary -> Backup or Backup -> Primary)
627 @param[in] PartHeader Partition table header structure
628 @param[in] PartEntry The partition entry array
629 @param[out] PEntryStatus the partition entry status array
630 recording the status of each partition
634 PartitionCheckGptEntry (
635 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
,
636 IN EFI_PARTITION_ENTRY
*PartEntry
,
637 OUT EFI_PARTITION_ENTRY_STATUS
*PEntryStatus
645 DEBUG ((EFI_D_INFO
, " start check partition entries\n"));
646 for (Index1
= 0; Index1
< PartHeader
->NumberOfPartitionEntries
; Index1
++) {
647 if (CompareGuid (&PartEntry
[Index1
].PartitionTypeGUID
, &gEfiPartTypeUnusedGuid
)) {
651 StartingLBA
= PartEntry
[Index1
].StartingLBA
;
652 EndingLBA
= PartEntry
[Index1
].EndingLBA
;
653 if (StartingLBA
> EndingLBA
||
654 StartingLBA
< PartHeader
->FirstUsableLBA
||
655 StartingLBA
> PartHeader
->LastUsableLBA
||
656 EndingLBA
< PartHeader
->FirstUsableLBA
||
657 EndingLBA
> PartHeader
->LastUsableLBA
659 PEntryStatus
[Index1
].OutOfRange
= TRUE
;
663 for (Index2
= Index1
+ 1; Index2
< PartHeader
->NumberOfPartitionEntries
; Index2
++) {
665 if (CompareGuid (&PartEntry
[Index2
].PartitionTypeGUID
, &gEfiPartTypeUnusedGuid
)) {
669 if (PartEntry
[Index2
].EndingLBA
>= StartingLBA
&& PartEntry
[Index2
].StartingLBA
<= EndingLBA
) {
671 // This region overlaps with the Index1'th region
673 PEntryStatus
[Index1
].Overlap
= TRUE
;
674 PEntryStatus
[Index2
].Overlap
= TRUE
;
681 DEBUG ((EFI_D_INFO
, " End check partition entries\n"));
686 Updates the CRC32 value in the table header.
688 @param Hdr Table to update
693 IN OUT EFI_TABLE_HEADER
*Hdr
696 PartitionSetCrcAltSize (Hdr
->HeaderSize
, Hdr
);
701 Updates the CRC32 value in the table header.
703 @param Size The size of the table
704 @param Hdr Table to update
708 PartitionSetCrcAltSize (
710 IN OUT EFI_TABLE_HEADER
*Hdr
716 gBS
->CalculateCrc32 ((UINT8
*) Hdr
, Size
, &Crc
);
722 Checks the CRC32 value in the table header.
724 @param MaxSize Max Size limit
725 @param Hdr Table to check
727 @return TRUE CRC Valid
728 @return FALSE CRC Invalid
734 IN OUT EFI_TABLE_HEADER
*Hdr
737 return PartitionCheckCrcAltSize (MaxSize
, Hdr
->HeaderSize
, Hdr
);
742 Checks the CRC32 value in the table header.
744 @param MaxSize Max Size limit
745 @param Size The size of the table
746 @param Hdr Table to check
748 @return TRUE CRC Valid
749 @return FALSE CRC Invalid
753 PartitionCheckCrcAltSize (
756 IN OUT EFI_TABLE_HEADER
*Hdr
767 // If header size is 0 CRC will pass so return FALSE here
772 if ((MaxSize
!= 0) && (Size
> MaxSize
)) {
773 DEBUG ((EFI_D_ERROR
, "CheckCrc32: Size > MaxSize\n"));
777 // clear old crc from header
782 Status
= gBS
->CalculateCrc32 ((UINT8
*) Hdr
, Size
, &Crc
);
783 if (EFI_ERROR (Status
)) {
784 DEBUG ((EFI_D_ERROR
, "CheckCrc32: Crc calculation failed\n"));
797 DEBUG ((EFI_D_ERROR
, "CheckCrc32: Crc check failed\n"));
801 return (BOOLEAN
) (OrgCrc
== Crc
);