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"
26 PartitionValidGptTable (
27 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
28 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
30 OUT EFI_PARTITION_TABLE_HEADER
*PartHeader
34 PartitionCheckGptEntryArrayCRC (
35 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
36 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
37 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
41 PartitionRestoreGptTable (
42 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
43 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
44 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
48 PartitionCheckGptEntry (
49 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
,
50 IN EFI_PARTITION_ENTRY
*PartEntry
,
51 OUT EFI_PARTITION_ENTRY_STATUS
*PEntryStatus
55 PartitionCheckCrcAltSize (
58 IN OUT EFI_TABLE_HEADER
*Hdr
64 IN OUT EFI_TABLE_HEADER
*Hdr
68 PartitionSetCrcAltSize (
70 IN OUT EFI_TABLE_HEADER
*Hdr
75 IN OUT EFI_TABLE_HEADER
*Hdr
79 PartitionInstallGptChildHandles (
80 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
82 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
83 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
84 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
89 Install child handles if the Handle supports GPT partition structure.
92 This - Calling context.
93 Handle - Parent Handle
94 DiskIo - Parent DiskIo interface
95 BlockIo - Parent BlockIo interface
96 DevicePath - Parent Device Path
99 EFI_SUCCESS - Valid GPT disk
100 EFI_MEDIA_CHANGED - Media changed Detected
101 !EFI_SUCCESS - Not a valid GPT disk
108 MASTER_BOOT_RECORD
*ProtectiveMbr
;
109 EFI_PARTITION_TABLE_HEADER
*PrimaryHeader
;
110 EFI_PARTITION_TABLE_HEADER
*BackupHeader
;
111 EFI_PARTITION_ENTRY
*PartEntry
;
112 EFI_PARTITION_ENTRY_STATUS
*PEntryStatus
;
115 HARDDRIVE_DEVICE_PATH HdDev
;
117 ProtectiveMbr
= NULL
;
118 PrimaryHeader
= NULL
;
123 BlockSize
= BlockIo
->Media
->BlockSize
;
124 LastBlock
= BlockIo
->Media
->LastBlock
;
126 DEBUG ((EFI_D_INFO
, " BlockSize : %d \n", BlockSize
));
127 DEBUG ((EFI_D_INFO
, " LastBlock : %x \n", LastBlock
));
129 GptValid
= EFI_NOT_FOUND
;
132 // Allocate a buffer for the Protective MBR
134 ProtectiveMbr
= AllocatePool (BlockSize
);
135 if (ProtectiveMbr
== NULL
) {
136 return EFI_NOT_FOUND
;
140 // Read the Protective MBR from LBA #0
142 Status
= BlockIo
->ReadBlocks (
144 BlockIo
->Media
->MediaId
,
146 BlockIo
->Media
->BlockSize
,
149 if (EFI_ERROR (Status
)) {
154 // Verify that the Protective MBR is valid
156 if (ProtectiveMbr
->Partition
[0].BootIndicator
!= 0x00 ||
157 ProtectiveMbr
->Partition
[0].OSIndicator
!= PMBR_GPT_PARTITION
||
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
)) {
230 DEBUG ((EFI_D_INFO
, " Partition Entry ReadBlocks error\n"));
234 DEBUG ((EFI_D_INFO
, " Partition entries read block success\n"));
236 DEBUG ((EFI_D_INFO
, " Number of partition entries: %d\n", PrimaryHeader
->NumberOfPartitionEntries
));
238 PEntryStatus
= AllocateZeroPool (PrimaryHeader
->NumberOfPartitionEntries
* sizeof (EFI_PARTITION_ENTRY_STATUS
));
239 if (PEntryStatus
== NULL
) {
240 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
245 // Check the integrity of partition entries
247 PartitionCheckGptEntry (PrimaryHeader
, PartEntry
, PEntryStatus
);
250 // If we got this far the GPT layout of the disk is valid and we should return true
252 GptValid
= EFI_SUCCESS
;
255 // Create child device handles
257 for (Index
= 0; Index
< PrimaryHeader
->NumberOfPartitionEntries
; Index
++) {
258 if (CompareGuid (&PartEntry
[Index
].PartitionTypeGUID
, &gEfiPartTypeUnusedGuid
) ||
259 PEntryStatus
[Index
].OutOfRange
||
260 PEntryStatus
[Index
].Overlap
263 // Don't use null EFI Partition Entries or Invalid Partition Entries
268 ZeroMem (&HdDev
, sizeof (HdDev
));
269 HdDev
.Header
.Type
= MEDIA_DEVICE_PATH
;
270 HdDev
.Header
.SubType
= MEDIA_HARDDRIVE_DP
;
271 SetDevicePathNodeLength (&HdDev
.Header
, sizeof (HdDev
));
273 HdDev
.PartitionNumber
= (UINT32
) Index
+ 1;
274 HdDev
.MBRType
= MBR_TYPE_EFI_PARTITION_TABLE_HEADER
;
275 HdDev
.SignatureType
= SIGNATURE_TYPE_GUID
;
276 HdDev
.PartitionStart
= PartEntry
[Index
].StartingLBA
;
277 HdDev
.PartitionSize
= PartEntry
[Index
].EndingLBA
- PartEntry
[Index
].StartingLBA
+ 1;
278 CopyMem (HdDev
.Signature
, &PartEntry
[Index
].UniquePartitionGUID
, sizeof (EFI_GUID
));
280 DEBUG ((EFI_D_INFO
, " Index : %d\n", Index
));
281 DEBUG ((EFI_D_INFO
, " Start LBA : %x\n", HdDev
.PartitionStart
));
282 DEBUG ((EFI_D_INFO
, " End LBA : %x\n", PartEntry
[Index
].EndingLBA
));
283 DEBUG ((EFI_D_INFO
, " Partition size: %x\n", HdDev
.PartitionSize
));
284 DEBUG ((EFI_D_INFO
, " Start : %x", MultU64x32 (PartEntry
[Index
].StartingLBA
, BlockSize
)));
285 DEBUG ((EFI_D_INFO
, " End : %x\n", MultU64x32 (PartEntry
[Index
].EndingLBA
, BlockSize
)));
287 Status
= PartitionInstallChildHandle (
293 (EFI_DEVICE_PATH_PROTOCOL
*) &HdDev
,
294 PartEntry
[Index
].StartingLBA
,
295 PartEntry
[Index
].EndingLBA
,
297 CompareGuid(&PartEntry
[Index
].PartitionTypeGUID
, &gEfiPartTypeSystemPartGuid
)
301 DEBUG ((EFI_D_INFO
, "Prepare to Free Pool\n"));
304 if (ProtectiveMbr
!= NULL
) {
305 gBS
->FreePool (ProtectiveMbr
);
307 if (PrimaryHeader
!= NULL
) {
308 gBS
->FreePool (PrimaryHeader
);
310 if (BackupHeader
!= NULL
) {
311 gBS
->FreePool (BackupHeader
);
313 if (PartEntry
!= NULL
) {
314 gBS
->FreePool (PartEntry
);
316 if (PEntryStatus
!= NULL
) {
317 gBS
->FreePool (PEntryStatus
);
324 PartitionValidGptTable (
325 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
326 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
328 OUT EFI_PARTITION_TABLE_HEADER
*PartHeader
333 Check if the GPT partition table is valid
336 BlockIo - Parent BlockIo interface
337 DiskIo - Disk Io protocol.
338 Lba - The starting Lba of the Partition Table
339 PartHeader - Stores the partition table that is read
342 TRUE - The partition table is valid
343 FALSE - The partition table is not valid
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
)) {
370 gBS
->FreePool (PartHdr
);
374 if (CompareMem (&PartHdr
->Header
.Signature
, EFI_PTAB_HEADER_ID
, sizeof (UINT64
)) != 0 ||
375 !PartitionCheckCrc (BlockSize
, &PartHdr
->Header
) ||
376 PartHdr
->MyLBA
!= Lba
378 DEBUG ((EFI_D_INFO
, " !Valid efi partition table header\n"));
379 gBS
->FreePool (PartHdr
);
383 CopyMem (PartHeader
, PartHdr
, sizeof (EFI_PARTITION_TABLE_HEADER
));
384 if (!PartitionCheckGptEntryArrayCRC (BlockIo
, DiskIo
, PartHeader
)) {
385 gBS
->FreePool (PartHdr
);
389 DEBUG ((EFI_D_INFO
, " Valid efi partition table header\n"));
390 gBS
->FreePool (PartHdr
);
395 PartitionCheckGptEntryArrayCRC (
396 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
397 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
398 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
404 Check if the CRC field in the Partition table header is valid
405 for Partition entry array
409 BlockIo - parent BlockIo interface
410 DiskIo - Disk Io Protocol.
411 PartHeader - Partition table header structure
415 TRUE - the CRC is valid
416 FALSE - the CRC is invalid
426 // Read the EFI Partition Entries
428 Ptr
= AllocatePool (PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
);
430 DEBUG ((EFI_D_ERROR
, " Allocate pool error\n"));
434 Status
= DiskIo
->ReadDisk (
436 BlockIo
->Media
->MediaId
,
437 MultU64x32(PartHeader
->PartitionEntryLBA
, BlockIo
->Media
->BlockSize
),
438 PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
,
441 if (EFI_ERROR (Status
)) {
446 Size
= PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
;
448 Status
= gBS
->CalculateCrc32 (Ptr
, Size
, &Crc
);
449 if (EFI_ERROR (Status
)) {
450 DEBUG ((EFI_D_ERROR
, "CheckPEntryArrayCRC: Crc calculation failed\n"));
457 return (BOOLEAN
) (PartHeader
->PartitionEntryArrayCRC32
== Crc
);
461 PartitionRestoreGptTable (
462 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
463 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
464 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
470 Restore Partition Table to its alternate place
471 (Primary -> Backup or Backup -> Primary)
475 BlockIo - parent BlockIo interface
476 DiskIo - Disk Io Protocol.
477 PartHeader - the source Partition table header structure
481 TRUE - Restoring succeeds
482 FALSE - Restoring failed
488 EFI_PARTITION_TABLE_HEADER
*PartHdr
;
495 BlockSize
= BlockIo
->Media
->BlockSize
;
497 PartHdr
= AllocateZeroPool (BlockSize
);
499 if (PartHdr
== NULL
) {
500 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
504 PEntryLBA
= (PartHeader
->MyLBA
== PRIMARY_PART_HEADER_LBA
) ? \
505 (PartHeader
->LastUsableLBA
+ 1) : \
506 (PRIMARY_PART_HEADER_LBA
+ 1);
508 CopyMem (PartHdr
, PartHeader
, sizeof (EFI_PARTITION_TABLE_HEADER
));
510 PartHdr
->MyLBA
= PartHeader
->AlternateLBA
;
511 PartHdr
->AlternateLBA
= PartHeader
->MyLBA
;
512 PartHdr
->PartitionEntryLBA
= PEntryLBA
;
513 PartitionSetCrc ((EFI_TABLE_HEADER
*) PartHdr
);
515 Status
= BlockIo
->WriteBlocks (BlockIo
, BlockIo
->Media
->MediaId
, PartHdr
->MyLBA
, BlockSize
, PartHdr
);
516 if (EFI_ERROR (Status
)) {
520 Ptr
= AllocatePool (PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
);
522 DEBUG ((EFI_D_ERROR
, " Allocate pool effor\n"));
523 Status
= EFI_OUT_OF_RESOURCES
;
527 Status
= DiskIo
->ReadDisk (
529 BlockIo
->Media
->MediaId
,
530 MultU64x32(PartHeader
->PartitionEntryLBA
, BlockIo
->Media
->BlockSize
),
531 PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
,
534 if (EFI_ERROR (Status
)) {
538 Status
= DiskIo
->WriteDisk (
540 BlockIo
->Media
->MediaId
,
541 MultU64x32(PEntryLBA
, BlockIo
->Media
->BlockSize
),
542 PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
,
547 gBS
->FreePool (PartHdr
);
550 if (EFI_ERROR (Status
)) {
558 PartitionCheckGptEntry (
559 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
,
560 IN EFI_PARTITION_ENTRY
*PartEntry
,
561 OUT EFI_PARTITION_ENTRY_STATUS
*PEntryStatus
567 Check each partition entry for its range
571 PartHeader - the partition table header
572 PartEntry - the partition entry array
573 PEntryStatus - the partition entry status array recording the status of
586 DEBUG ((EFI_D_INFO
, " start check partition entries\n"));
587 for (Index1
= 0; Index1
< PartHeader
->NumberOfPartitionEntries
; Index1
++) {
588 if (CompareGuid (&PartEntry
[Index1
].PartitionTypeGUID
, &gEfiPartTypeUnusedGuid
)) {
592 StartingLBA
= PartEntry
[Index1
].StartingLBA
;
593 EndingLBA
= PartEntry
[Index1
].EndingLBA
;
594 if (StartingLBA
> EndingLBA
||
595 StartingLBA
< PartHeader
->FirstUsableLBA
||
596 StartingLBA
> PartHeader
->LastUsableLBA
||
597 EndingLBA
< PartHeader
->FirstUsableLBA
||
598 EndingLBA
> PartHeader
->LastUsableLBA
600 PEntryStatus
[Index1
].OutOfRange
= TRUE
;
604 for (Index2
= Index1
+ 1; Index2
< PartHeader
->NumberOfPartitionEntries
; Index2
++) {
606 if (CompareGuid (&PartEntry
[Index2
].PartitionTypeGUID
, &gEfiPartTypeUnusedGuid
)) {
610 if (PartEntry
[Index2
].EndingLBA
>= StartingLBA
&& PartEntry
[Index2
].StartingLBA
<= EndingLBA
) {
612 // This region overlaps with the Index1'th region
614 PEntryStatus
[Index1
].Overlap
= TRUE
;
615 PEntryStatus
[Index2
].Overlap
= TRUE
;
622 DEBUG ((EFI_D_INFO
, " End check partition entries\n"));
627 IN OUT EFI_TABLE_HEADER
*Hdr
633 Updates the CRC32 value in the table header
637 Hdr - The table to update
645 PartitionSetCrcAltSize (Hdr
->HeaderSize
, Hdr
);
649 PartitionSetCrcAltSize (
651 IN OUT EFI_TABLE_HEADER
*Hdr
657 Updates the CRC32 value in the table header
661 Size - The size of the table
662 Hdr - The table to update
673 gBS
->CalculateCrc32 ((UINT8
*) Hdr
, Size
, &Crc
);
680 IN OUT EFI_TABLE_HEADER
*Hdr
686 Checks the CRC32 value in the table header
690 MaxSize - Max Size limit
691 Hdr - The table to check
695 TRUE if the CRC is OK in the table
699 return PartitionCheckCrcAltSize (MaxSize
, Hdr
->HeaderSize
, Hdr
);
703 PartitionCheckCrcAltSize (
706 IN OUT EFI_TABLE_HEADER
*Hdr
712 Checks the CRC32 value in the table header
716 MaxSize - Max Size Limit
717 Size - The size of the table
718 Hdr - The table to check
722 TRUE if the CRC is OK in the table
734 // If header size is 0 CRC will pass so return FALSE here
739 if (MaxSize
&& Size
> MaxSize
) {
740 DEBUG ((EFI_D_ERROR
, "CheckCrc32: Size > MaxSize\n"));
744 // clear old crc from header
749 Status
= gBS
->CalculateCrc32 ((UINT8
*) Hdr
, Size
, &Crc
);
750 if (EFI_ERROR (Status
)) {
751 DEBUG ((EFI_D_ERROR
, "CheckCrc32: Crc calculation failed\n"));
764 DEBUG ((EFI_D_ERROR
, "CheckCrc32: Crc check failed\n"));
768 return (BOOLEAN
) (OrgCrc
== Crc
);