/** @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; }