/** This function finds Eltorito partitions. Main algorithm is ported from DXE partition driver. @param PrivateData The global memory map @param 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; }
/** Disk reading. @param PrivateData the global memory map; @param BlockDeviceNo the block device to read; @param StartingAddress the starting address. @param Size the amount of data to read. @param Buffer the buffer holding the data @retval EFI_SUCCESS The function completed successfully. @retval EFI_DEVICE_ERROR Something error. **/ EFI_STATUS FatReadDisk ( IN PEI_FAT_PRIVATE_DATA *PrivateData, IN UINTN BlockDeviceNo, IN UINT64 StartingAddress, IN UINTN Size, OUT VOID *Buffer ) { EFI_STATUS Status; UINT32 BlockSize; CHAR8 *BufferPtr; CHAR8 *CachePtr; UINT32 Offset; UINT64 Lba; UINT64 OverRunLba; UINTN Amount; Status = EFI_SUCCESS; BufferPtr = Buffer; BlockSize = PrivateData->BlockDevice[BlockDeviceNo].BlockSize; // // Read underrun // Lba = DivU64x32Remainder (StartingAddress, BlockSize, &Offset); Status = FatGetCacheBlock (PrivateData, BlockDeviceNo, Lba, &CachePtr); if (EFI_ERROR (Status)) { return EFI_DEVICE_ERROR; } Amount = Size < (BlockSize - Offset) ? Size : (BlockSize - Offset); CopyMem (BufferPtr, CachePtr + Offset, Amount); if (Size == Amount) { return EFI_SUCCESS; } Size -= Amount; BufferPtr += Amount; StartingAddress += Amount; Lba += 1; // // Read aligned parts // OverRunLba = Lba + DivU64x32Remainder (Size, BlockSize, &Offset); Size -= Offset; Status = FatReadBlock (PrivateData, BlockDeviceNo, Lba, Size, BufferPtr); if (EFI_ERROR (Status)) { return EFI_DEVICE_ERROR; } BufferPtr += Size; // // Read overrun // if (Offset != 0) { Status = FatGetCacheBlock (PrivateData, BlockDeviceNo, OverRunLba, &CachePtr); if (EFI_ERROR (Status)) { return EFI_DEVICE_ERROR; } CopyMem (BufferPtr, CachePtr, Offset); } return Status; }
/** This function finds Mbr partitions. Main algorithm is ported from DXE partition driver. @param PrivateData The global memory map @param 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]); 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; }
/** Find a cache block designated to specific Block device and Lba. If not found, invalidate an oldest one and use it. (LRU cache) @param PrivateData the global memory map. @param BlockDeviceNo the Block device. @param Lba the Logical Block Address @param CachePtr Ptr to the starting address of the memory holding the data; @retval EFI_SUCCESS The function completed successfully. @retval EFI_DEVICE_ERROR Something error while accessing media. **/ EFI_STATUS FatGetCacheBlock ( IN PEI_FAT_PRIVATE_DATA *PrivateData, IN UINTN BlockDeviceNo, IN UINT64 Lba, OUT CHAR8 **CachePtr ) { EFI_STATUS Status; PEI_FAT_CACHE_BUFFER *CacheBuffer; INTN Index; STATIC UINT8 Seed; Status = EFI_SUCCESS; CacheBuffer = NULL; // // go through existing cache buffers // for (Index = 0; Index < PEI_FAT_CACHE_SIZE; Index++) { CacheBuffer = &(PrivateData->CacheBuffer[Index]); if (CacheBuffer->Valid && CacheBuffer->BlockDeviceNo == BlockDeviceNo && CacheBuffer->Lba == Lba) { break; } } if (Index < PEI_FAT_CACHE_SIZE) { *CachePtr = (CHAR8 *) CacheBuffer->Buffer; return EFI_SUCCESS; } // // We have to find an invalid cache buffer // for (Index = 0; Index < PEI_FAT_CACHE_SIZE; Index++) { if (!PrivateData->CacheBuffer[Index].Valid) { break; } } // // Use the cache buffer // if (Index == PEI_FAT_CACHE_SIZE) { Index = (Seed++) % PEI_FAT_CACHE_SIZE; } // // Current device ID should be less than maximum device ID. // if (BlockDeviceNo >= PEI_FAT_MAX_BLOCK_DEVICE) { return EFI_DEVICE_ERROR; } CacheBuffer = &(PrivateData->CacheBuffer[Index]); CacheBuffer->BlockDeviceNo = BlockDeviceNo; CacheBuffer->Lba = Lba; CacheBuffer->Size = PrivateData->BlockDevice[BlockDeviceNo].BlockSize; // // Read in the data // Status = FatReadBlock ( PrivateData, BlockDeviceNo, Lba, CacheBuffer->Size, CacheBuffer->Buffer ); if (EFI_ERROR (Status)) { return EFI_DEVICE_ERROR; } CacheBuffer->Valid = TRUE; *CachePtr = (CHAR8 *) CacheBuffer->Buffer; return Status; }