/** @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/ElTorito.h> | |
#include "FatLitePeim.h" | |
/** | |
This function finds Eltorito 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 | |
FatFindEltoritoPartitions ( | |
IN PEI_FAT_PRIVATE_DATA *PrivateData, | |
IN UINTN ParentBlockDevNo | |
) | |
{ | |
EFI_STATUS Status; | |
BOOLEAN Found; | |
PEI_FAT_BLOCK_DEVICE *BlockDev; | |
PEI_FAT_BLOCK_DEVICE *ParentBlockDev; | |
UINT32 VolDescriptorLba; | |
UINT32 Lba; | |
CDROM_VOLUME_DESCRIPTOR *VolDescriptor; | |
ELTORITO_CATALOG *Catalog; | |
UINTN Check; | |
UINTN Index; | |
UINTN MaxIndex; | |
UINT16 *CheckBuffer; | |
UINT32 SubBlockSize; | |
UINT32 SectorCount; | |
UINT32 VolSpaceSize; | |
if (ParentBlockDevNo > PEI_FAT_MAX_BLOCK_DEVICE - 1) { | |
return FALSE; | |
} | |
Found = FALSE; | |
ParentBlockDev = &(PrivateData->BlockDevice[ParentBlockDevNo]); | |
VolSpaceSize = 0; | |
// | |
// CD_ROM has the fixed block size as 2048 bytes | |
// | |
if (ParentBlockDev->BlockSize != 2048) { | |
return FALSE; | |
} | |
VolDescriptor = (CDROM_VOLUME_DESCRIPTOR *)PrivateData->BlockData; | |
Catalog = (ELTORITO_CATALOG *)VolDescriptor; | |
// | |
// the ISO-9660 volume descriptor starts at 32k on the media | |
// and CD_ROM has the fixed block size as 2048 bytes, so... | |
// | |
VolDescriptorLba = 15; | |
// | |
// ((16*2048) / Media->BlockSize) - 1; | |
// | |
// Loop: handle one volume descriptor per time | |
// | |
while (TRUE) { | |
VolDescriptorLba += 1; | |
if (VolDescriptorLba > ParentBlockDev->LastBlock) { | |
// | |
// We are pointing past the end of the device so exit | |
// | |
break; | |
} | |
Status = FatReadBlock ( | |
PrivateData, | |
ParentBlockDevNo, | |
VolDescriptorLba, | |
ParentBlockDev->BlockSize, | |
VolDescriptor | |
); | |
if (EFI_ERROR (Status)) { | |
break; | |
} | |
// | |
// Check for valid volume descriptor signature | |
// | |
if ((VolDescriptor->Unknown.Type == CDVOL_TYPE_END) || | |
(CompareMem (VolDescriptor->Unknown.Id, CDVOL_ID, sizeof (VolDescriptor->Unknown.Id)) != 0) | |
) | |
{ | |
// | |
// end of Volume descriptor list | |
// | |
break; | |
} | |
// | |
// Read the Volume Space Size from Primary Volume Descriptor 81-88 byte | |
// | |
if (VolDescriptor->Unknown.Type == CDVOL_TYPE_CODED) { | |
VolSpaceSize = VolDescriptor->PrimaryVolume.VolSpaceSize[1]; | |
} | |
// | |
// Is it an El Torito volume descriptor? | |
// | |
if (CompareMem ( | |
VolDescriptor->BootRecordVolume.SystemId, | |
CDVOL_ELTORITO_ID, | |
sizeof (CDVOL_ELTORITO_ID) - 1 | |
) != 0) | |
{ | |
continue; | |
} | |
// | |
// Read in the boot El Torito boot catalog | |
// | |
Lba = UNPACK_INT32 (VolDescriptor->BootRecordVolume.EltCatalog); | |
if (Lba > ParentBlockDev->LastBlock) { | |
continue; | |
} | |
Status = FatReadBlock ( | |
PrivateData, | |
ParentBlockDevNo, | |
Lba, | |
ParentBlockDev->BlockSize, | |
Catalog | |
); | |
if (EFI_ERROR (Status)) { | |
continue; | |
} | |
// | |
// We don't care too much about the Catalog header's contents, but we do want | |
// to make sure it looks like a Catalog header | |
// | |
if ((Catalog->Catalog.Indicator != ELTORITO_ID_CATALOG) || (Catalog->Catalog.Id55AA != 0xAA55)) { | |
continue; | |
} | |
Check = 0; | |
CheckBuffer = (UINT16 *)Catalog; | |
for (Index = 0; Index < sizeof (ELTORITO_CATALOG) / sizeof (UINT16); Index += 1) { | |
Check += CheckBuffer[Index]; | |
} | |
if ((Check & 0xFFFF) != 0) { | |
continue; | |
} | |
MaxIndex = ParentBlockDev->BlockSize / sizeof (ELTORITO_CATALOG); | |
for (Index = 1; Index < MaxIndex; Index += 1) { | |
// | |
// Next entry | |
// | |
Catalog += 1; | |
// | |
// Check this entry | |
// | |
if ((Catalog->Boot.Indicator != ELTORITO_ID_SECTION_BOOTABLE) || (Catalog->Boot.Lba == 0)) { | |
continue; | |
} | |
SubBlockSize = 512; | |
SectorCount = Catalog->Boot.SectorCount; | |
switch (Catalog->Boot.MediaType) { | |
case ELTORITO_NO_EMULATION: | |
SubBlockSize = ParentBlockDev->BlockSize; | |
SectorCount = Catalog->Boot.SectorCount; | |
break; | |
case ELTORITO_HARD_DISK: | |
break; | |
case ELTORITO_12_DISKETTE: | |
SectorCount = 0x50 * 0x02 * 0x0F; | |
break; | |
case ELTORITO_14_DISKETTE: | |
SectorCount = 0x50 * 0x02 * 0x12; | |
break; | |
case ELTORITO_28_DISKETTE: | |
SectorCount = 0x50 * 0x02 * 0x24; | |
break; | |
default: | |
SectorCount = 0; | |
SubBlockSize = ParentBlockDev->BlockSize; | |
break; | |
} | |
if (SectorCount < 2) { | |
SectorCount = (VolSpaceSize > ParentBlockDev->LastBlock + 1) ? (UINT32)(ParentBlockDev->LastBlock - Catalog->Boot.Lba + 1) : (UINT32)(VolSpaceSize - Catalog->Boot.Lba); | |
} | |
// | |
// Register this partition | |
// | |
if (PrivateData->BlockDeviceCount < PEI_FAT_MAX_BLOCK_DEVICE) { | |
Found = TRUE; | |
BlockDev = &(PrivateData->BlockDevice[PrivateData->BlockDeviceCount]); | |
BlockDev->BlockSize = SubBlockSize; | |
BlockDev->LastBlock = SectorCount - 1; | |
BlockDev->IoAlign = ParentBlockDev->IoAlign; | |
BlockDev->Logical = TRUE; | |
BlockDev->PartitionChecked = FALSE; | |
BlockDev->StartingPos = MultU64x32 (Catalog->Boot.Lba, ParentBlockDev->BlockSize); | |
BlockDev->ParentDevNo = ParentBlockDevNo; | |
PrivateData->BlockDeviceCount++; | |
} | |
} | |
} | |
ParentBlockDev->PartitionChecked = TRUE; | |
return Found; | |
} |