/** @file | |
Routines supporting partition discovery and | |
logical device reading | |
Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include <IndustryStandard/Mbr.h> | |
#include "FatLitePeim.h" | |
/** | |
Test to see if the Mbr buffer is a valid MBR | |
@param[in] Mbr Parent Handle | |
@param[in] LastLba Last Lba address on the device. | |
@retval TRUE Mbr is a Valid MBR | |
@retval FALSE Mbr is not a Valid MBR | |
**/ | |
BOOLEAN | |
PartitionValidMbr ( | |
IN MASTER_BOOT_RECORD *Mbr, | |
IN EFI_PEI_LBA LastLba | |
) | |
{ | |
UINT32 StartingLBA; | |
UINT32 EndingLBA; | |
UINT32 NewEndingLBA; | |
INTN Index1; | |
INTN Index2; | |
BOOLEAN MbrValid; | |
if (Mbr->Signature != MBR_SIGNATURE) { | |
return FALSE; | |
} | |
// | |
// The BPB also has this signature, so it can not be used alone. | |
// | |
MbrValid = FALSE; | |
for (Index1 = 0; Index1 < MAX_MBR_PARTITIONS; Index1++) { | |
if ((Mbr->Partition[Index1].OSIndicator == 0x00) || (UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) == 0)) { | |
continue; | |
} | |
MbrValid = TRUE; | |
StartingLBA = UNPACK_UINT32 (Mbr->Partition[Index1].StartingLBA); | |
EndingLBA = StartingLBA + UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) - 1; | |
if (EndingLBA > LastLba) { | |
// | |
// Compatibility Errata: | |
// Some systems try to hide drive space with their INT 13h driver | |
// This does not hide space from the OS driver. This means the MBR | |
// that gets created from DOS is smaller than the MBR created from | |
// a real OS (NT & Win98). This leads to BlockIo->LastBlock being | |
// wrong on some systems FDISKed by the OS. | |
// | |
// return FALSE Because no block devices on a system are implemented | |
// with INT 13h | |
// | |
return FALSE; | |
} | |
for (Index2 = Index1 + 1; Index2 < MAX_MBR_PARTITIONS; Index2++) { | |
if ((Mbr->Partition[Index2].OSIndicator == 0x00) || (UNPACK_INT32 (Mbr->Partition[Index2].SizeInLBA) == 0)) { | |
continue; | |
} | |
NewEndingLBA = UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) + UNPACK_UINT32 (Mbr->Partition[Index2].SizeInLBA) - 1; | |
if ((NewEndingLBA >= StartingLBA) && (UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) <= EndingLBA)) { | |
// | |
// This region overlaps with the Index1'th region | |
// | |
return FALSE; | |
} | |
} | |
} | |
// | |
// Non of the regions overlapped so MBR is O.K. | |
// | |
return MbrValid; | |
} | |
/** | |
This function finds Mbr partitions. Main algorithm | |
is ported from DXE partition driver. | |
@param[in] PrivateData The global memory map | |
@param[in] ParentBlockDevNo The parent block device | |
@retval TRUE New partitions are detected and logical block devices | |
are added to block device array | |
@retval FALSE No new partitions are added | |
**/ | |
BOOLEAN | |
FatFindMbrPartitions ( | |
IN PEI_FAT_PRIVATE_DATA *PrivateData, | |
IN UINTN ParentBlockDevNo | |
) | |
{ | |
EFI_STATUS Status; | |
MASTER_BOOT_RECORD *Mbr; | |
UINTN Index; | |
BOOLEAN Found; | |
PEI_FAT_BLOCK_DEVICE *ParentBlockDev; | |
PEI_FAT_BLOCK_DEVICE *BlockDev; | |
if (ParentBlockDevNo > PEI_FAT_MAX_BLOCK_DEVICE - 1) { | |
return FALSE; | |
} | |
ParentBlockDev = &(PrivateData->BlockDevice[ParentBlockDevNo]); | |
if (ParentBlockDev->BlockSize > PEI_FAT_MAX_BLOCK_SIZE) { | |
DEBUG ((DEBUG_ERROR, "Device BlockSize %x exceeds FAT_MAX_BLOCK_SIZE\n", ParentBlockDev->BlockSize)); | |
return FALSE; | |
} | |
Found = FALSE; | |
Mbr = (MASTER_BOOT_RECORD *)PrivateData->BlockData; | |
Status = FatReadBlock ( | |
PrivateData, | |
ParentBlockDevNo, | |
0, | |
ParentBlockDev->BlockSize, | |
Mbr | |
); | |
if (EFI_ERROR (Status) || !PartitionValidMbr (Mbr, ParentBlockDev->LastBlock)) { | |
goto Done; | |
} | |
// | |
// We have a valid mbr - add each partition | |
// | |
for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) { | |
if ((Mbr->Partition[Index].OSIndicator == 0x00) || (UNPACK_INT32 (Mbr->Partition[Index].SizeInLBA) == 0)) { | |
// | |
// Don't use null MBR entries | |
// | |
continue; | |
} | |
// | |
// Register this partition | |
// | |
if (PrivateData->BlockDeviceCount < PEI_FAT_MAX_BLOCK_DEVICE) { | |
Found = TRUE; | |
BlockDev = &(PrivateData->BlockDevice[PrivateData->BlockDeviceCount]); | |
BlockDev->BlockSize = MBR_SIZE; | |
BlockDev->LastBlock = UNPACK_INT32 (Mbr->Partition[Index].SizeInLBA) - 1; | |
BlockDev->IoAlign = ParentBlockDev->IoAlign; | |
BlockDev->Logical = TRUE; | |
BlockDev->PartitionChecked = FALSE; | |
BlockDev->StartingPos = MultU64x32 ( | |
UNPACK_INT32 (Mbr->Partition[Index].StartingLBA), | |
ParentBlockDev->BlockSize | |
); | |
BlockDev->ParentDevNo = ParentBlockDevNo; | |
PrivateData->BlockDeviceCount++; | |
} | |
} | |
Done: | |
ParentBlockDev->PartitionChecked = TRUE; | |
return Found; | |
} |