diff options
Diffstat (limited to 'Core/CORE_DXE/Partition/Gpt.c')
-rw-r--r-- | Core/CORE_DXE/Partition/Gpt.c | 606 |
1 files changed, 606 insertions, 0 deletions
diff --git a/Core/CORE_DXE/Partition/Gpt.c b/Core/CORE_DXE/Partition/Gpt.c new file mode 100644 index 0000000..3a1fe92 --- /dev/null +++ b/Core/CORE_DXE/Partition/Gpt.c @@ -0,0 +1,606 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** + +//********************************************************************** +// $Header: /Alaska/SOURCE/Core/CORE_DXE/Partition/Gpt.c 16 7/19/12 10:26a Artems $ +// +// $Revision: 16 $ +// +// $Date: 7/19/12 10:26a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Core/CORE_DXE/Partition/Gpt.c $ +// +// 16 7/19/12 10:26a Artems +// [TAG] EIP94126 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] GPT system recovery can't work and backup GPT partition +// will also be destroyed after GPT recovery. +// [RootCause] Incorrect LBA used to restore GPT partition +// [Solution] Use correct LBA +// [Files] Gpt.c +// +// 15 5/02/11 5:57p Artems +// EIP 59571: New partition driver functionality as per UEFI spec v.2.3.1 +// +// 14 11/23/10 4:43p Vyacheslava +// [TAG] EIP45145 +// [Category] New Feature +// [Description] A new feature has done by Cire Lin: We're did the code +// for repairing GPT table. If CRC checking fails then it will run +// CopyGpt() to repair GPT table. +// +// 13 4/16/10 4:24p Pats +// EIP 30719: Support for the HDD with sector size more than 512bytes. +// +// 12 2/04/10 2:07p Oleksiyy +// Minor fixes +// +// 11 7/09/09 5:01p Oleksiyy +// Files clean-up +// +// 10 4/03/09 5:24p Oleksiyy +// EIP 20879: Linux GPT discovering logic improvement. +// +// 9 1/07/08 4:21p Robert +// Updated for coding standard +// +// 8 4/24/07 6:07p Robert +// Update for CHM compliance +// +// 7 4/12/07 7:04p Robert +// Coding Standard Updates +// +// 6 3/22/07 5:39p Robert +// Updated Files for coding standard +// +// 5 10/10/06 3:22p Yakovlevs +// Bug fixes. The GPT Partition Driver working now. +// +// 4 5/19/06 10:47p Felixp +// Device Path code updated to use NEXT_NODE/NODE_LENGTH/SET_NODE_LENGTH +// macros to remove direct access to the Length field +// +// 3 2/11/05 6:14p Felixp +// - Code optimized by using DPAddNode instead of DPAdd +// - bug fixes +// +//********************************************************************** +//<AMI_FHDR_START> +// +// Name: Gpt.c +// +// Description: EFI GPT Partition Generic Driver. +// This file detects whether or not the system has a GPT format +// for the drive and sets up all partitions on the drive +// +//<AMI_FHDR_END> +//********************************************************************** + +//----------------------------------------------------------------------------- +// Includes +#include "Partition.h" +#include "Gpt.h" +#include "Mbr.h" + +//----------------------------------------------------------------------------- +// global variables + + +//----------------------------------------------------------------------------- +// Function Definitions + + +//----------------------------------------------------------------------------- +//<AMI_PHDR_START> +// Procedure: AdjustBufferSize +// +// Description: Calculates correct Buffer size for BlockIO trasfer +// +// Input: EFI_BLOCK_IO_PROTOCOL *BlockIo BlockIo Protocol Interface +// UINTN *BufferSize Pointer To the Size Needed +// +// Output: Modifies Buffer Size to reflect correct number of bytes +// +// Returns: Nothing +// +// Referrals: +// +//<AMI_PHDR_END> +//----------------------------------------------------------------------------- + +VOID AdjustBufferSize(IN EFI_BLOCK_IO_PROTOCOL *BlockIo, IN OUT UINTN *BufferSize) +{ + UINTN sz; + + // Calculate the size of trazaction + sz=BlockIo->Media->BlockSize * (*BufferSize/BlockIo->Media->BlockSize); + + if (*BufferSize % BlockIo->Media->BlockSize) sz+=BlockIo->Media->BlockSize; + + *BufferSize=sz; +} + + +//----------------------------------------------------------------------------- +//<AMI_PHDR_START> +// +// Procedure: CopyGpt +// +// Description: Copies a valid GPT to the location of an invalid one +// +// Input: +// BlockIo - pointer to the BlockIo partition so we can read and write +// to the Block Device +// DiskIo - Unused at this time +// Destination - Pointer to where the valid GPT will be copied +// Source - Pointer to a valid GPT +// +// Output: None - A valid GPT will be written to the Destination address +// +// Returns: None +// +// Referrals: CopyMem ReadBlocks CalculateCrc32 AllocatePool AdjustBufferSize +// WriteBlocks FreePool +// +//<AMI_PHDR_END> +//----------------------------------------------------------------------------- + +VOID CopyGpt( + EFI_BLOCK_IO_PROTOCOL *BlockIo, + EFI_DISK_IO_PROTOCOL *DiskIo, + GPT_HEADER *Destination, + GPT_HEADER *Source +) +{ + EFI_STATUS Status; + UINT8 *EntryArray; + EFI_LBA EntryLba; + UINTN Size; + UINT32 Crc32; + + // Calculate Buffer Size for Enrty array + Size = Source->NumberOfPartitionEntries * Source->SizeOfPartitionEntry; + AdjustBufferSize(BlockIo, &Size); + + if (Source->MyLba == 1) + EntryLba = Source->LastUsableLba + 1; + else + EntryLba = Source->AlternateLba + 1; + + // Copy the GPT Header + gBS->CopyMem( Destination, Source, sizeof(GPT_HEADER) ); + + Destination->MyLba = Source->AlternateLba; + Destination->AlternateLba = Source->MyLba; + Destination->PartitionEntryLba = EntryLba; + Destination->Crc32 = 0; + Destination->Header.CRC32 = 0; + + // Allocate Memory for Source Patrition Table Array + Status = gBS->AllocatePool( EfiBootServicesData, Size, &EntryArray ); + + // Zero it out + gBS->SetMem( EntryArray, Size, 0 ); + + // Read Source's Partition Table Entry Array to the buffer + Status = BlockIo->ReadBlocks( + BlockIo, + BlockIo->Media->MediaId, + Source->PartitionEntryLba, + Size, + EntryArray + ); + + // Calculate CRC32 of GIUID Partition Table Entry Array + gBS->CalculateCrc32( + (UINT8*)EntryArray, + Source->NumberOfPartitionEntries * Source->SizeOfPartitionEntry, + &Crc32 + ); + Destination->Crc32 = Crc32; + + gBS->CalculateCrc32( + (UINT8*)Destination, + sizeof(GPT_HEADER), + &Crc32 + ); + Destination->Header.CRC32 = Crc32; + + + // Write to Destination Partition Header Block + Status = BlockIo->WriteBlocks( + BlockIo, + BlockIo->Media->MediaId, + Destination->MyLba, + BlockIo->Media->BlockSize, + Destination + ); + + // Write Destination Partition Table Entry Array + Status = BlockIo->WriteBlocks( + BlockIo, + BlockIo->Media->MediaId, + Destination->PartitionEntryLba, + Size, + EntryArray + ); + + gBS->FreePool(EntryArray); +} + + +//<AMI_PHDR_START> +//============================================================================= +// Procedure: ValidateGptHeader +// +// Description: Checks if the GPT table is valid +// +// Input: +// BlockIo - Pointer to the Parent BlockIo instance +// GptHeader - Pointer to a memory area that contains the GPT header +// to validate +// HdrLoc - Header location +// +// Output: None +// +// Returns: +// EFI_SUCCESS - GPT is valid +// EFI_INVALID_PARAMETER - checks to see if the CRC, signature, and Header +// Location are vlaid +// EFI_OUT_OF_RESOURCES - Not enough free memory to allocate to read the +// GPT entry table +// +// Referrals: CalculateCrc32 MemCmp AdjustBufferSize AllocatePool ReadBlocks +// FreePool +// +//============================================================================= +//<AMI_PHDR_END> +EFI_STATUS ValidateGptHeader( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN GPT_HEADER *GptHeader, + IN EFI_LBA HdrLoc +) +{ + EFI_STATUS Status; + UINT32 Crc; + UINT32 Temp32; + UINTN Size; + PARTITION_ENTRY *GptEntryTable; + + + // Get CRC of the Partition Header + Temp32 = GptHeader->Header.CRC32; + GptHeader->Header.CRC32 = 0; + + gBS->CalculateCrc32((UINT8*)GptHeader, sizeof(GPT_HEADER), &Crc); + GptHeader->Header.CRC32 = Crc; + + // Check calculated CRC + // Check signature + // Check that MyLBA parameter points to the location of the current Header + if (MemCmp(EFI_GPT_HEADER_ID, &GptHeader->Header.Signature, sizeof(UINT64)) + || (Temp32 != Crc) + || (GptHeader->MyLba != HdrLoc) ) + return EFI_INVALID_PARAMETER; + + // Calculate the size of trasaction + Size = GptHeader->NumberOfPartitionEntries * + GptHeader->SizeOfPartitionEntry; + AdjustBufferSize(BlockIo,&Size); + + // allocate memory for the Entry array + Status = gBS->AllocatePool( EfiBootServicesData, Size, &GptEntryTable); + + if (EFI_ERROR(Status)) return EFI_OUT_OF_RESOURCES; + + // get the data from the entry array + BlockIo->ReadBlocks(BlockIo, BlockIo->Media->MediaId, + GptHeader->PartitionEntryLba, + Size, GptEntryTable); + + // calculate the CRC value for the entry array + gBS->CalculateCrc32((UINT8*)GptEntryTable, + GptHeader->NumberOfPartitionEntries* + GptHeader->SizeOfPartitionEntry, &Crc); + + // the the allocated memory + if (GptEntryTable != NULL ) gBS->FreePool(GptEntryTable); + + // check if the CRC that was calculated matches the value that was stored + if (Crc != GptHeader->Crc32) return EFI_INVALID_PARAMETER; + + // All checks passed, the GPT is valid + return EFI_SUCCESS; +} + + +//<AMI_PHDR_START> +//============================================================================= +// Procedure: VerifyPartionTables +// +// Description: Check if either GPT is valid. if only one is then fix the other +// if both are bad, then it is not a valid GPT system. return error +// +// Input: +// BlockIo - pointer to the BlockIo partition so we can read and write +// to the Block Device +// DiskIo - Unused at this time +// +// Output: +// GPT - pointer to a memory space for one GPT +// +// Returns: EFI_SUCCESS - If a valid GPT is found +// EFI_UNSUPPORTED - if no valid GPT is found +// EFI_OUT_OF_RESOURCES - not enough allocateable memory is available +// +// Referrals: AllocatePool ReadBlocks FreePool AdjustBufferSize +// ValidateGPTHeader CopyGPT CopyMem +// +// Notes +// +//============================================================================= +//<AMI_PHDR_END> +EFI_STATUS VerifyPartionTables( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + OUT GPT_HEADER *Gpt +) +{ + EFI_STATUS Status; + GPT_HEADER *Primary = NULL; + GPT_HEADER *Secondary = NULL; + MASTER_BOOT_RECORD *Pmbr = NULL; + UINTN Size; + UINT8 i, FoundPP = 0; + + // Allocate a buffer for the Protective MBR + Status = gBS->AllocatePool(EfiBootServicesData, BlockIo->Media->BlockSize, &Pmbr); + + if (EFI_ERROR(Status)) return EFI_OUT_OF_RESOURCES; + + // Read the Protective MBR from LBA #0 + Status = BlockIo->ReadBlocks (BlockIo, BlockIo->Media->MediaId, 0, + BlockIo->Media->BlockSize, Pmbr); + + if (EFI_ERROR (Status)) + { + gBS->FreePool(Pmbr); + return Status; + } + + for (i=0; i < 4; i++) + + // See if Protective MBR is valid and if not free allocated memory and return EFI_UNSUPPORTED + if ((Pmbr->PartRec[i].BootIndicator == 0x00) && (Pmbr->PartRec[i].OSType == 0xee) && + (Pmbr->PartRec[i].StartingLba == 1)) FoundPP++; + + if (FoundPP == 0) + { + gBS->FreePool(Pmbr); + return EFI_UNSUPPORTED; + } + + // Allocate memory to hold the data for the Primary and Secondary GPT headers + // Allocate Primary + Size=sizeof(GPT_HEADER); + AdjustBufferSize(BlockIo, &Size); + + Status = gBS->AllocatePool(EfiBootServicesData, Size, &Primary); + + // if error is returned, exit with No resources available + if (EFI_ERROR(Status)) + { + gBS->FreePool(Pmbr); + return EFI_OUT_OF_RESOURCES; + } + + // Allocate for secondary header + Status = gBS->AllocatePool(EfiBootServicesData, Size, &Secondary); + + // if error, free memory allocated for primary and then exit with no resources available + if (EFI_ERROR(Status)) + { + gBS->FreePool(Pmbr); + gBS->FreePool(Primary); + return EFI_OUT_OF_RESOURCES; + } + + // Read primary and backup table + BlockIo->ReadBlocks(BlockIo, BlockIo->Media->MediaId, 1, Size, Primary); + BlockIo->ReadBlocks(BlockIo, BlockIo->Media->MediaId, BlockIo->Media->LastBlock, Size, Secondary); + + // read primary header from the block device and verify if it is valid + if (EFI_ERROR(ValidateGptHeader(BlockIo, Primary, 1))) + { + // if primary is not valid, check secondary to see if it is valid + if (EFI_ERROR(ValidateGptHeader(BlockIo, Secondary, BlockIo->Media->LastBlock))) + { + gBS->FreePool(Pmbr); + gBS->FreePool(Primary); + gBS->FreePool(Secondary); + return EFI_UNSUPPORTED; + } + + // if secondary table is good, copy to primary + else + { + CopyGpt(BlockIo, DiskIo, Primary, Secondary); + } + } + + // if primary is good, check secondary + else + { + // if secondary is bad, copy primary to secondary + if (EFI_ERROR(ValidateGptHeader(BlockIo, Secondary, BlockIo->Media->LastBlock))) + { + CopyGpt(BlockIo, DiskIo, Secondary, Primary); + } + } + + // now that both tables are fixed, copy to GPT output variable and exit + gBS->CopyMem(Gpt, Primary, sizeof(GPT_HEADER)); + + // before we exit free all memory allocation and exit with success + gBS->FreePool(Pmbr); + gBS->FreePool(Primary); + gBS->FreePool(Secondary); + + return EFI_SUCCESS; +} + + + +//<AMI_PHDR_START> +//============================================================================= +// Procedure: GPTDiscoverPartitions +// +// Description: Searches GPT Table for partitions +// +// Input: +// *This - Pointer to the instance of this blockIo protocol +// *BlockIo - Pointer to the parent blockIo Protocol +// *DiskIo - Pointer to the parent DiskIo protocol +// *DevicePath - Pointer to the Parent's device path +// ControllerHandle - the parent's controller handle +// +// Output: None +// +// Returns: +// EFI_SUCCESS - Driver loaded +// other - Driver not loaded +// +// Referrals: AllocatePool FreePool VerifyPartionTables AdjustBufferSize +// MemCmp SetMem CopyMem CreateChildHandle SET_NODE_LENGTH +// +//============================================================================= +//<AMI_PHDR_END> +EFI_STATUS GptDiscoverPartitions ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN EFI_HANDLE ControllerHandle +) +{ + EFI_STATUS Status; + GPT_HEADER *Gpt = NULL; + UINT8 *EntryArray = NULL; + PARTITION_ENTRY *PartEntry=NULL; + HARDDRIVE_DEVICE_PATH HdDp; + PARTITION_DATA PData; + UINTN Idx; + UINTN Size; + + + // Allocate memory for a valid GPT partiton header + Status = gBS->AllocatePool(EfiBootServicesData, sizeof(GPT_HEADER), &Gpt); + + if (EFI_ERROR(Status)) + return EFI_OUT_OF_RESOURCES; + +// EFI_DEADLOOP(); + // verify that the GPT headers on this BlockIo device are valid + if (EFI_ERROR(VerifyPartionTables(BlockIo, DiskIo, Gpt )) ) + { + gBS->FreePool(Gpt); + return EFI_INVALID_PARAMETER; + } + + // If this gets executed, then the Headers are valid and the Entry array + // has the correct CRC value + // Now parse through the Entry Array and create instances for each + // partition on the media + // Check Entry Table Crc + Size = Gpt->NumberOfPartitionEntries * Gpt->SizeOfPartitionEntry; + AdjustBufferSize(BlockIo, &Size); + + Status = gBS->AllocatePool(EfiBootServicesData, Size, &EntryArray); + + if (EFI_ERROR(Status)) + { + gBS->FreePool(Gpt); + return EFI_OUT_OF_RESOURCES; + } + + BlockIo->ReadBlocks(BlockIo, BlockIo->Media->MediaId, + Gpt->PartitionEntryLba, Size, EntryArray); + + for (Idx = 0; Idx < Gpt->NumberOfPartitionEntries; Idx++) + { + PartEntry = (PARTITION_ENTRY *)(EntryArray + Idx * Gpt->SizeOfPartitionEntry); + + // Check to see if this is an unused partition + if (!(MemCmp(&PartEntry->PartitionTypeGuid, &gUnusedPartitionGuid, sizeof(EFI_GUID)))) + continue; // This is an unused partition + + if(PartEntry->Attributes & 0x2) //bit 1 of Attributes set? + continue; //no BlockIo for this partition - UEFI spec 2.3.1 p.5.3.3 table 19 + + // clear the data structure + gBS->SetMem(&PData, sizeof(PARTITION_DATA), 0); + + // set up the device path for the partition + HdDp.Header.Type = MEDIA_DEVICE_PATH; + HdDp.Header.SubType = MEDIA_HARDDRIVE_DP; + SET_NODE_LENGTH(&HdDp.Header,sizeof(HARDDRIVE_DEVICE_PATH)); + + // Idx is 0 based so add one so that partitionNumber is 1 based + HdDp.PartitionNumber = (UINT32) Idx + 1; + HdDp.PartitionStart = PartEntry->StartingLba; + HdDp.PartitionSize = PartEntry->EndingLba - PartEntry->StartingLba + 1; + gBS->CopyMem(&HdDp.Signature, &PartEntry->UniquePartitionGuid, + sizeof(EFI_GUID)); + HdDp.MBRType = MBR_TYPE_EFI_PARTITION_TABLE_HEADER; + HdDp.SignatureType = SIGNATURE_TYPE_GUID; + + PData.DevPath = DPAddNode(DevicePath, &HdDp.Header); + + // save pertinent info + PData.Handle = NULL; + PData.ParentHandle = ControllerHandle; + PData.ParentBlockIo = BlockIo; + PData.ParentDiskIo = DiskIo; + PData.StartingLba = PartEntry->StartingLba; + PData.EndingLba = PartEntry->EndingLba; + gBS->CopyMem(&PData.PartGuid, &PartEntry->PartitionTypeGuid, + sizeof (EFI_GUID)); + + // This is a valid GPT partition: Add a child instance + Status = CreateChildHandle(This, &PData, BlockIo->Media->BlockSize); + + } + + gBS->FreePool(Gpt); + gBS->FreePool(EntryArray); + + return EFI_SUCCESS; +} + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** |