diff options
Diffstat (limited to 'FatPkg/FatPei/Eltorito.c')
-rw-r--r-- | FatPkg/FatPei/Eltorito.c | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/FatPkg/FatPei/Eltorito.c b/FatPkg/FatPei/Eltorito.c new file mode 100644 index 0000000..a350237 --- /dev/null +++ b/FatPkg/FatPei/Eltorito.c @@ -0,0 +1,239 @@ +/** @file
+ Routines supporting partition discovery and
+ logical device reading
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials are licensed and made available
+under the terms and conditions of the BSD License which accompanies this
+distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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;
+
+}
|