/** @file
Routines supporting partition discovery and
logical device reading
Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#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;
}