123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682 |
- /*++
- Copyright (c) 2014 Minoca Corp.
- This file is licensed under the terms of the GNU General Public License
- version 3. Alternative licensing terms are available. Contact
- info@minocacorp.com for details. See the LICENSE file at the root of this
- project for complete licensing information.
- Module Name:
- partgpt.c
- Abstract:
- This module implements UEFI GPT partition support.
- Author:
- Evan Green 19-Mar-2014
- Environment:
- Firmware
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include "ueficore.h"
- #include "part.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- BOOLEAN
- EfipPartitionValidGptTable (
- EFI_BLOCK_IO_PROTOCOL *BlockIo,
- EFI_DISK_IO_PROTOCOL *DiskIo,
- EFI_LBA Lba,
- EFI_PARTITION_TABLE_HEADER *PartitionHeader
- );
- BOOLEAN
- EfipPartitionCheckCrc (
- UINTN MaxSize,
- EFI_TABLE_HEADER *Header
- );
- BOOLEAN
- EfipPartitionCheckPartitionEntriesCrc (
- EFI_BLOCK_IO_PROTOCOL *BlockIo,
- EFI_DISK_IO_PROTOCOL *DiskIo,
- EFI_PARTITION_TABLE_HEADER *PartitionHeader
- );
- VOID
- EfipPartitionCheckGptEntries (
- EFI_PARTITION_TABLE_HEADER *Header,
- EFI_PARTITION_ENTRY *Entries,
- EFI_PARTITION_ENTRY_STATUS *EntryStatus
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- EFI_GUID EfiPartitionTypeUnusedGuid = EFI_PARTITION_TYPE_UNUSED_GUID;
- EFI_GUID EfiPartitionTypeSystemPartitionGuid =
- EFI_PARTITION_TYPE_EFI_SYSTEM_GUID;
- //
- // ------------------------------------------------------------------ Functions
- //
- EFI_STATUS
- EfiPartitionDetectGpt (
- EFI_DRIVER_BINDING_PROTOCOL *This,
- EFI_HANDLE Handle,
- EFI_DISK_IO_PROTOCOL *DiskIo,
- EFI_BLOCK_IO_PROTOCOL *BlockIo,
- EFI_DEVICE_PATH_PROTOCOL *DevicePath
- )
- /*++
- Routine Description:
- This routine attempts to detect a GPT partitioned disk, and exposes child
- block devices for each partition it finds.
- Arguments:
- This - Supplies the driver binding protocol instance.
- Handle - Supplies the new controller handle.
- DiskIo - Supplies a pointer to the disk I/O protocol.
- BlockIo - Supplies a pointer to the block I/O protocol.
- DevicePath - Supplies a pointer to the device path.
- Return Value:
- EFI status code.
- --*/
- {
- PEFI_PARTITION_TABLE_HEADER BackupHeader;
- UINT32 BlockSize;
- HARDDRIVE_DEVICE_PATH DrivePath;
- UINT32 EntriesSize;
- PEFI_PARTITION_ENTRY Entry;
- EFI_STATUS GptValidStatus;
- UINTN Index;
- EFI_LBA LastBlock;
- BOOLEAN Match;
- UINT32 MediaId;
- PEFI_PARTITION_ENTRY PartitionEntry;
- PEFI_PARTITION_ENTRY_STATUS PartitionEntryStatus;
- UINTN PartitionEntryStatusSize;
- PEFI_PARTITION_TABLE_HEADER PrimaryHeader;
- PEFI_MASTER_BOOT_RECORD ProtectiveMbr;
- EFI_STATUS Status;
- BOOLEAN SystemPartition;
- BOOLEAN Valid;
- ProtectiveMbr = NULL;
- PrimaryHeader = NULL;
- BackupHeader = NULL;
- PartitionEntry = NULL;
- PartitionEntryStatus = NULL;
- BlockSize = BlockIo->Media->BlockSize;
- LastBlock = BlockIo->Media->LastBlock;
- MediaId = BlockIo->Media->MediaId;
- GptValidStatus = EFI_NOT_FOUND;
- ProtectiveMbr = EfiCoreAllocateBootPool(BlockSize);
- if (ProtectiveMbr == NULL) {
- return EFI_NOT_FOUND;
- }
- //
- // Read the protective MBR from LBA zero.
- //
- Status = DiskIo->ReadDisk(DiskIo,
- MediaId,
- 0,
- BlockSize,
- ProtectiveMbr);
- if (EFI_ERROR(Status)) {
- GptValidStatus = Status;
- goto PartitionDetectGptEnd;
- }
- //
- // Verify that the protective MBR is valid.
- //
- for (Index = 0; Index < EFI_MAX_MBR_PARTITIONS; Index += 1) {
- if ((ProtectiveMbr->Partition[Index].BootIndicator == 0x00) &&
- (ProtectiveMbr->Partition[Index].OsIndicator ==
- EFI_PROTECTIVE_MBR_PARTITION) &&
- (EFI_UNPACK_UINT32(ProtectiveMbr->Partition[Index].StartingLba) ==
- 1)) {
- break;
- }
- }
- if (Index == EFI_MAX_MBR_PARTITIONS) {
- goto PartitionDetectGptEnd;
- }
- //
- // Allocate the GPT structures.
- //
- PrimaryHeader = EfiCoreAllocateBootPool(sizeof(EFI_PARTITION_TABLE_HEADER));
- if (PrimaryHeader == NULL) {
- goto PartitionDetectGptEnd;
- }
- BackupHeader = EfiCoreAllocateBootPool(sizeof(EFI_PARTITION_TABLE_HEADER));
- if (BackupHeader == NULL) {
- goto PartitionDetectGptEnd;
- }
- //
- // Check the primary and backup headers.
- //
- Valid = EfipPartitionValidGptTable(BlockIo,
- DiskIo,
- EFI_PRIMARY_PARTITION_HEADER_LBA,
- PrimaryHeader);
- if (Valid == FALSE) {
- Valid = EfipPartitionValidGptTable(BlockIo,
- DiskIo,
- LastBlock,
- BackupHeader);
- //
- // End now if neither the primary nor the backup header was valid.
- //
- if (Valid == FALSE) {
- goto PartitionDetectGptEnd;
- //
- // The primary header was bad but the backup header is valid.
- //
- } else {
- RtlDebugPrint("Warning: Primary GPT header was bad, using backup "
- "header.\n");
- EfiCopyMem(PrimaryHeader,
- BackupHeader,
- sizeof(EFI_PARTITION_TABLE_HEADER));
- }
- //
- // The primary partition header is valid. Check the backup header.
- //
- } else {
- Valid = EfipPartitionValidGptTable(BlockIo,
- DiskIo,
- PrimaryHeader->AlternateLba,
- BackupHeader);
- if (Valid == FALSE) {
- RtlDebugPrint("Warning: Backup GPT header is invalid!\n");
- }
- }
- //
- // Read the EFI partition entries.
- //
- EntriesSize = PrimaryHeader->NumberOfPartitionEntries *
- PrimaryHeader->SizeOfPartitionEntry;
- PartitionEntry = EfiCoreAllocateBootPool(EntriesSize);
- if (PartitionEntry == NULL) {
- goto PartitionDetectGptEnd;
- }
- Status = DiskIo->ReadDisk(DiskIo,
- MediaId,
- PrimaryHeader->PartitionEntryLba * BlockSize,
- EntriesSize,
- PartitionEntry);
- if (EFI_ERROR(Status)) {
- GptValidStatus = Status;
- goto PartitionDetectGptEnd;
- }
- PartitionEntryStatusSize = PrimaryHeader->NumberOfPartitionEntries *
- sizeof(EFI_PARTITION_ENTRY_STATUS);
- PartitionEntryStatus = EfiCoreAllocateBootPool(PartitionEntryStatusSize);
- if (PartitionEntryStatus == NULL) {
- goto PartitionDetectGptEnd;
- }
- EfiSetMem(PartitionEntryStatus, PartitionEntryStatusSize, 0);
- //
- // Check the integrity of the partition entries.
- //
- EfipPartitionCheckGptEntries(PrimaryHeader,
- PartitionEntry,
- PartitionEntryStatus);
- //
- // Everything looks pretty valid.
- //
- GptValidStatus = EFI_SUCCESS;
- //
- // Create child device handles.
- //
- for (Index = 0;
- Index < PrimaryHeader->NumberOfPartitionEntries;
- Index += 1) {
- Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry +
- (Index *
- PrimaryHeader->SizeOfPartitionEntry));
- Match = EfiCoreCompareGuids(&(Entry->PartitionTypeGuid),
- &EfiPartitionTypeUnusedGuid);
- if ((Match != FALSE) ||
- (PartitionEntryStatus[Index].OutOfRange != FALSE) ||
- (PartitionEntryStatus[Index].Overlap != FALSE) ||
- (PartitionEntryStatus[Index].OsSpecific != FALSE)) {
- //
- // Don't use null entries, invalid entries, or OS-specific entries.
- //
- continue;
- }
- EfiSetMem(&DrivePath, sizeof(DrivePath), 0);
- DrivePath.Header.Type = MEDIA_DEVICE_PATH;
- DrivePath.Header.SubType = MEDIA_HARDDRIVE_DP;
- EfiCoreSetDevicePathNodeLength(&(DrivePath.Header), sizeof(DrivePath));
- DrivePath.PartitionNumber = (UINT32)Index + 1;
- DrivePath.MBRType = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
- DrivePath.SignatureType = SIGNATURE_TYPE_GUID;
- DrivePath.PartitionStart = Entry->StartingLba;
- DrivePath.PartitionSize = Entry->EndingLba - Entry->StartingLba + 1;
- EfiCopyMem(&(DrivePath.Signature),
- &(Entry->UniquePartitionGuid), sizeof(EFI_GUID));
- SystemPartition =
- EfiCoreCompareGuids(&(Entry->PartitionTypeGuid),
- &EfiPartitionTypeSystemPartitionGuid);
- Status = EfiPartitionInstallChildHandle(
- This,
- Handle,
- DiskIo,
- BlockIo,
- DevicePath,
- (EFI_DEVICE_PATH_PROTOCOL *)&DrivePath,
- Entry->StartingLba,
- Entry->EndingLba,
- BlockSize,
- SystemPartition);
- }
- PartitionDetectGptEnd:
- if (ProtectiveMbr != NULL) {
- EfiFreePool(ProtectiveMbr);
- }
- if (PrimaryHeader != NULL) {
- EfiFreePool(PrimaryHeader);
- }
- if (BackupHeader != NULL) {
- EfiFreePool(BackupHeader);
- }
- if (PartitionEntry != NULL) {
- EfiFreePool(PartitionEntry);
- }
- if (PartitionEntryStatus != NULL) {
- EfiFreePool(PartitionEntryStatus);
- }
- return GptValidStatus;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- BOOLEAN
- EfipPartitionValidGptTable (
- EFI_BLOCK_IO_PROTOCOL *BlockIo,
- EFI_DISK_IO_PROTOCOL *DiskIo,
- EFI_LBA Lba,
- EFI_PARTITION_TABLE_HEADER *PartitionHeader
- )
- /*++
- Routine Description:
- This routine determines if the given partition table header is valid.
- Arguments:
- BlockIo - Supplies a pointer to the block I/O protocol.
- DiskIo - Supplies a pointer to the disk I/O protocol.
- Lba - Supplies the LBA to read.
- PartitionHeader - Supplies a pointer where the partition table will be read
- and returned.
- Return Value:
- TRUE if the header is valid.
- FALSE if the header is invalid.
- --*/
- {
- UINT32 BlockSize;
- EFI_PARTITION_TABLE_HEADER *Header;
- UINT32 MediaId;
- EFI_STATUS Status;
- BOOLEAN Valid;
- BlockSize = BlockIo->Media->BlockSize;
- MediaId = BlockIo->Media->MediaId;
- Header = EfiCoreAllocateBootPool(BlockSize);
- if (Header == NULL) {
- return FALSE;
- }
- EfiSetMem(Header, BlockSize, 0);
- Status = DiskIo->ReadDisk(DiskIo,
- MediaId,
- Lba * BlockSize,
- BlockSize,
- Header);
- if (EFI_ERROR(Status)) {
- EfiFreePool(Header);
- return FALSE;
- }
- if ((Header->Header.Signature != EFI_GPT_HEADER_SIGNATURE) ||
- (EfipPartitionCheckCrc(BlockSize, &(Header->Header)) == FALSE) ||
- (Header->MyLba != Lba) ||
- (Header->SizeOfPartitionEntry < sizeof(EFI_PARTITION_ENTRY))) {
- EfiFreePool(Header);
- return FALSE;
- }
- EfiCopyMem(PartitionHeader, Header, sizeof(EFI_PARTITION_TABLE_HEADER));
- Valid = EfipPartitionCheckPartitionEntriesCrc(BlockIo,
- DiskIo,
- PartitionHeader);
- EfiFreePool(Header);
- return Valid;
- }
- BOOLEAN
- EfipPartitionCheckCrc (
- UINTN MaxSize,
- EFI_TABLE_HEADER *Header
- )
- /*++
- Routine Description:
- This routine validates the CRC of the partition header.
- Arguments:
- MaxSize - Supplies the maximum size of the buffer.
- Header - Supplies a pointer to the header to validate.
- Return Value:
- TRUE if the CRC is valid.
- FALSE if the CRC is invalid.
- --*/
- {
- UINT32 Crc;
- UINT32 OriginalCrc;
- UINTN Size;
- Size = Header->HeaderSize;
- Crc = 0;
- if (Size == 0) {
- return FALSE;
- }
- if ((MaxSize != 0) && (Size > MaxSize)) {
- return FALSE;
- }
- OriginalCrc = Header->CRC32;
- Header->CRC32 = 0;
- EfiCalculateCrc32((UINT8 *)Header, Size, &Crc);
- Header->CRC32 = Crc;
- if (Crc != OriginalCrc) {
- return FALSE;
- }
- return TRUE;
- }
- BOOLEAN
- EfipPartitionCheckPartitionEntriesCrc (
- EFI_BLOCK_IO_PROTOCOL *BlockIo,
- EFI_DISK_IO_PROTOCOL *DiskIo,
- EFI_PARTITION_TABLE_HEADER *PartitionHeader
- )
- /*++
- Routine Description:
- This routine validates the CRC of the partition entries.
- Arguments:
- BlockIo - Supplies a pointer to the block I/O protocol.
- DiskIo - Supplies a pointer to the disk I/O protocol.
- PartitionHeader - Supplies a pointer to the GPT header.
- Return Value:
- TRUE if the CRC is valid.
- FALSE if the CRC is invalid.
- --*/
- {
- UINT8 *Buffer;
- UINT32 Crc;
- UINTN EntriesSize;
- UINT64 Offset;
- EFI_STATUS Status;
- BOOLEAN Valid;
- EntriesSize = PartitionHeader->NumberOfPartitionEntries *
- PartitionHeader->SizeOfPartitionEntry;
- Buffer = EfiCoreAllocateBootPool(EntriesSize);
- if (Buffer == NULL) {
- return FALSE;
- }
- Offset = PartitionHeader->PartitionEntryLba *
- BlockIo->Media->BlockSize;
- Status = DiskIo->ReadDisk(DiskIo,
- BlockIo->Media->MediaId,
- Offset,
- EntriesSize,
- Buffer);
- if (EFI_ERROR(Status)) {
- EfiFreePool(Buffer);
- return FALSE;
- }
- Valid = FALSE;
- Status = EfiCalculateCrc32(Buffer, EntriesSize, &Crc);
- if (EFI_ERROR(Status)) {
- RtlDebugPrint("GPT: Needed CRC and it wasn't there!\n");
- } else if (PartitionHeader->PartitionEntryArrayCrc32 == Crc) {
- Valid = TRUE;
- }
- EfiFreePool(Buffer);
- return Valid;
- }
- VOID
- EfipPartitionCheckGptEntries (
- EFI_PARTITION_TABLE_HEADER *Header,
- EFI_PARTITION_ENTRY *Entries,
- EFI_PARTITION_ENTRY_STATUS *EntryStatus
- )
- /*++
- Routine Description:
- This routine checks the validity of the partition entry array.
- Arguments:
- Header - Supplies a pointer to the partition entry header.
- Entries - Supplies a pointer to the partition entries to validate.
- EntryStatus - Supplies a pointer where the validity information of each
- partition will be returned.
- Return Value:
- None.
- --*/
- {
- UINTN CompareIndex;
- EFI_LBA EndingLba;
- EFI_PARTITION_ENTRY *Entry;
- UINTN EntryIndex;
- BOOLEAN Match;
- EFI_LBA StartingLba;
- for (EntryIndex = 0;
- EntryIndex < Header->NumberOfPartitionEntries;
- EntryIndex += 1) {
- Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)Entries +
- (EntryIndex *
- Header->SizeOfPartitionEntry));
- Match = EfiCoreCompareGuids(&(Entry->PartitionTypeGuid),
- &EfiPartitionTypeUnusedGuid);
- if (Match != FALSE) {
- continue;
- }
- StartingLba = Entry->StartingLba;
- EndingLba = Entry->EndingLba;
- if ((StartingLba > EndingLba) ||
- (StartingLba < Header->FirstUsableLba) ||
- (EndingLba < Header->FirstUsableLba) ||
- (EndingLba > Header->LastUsableLba)) {
- EntryStatus[EntryIndex].OutOfRange = TRUE;
- continue;
- }
- if ((Entry->Attributes & EFI_GPT_ATTRIBUTE_OS_SPECIFIC) != 0) {
- EntryStatus[EntryIndex].OsSpecific = TRUE;
- }
- for (CompareIndex = EntryIndex + 1;
- CompareIndex < Header->NumberOfPartitionEntries;
- CompareIndex += 1) {
- Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)Entries +
- (CompareIndex *
- Header->SizeOfPartitionEntry));
- Match = EfiCoreCompareGuids(&(Entry->PartitionTypeGuid),
- &EfiPartitionTypeUnusedGuid);
- if (Match != FALSE) {
- continue;
- }
- if ((Entry->EndingLba >= StartingLba) &&
- (Entry->StartingLba <= EndingLba)) {
- EntryStatus[CompareIndex].Overlap = TRUE;
- EntryStatus[EntryIndex].Overlap = TRUE;
- }
- }
- }
- return;
- }
|