123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423 |
- /*++
- 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:
- partmbr.c
- Abstract:
- This module implements support for parsing MBR-style partitioned disks.
- Author:
- Evan Green 20-Mar-2014
- Environment:
- Firmware
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include "ueficore.h"
- #include "part.h"
- //
- // --------------------------------------------------------------------- Macros
- //
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- BOOLEAN
- EfipPartitionIsValidMbr (
- EFI_MASTER_BOOT_RECORD *Mbr,
- EFI_LBA LastLba
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // ------------------------------------------------------------------ Functions
- //
- EFI_STATUS
- EfiPartitionDetectMbr (
- 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 an El Torito 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.
- --*/
- {
- UINT32 BlockSize;
- UINT64 ChildSize;
- EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
- HARDDRIVE_DEVICE_PATH DrivePath;
- UINT32 ExtMbrStartingLba;
- EFI_STATUS Found;
- UINTN Index;
- EFI_LBA LastBlock;
- EFI_DEVICE_PATH_PROTOCOL *LastDevicePathNode;
- EFI_MASTER_BOOT_RECORD *Mbr;
- UINT32 MediaId;
- HARDDRIVE_DEVICE_PATH ParentPath;
- UINT32 PartitionNumber;
- EFI_STATUS Status;
- BOOLEAN SystemPartition;
- Found = EFI_NOT_FOUND;
- BlockSize = BlockIo->Media->BlockSize;
- MediaId = BlockIo->Media->MediaId;
- LastBlock = BlockIo->Media->LastBlock;
- Mbr = EfiCoreAllocateBootPool(BlockSize);
- if (Mbr == NULL) {
- return Found;
- }
- Status = DiskIo->ReadDisk(DiskIo, MediaId, 0, BlockSize, Mbr);
- if (EFI_ERROR(Status)) {
- Found = Status;
- goto PartitionDetectMbrEnd;
- }
- if (EfipPartitionIsValidMbr(Mbr, LastBlock) == FALSE) {
- goto PartitionDetectMbrEnd;
- }
- //
- // This is a valid MBR. Add each partition. Start by getting the starting
- // and ending LBA of the parent block device.
- //
- LastDevicePathNode = NULL;
- EfiSetMem(&ParentPath, sizeof(ParentPath), 0);
- DevicePathNode = DevicePath;
- while (EfiCoreIsDevicePathEnd(DevicePathNode) == FALSE) {
- LastDevicePathNode = DevicePathNode;
- DevicePathNode = EfiCoreGetNextDevicePathNode(DevicePathNode);
- }
- if (LastDevicePathNode != NULL) {
- if ((EfiCoreGetDevicePathType(LastDevicePathNode) ==
- MEDIA_DEVICE_PATH) &&
- (EfiCoreGetDevicePathSubType(LastDevicePathNode) ==
- MEDIA_HARDDRIVE_DP)) {
- EfiCopyMem(&ParentPath, LastDevicePathNode, sizeof(ParentPath));
- } else {
- LastDevicePathNode = NULL;
- }
- }
- PartitionNumber = 0;
- EfiSetMem(&DrivePath, sizeof(DrivePath), 0);
- DrivePath.Header.Type = MEDIA_DEVICE_PATH;
- DrivePath.Header.SubType = MEDIA_HARDDRIVE_DP;
- EfiCoreSetDevicePathNodeLength(&(DrivePath.Header), sizeof(DrivePath));
- DrivePath.MBRType = MBR_TYPE_PCAT;
- DrivePath.SignatureType = SIGNATURE_TYPE_MBR;
- //
- // If this is an MBR, add each partition.
- //
- if (LastDevicePathNode == NULL) {
- for (Index = 0; Index < EFI_MAX_MBR_PARTITIONS; Index += 1) {
- //
- // Skip null/free entries.
- //
- if ((Mbr->Partition[Index].OsIndicator == 0) ||
- (EFI_UNPACK_UINT32(Mbr->Partition[Index].SizeInLba) == 0)) {
- continue;
- }
- //
- // Skip GPT guards. Code can get here if there's a GPT disk with
- // zero partitions.
- //
- if (Mbr->Partition[Index].OsIndicator ==
- EFI_PROTECTIVE_MBR_PARTITION) {
- continue;
- }
- PartitionNumber += 1;
- DrivePath.PartitionNumber = PartitionNumber;
- DrivePath.PartitionStart =
- EFI_UNPACK_UINT32(Mbr->Partition[Index].StartingLba);
- DrivePath.PartitionSize =
- EFI_UNPACK_UINT32(Mbr->Partition[Index].SizeInLba);
- EfiCopyMem(DrivePath.Signature,
- &(Mbr->UniqueMbrSignature[0]),
- sizeof(Mbr->UniqueMbrSignature));
- SystemPartition = FALSE;
- if (Mbr->Partition[Index].OsIndicator == EFI_PARTITION) {
- SystemPartition = TRUE;
- }
- Status = EfiPartitionInstallChildHandle(
- This,
- Handle,
- DiskIo,
- BlockIo,
- DevicePath,
- (EFI_DEVICE_PATH_PROTOCOL *)&DrivePath,
- DrivePath.PartitionStart,
- DrivePath.PartitionStart + DrivePath.PartitionSize - 1,
- EFI_MBR_SIZE,
- SystemPartition);
- if (!EFI_ERROR(Status)) {
- Found = EFI_SUCCESS;
- }
- }
- //
- // This is an extended partition. Follow the extended partition chain to
- // get all logical drives.
- //
- } else {
- ExtMbrStartingLba = 0;
- do {
- Status = DiskIo->ReadDisk(DiskIo,
- MediaId,
- ExtMbrStartingLba * BlockSize,
- BlockSize,
- Mbr);
- if (EFI_ERROR(Status)) {
- Found = Status;
- goto PartitionDetectMbrEnd;
- }
- if (EFI_UNPACK_UINT32(Mbr->Partition[0].SizeInLba) == 0) {
- break;
- }
- if ((Mbr->Partition[0].OsIndicator ==
- EFI_EXTENDED_DOS_PARTITION) ||
- (Mbr->Partition[0].OsIndicator ==
- EFI_EXTENDED_WINDOWS_PARTITION)) {
- ExtMbrStartingLba =
- EFI_UNPACK_UINT32(Mbr->Partition[0].StartingLba);
- continue;
- }
- PartitionNumber += 1;
- DrivePath.PartitionNumber = PartitionNumber;
- DrivePath.PartitionStart =
- EFI_UNPACK_UINT32(Mbr->Partition[0].StartingLba) +
- ExtMbrStartingLba;
- DrivePath.PartitionSize =
- EFI_UNPACK_UINT32(Mbr->Partition[0].SizeInLba);
- if ((DrivePath.PartitionStart + DrivePath.PartitionSize - 1 >=
- ParentPath.PartitionStart + ParentPath.PartitionSize) ||
- (DrivePath.PartitionStart <= ParentPath.PartitionStart)) {
- break;
- }
- EfiSetMem(DrivePath.Signature, sizeof(DrivePath.Signature), 0);
- SystemPartition = FALSE;
- if (Mbr->Partition[0].OsIndicator == EFI_PARTITION) {
- SystemPartition = TRUE;
- }
- ChildSize = DrivePath.PartitionStart - ParentPath.PartitionStart +
- DrivePath.PartitionSize - 1;
- Status = EfiPartitionInstallChildHandle(
- This,
- Handle,
- DiskIo,
- BlockIo,
- DevicePath,
- (EFI_DEVICE_PATH_PROTOCOL *)&DrivePath,
- DrivePath.PartitionStart - ParentPath.PartitionStart,
- ChildSize,
- EFI_MBR_SIZE,
- SystemPartition);
- if (!EFI_ERROR(Status)) {
- Found = EFI_SUCCESS;
- }
- if ((Mbr->Partition[1].OsIndicator !=
- EFI_EXTENDED_DOS_PARTITION) &&
- (Mbr->Partition[1].OsIndicator !=
- EFI_EXTENDED_WINDOWS_PARTITION)) {
- break;
- }
- ExtMbrStartingLba =
- EFI_UNPACK_UINT32(Mbr->Partition[1].StartingLba);
- if (ExtMbrStartingLba == 0) {
- break;
- }
- } while (ExtMbrStartingLba < ParentPath.PartitionSize);
- }
- PartitionDetectMbrEnd:
- EfiFreePool(Mbr);
- return Found;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- BOOLEAN
- EfipPartitionIsValidMbr (
- EFI_MASTER_BOOT_RECORD *Mbr,
- EFI_LBA LastLba
- )
- /*++
- Routine Description:
- This routine validates the given MBR.
- Arguments:
- Mbr - Supplies a pointer to the MBR to validate.
- LastLba - Supplies the last valid block address on the disk.
- Return Value:
- TRUE if the MBR is valid.
- FALSE if the MBR is garbage.
- --*/
- {
- UINT32 EndingLba;
- UINT32 NewEndingLba;
- UINT32 OtherStart;
- UINTN PartitionIndex;
- UINTN SearchIndex;
- UINT32 Size;
- UINT32 StartingLba;
- BOOLEAN Valid;
- if (Mbr->Signature != EFI_MBR_SIGNATURE) {
- return FALSE;
- }
- Valid = FALSE;
- for (PartitionIndex = 0;
- PartitionIndex < EFI_MAX_MBR_PARTITIONS;
- PartitionIndex += 1) {
- Size = EFI_UNPACK_UINT32(Mbr->Partition[PartitionIndex].SizeInLba);
- if ((Mbr->Partition[PartitionIndex].OsIndicator == 0x00) ||
- (Size == 0)) {
- continue;
- }
- Valid = TRUE;
- StartingLba =
- EFI_UNPACK_UINT32(Mbr->Partition[PartitionIndex].StartingLba);
- EndingLba = StartingLba + Size - 1;
- if (EndingLba > LastLba) {
- return FALSE;
- }
- //
- // Search the other entries for overlap.
- //
- for (SearchIndex = PartitionIndex + 1;
- SearchIndex < EFI_MAX_MBR_PARTITIONS;
- SearchIndex += 1) {
- Size = EFI_UNPACK_UINT32(Mbr->Partition[SearchIndex].SizeInLba);
- if ((Mbr->Partition[SearchIndex].OsIndicator == 0x00) ||
- (Size == 0)) {
- continue;
- }
- OtherStart =
- EFI_UNPACK_UINT32(Mbr->Partition[SearchIndex].StartingLba);
- NewEndingLba = OtherStart + Size - 1;
- if ((NewEndingLba >= StartingLba) && (OtherStart <= EndingLba)) {
- return FALSE;
- }
- }
- }
- return Valid;
- }
|