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