diff -Naur VirtualBox-6.1.18/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_efi.c VirtualBox-6.1.18-p/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_efi.c --- VirtualBox-6.1.18/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_efi.c 2021-01-07 16:39:14.000000000 +0100 +++ VirtualBox-6.1.18-p/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_efi.c 2021-01-30 02:19:42.121968017 +0100 @@ -384,6 +384,181 @@ } #endif +#if defined(VBOX) +// +// Extract INT32 from char array +// +#define UNPACK_INT32(a) (INT32)( (((UINT8 *) a)[0] << 0) | \ + (((UINT8 *) a)[1] << 8) | \ + (((UINT8 *) a)[2] << 16) | \ + (((UINT8 *) a)[3] << 24) ) + +/** + Test for presence of one or more El Torito EFI boot entries. + + @param[in] BlockIo BlockIo interface. + @param[in] DiskIo DiskIo interface. + + @retval EFI_SUCCESS An El Torito EFI boot entry was found. + @retval EFI_NOT_FOUND An El Torito EFI boot entry was not found. + @retval other Failed to perform disk I/O. + +**/ +EFI_STATUS +FindElToritoBootEntry ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo + ) +{ + EFI_STATUS Status; + EFI_BLOCK_IO_MEDIA *Media; + CDROM_VOLUME_DESCRIPTOR *VolDescriptor; + ELTORITO_CATALOG *Catalog; + UINT64 VolDescriptorOffset; + UINT32 Lba2KB; + UINTN Check; + UINT16 *CheckBuffer; + UINTN Index; + UINTN InEfiSection; + UINTN MaxIndex; + EFI_STATUS Found; + + Found = EFI_NOT_FOUND; + Media = BlockIo->Media; + + // + // CD_ROM has the fixed block size as 2048 bytes (SIZE_2KB) + // + + // If the ISO image has been copied onto a different storage media + // then the block size might be different (eg: USB). + // Ensure 2048 (SIZE_2KB) is a multiple of block size + if (((SIZE_2KB % Media->BlockSize) != 0) || (Media->BlockSize > SIZE_2KB)) { + return EFI_NOT_FOUND; + } + + VolDescriptor = AllocatePool ((UINTN)SIZE_2KB); + + if (VolDescriptor == NULL) { + return EFI_NOT_FOUND; + } + + Catalog = (ELTORITO_CATALOG *) VolDescriptor; + + // + // Loop: handle one volume descriptor per time + // The ISO-9660 volume descriptor starts at 32k on the media + // + for (VolDescriptorOffset = SIZE_32KB; + VolDescriptorOffset <= MultU64x32 (Media->LastBlock, Media->BlockSize); + VolDescriptorOffset += SIZE_2KB) { + Status = DiskIo->ReadDisk ( + DiskIo, + Media->MediaId, + VolDescriptorOffset, + SIZE_2KB, + VolDescriptor + ); + if (EFI_ERROR (Status)) { + Found = 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; + } + // + // 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 + // The LBA unit used by El Torito boot catalog is 2KB unit + // + Lba2KB = UNPACK_INT32 (VolDescriptor->BootRecordVolume.EltCatalog); + // Ensure the LBA (in 2KB unit) fits into our media + if (Lba2KB * (SIZE_2KB / Media->BlockSize) > Media->LastBlock) { + continue; + } + + Status = DiskIo->ReadDisk ( + DiskIo, + Media->MediaId, + MultU64x32 (Lba2KB, SIZE_2KB), + SIZE_2KB, + Catalog + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EltCheckDevice: error reading catalog %r\n", 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) { + DEBUG ((EFI_D_ERROR, "EltCheckBootCatalog: El Torito boot catalog header IDs not correct\n")); + continue; + } + + Check = 0; + CheckBuffer = (UINT16 *) Catalog; + for (Index = 0; Index < sizeof (ELTORITO_CATALOG) / sizeof (UINT16); Index += 1) { + Check += CheckBuffer[Index]; + } + + if ((Check & 0xFFFF) != 0) { + DEBUG ((EFI_D_ERROR, "EltCheckBootCatalog: El Torito boot catalog header checksum failed\n")); + continue; + } + + InEfiSection = 0; + + // + // Here we limit the scan to a single media block. In theory + // an El Torito catalog can extend beyond that; in practice + // that's unlikely. + // + MaxIndex = Media->BlockSize / sizeof (ELTORITO_CATALOG); + for (Index = 1; Index < MaxIndex; Index += 1) { + // + // Next entry + // + Catalog += 1; + + // + // Check this entry + // + if (Catalog->Section.Indicator == ELTORITO_ID_SECTION_HEADER || + Catalog->Section.Indicator == ELTORITO_ID_SECTION_HEADER_FINAL) { + InEfiSection = Catalog->Section.PlatformId == 0xEF; + continue; + } + if (InEfiSection && + Catalog->Boot.Indicator == ELTORITO_ID_SECTION_BOOTABLE && + Catalog->Boot.MediaType == ELTORITO_NO_EMULATION && + Catalog->Boot.Lba != 0) { + Found = EFI_SUCCESS; + break; + } + } + } + + FreePool (VolDescriptor); + + return Found; +} +#endif + static EFI_STATUS fsw_efi_ReMount(IN FSW_VOLUME_DATA *pVolume, IN EFI_HANDLE ControllerHandle, EFI_DISK_IO *pDiskIo, @@ -411,6 +586,20 @@ if (!EFI_ERROR(Status)) Status = EFI_UNSUPPORTED; else + Status = EFI_SUCCESS; + } +#endif +#if defined(VBOX) + /* + * Don't give the iso9660 filesystem driver a chance to claim a volume which contains + * an El Torito EFI boot entry or we lose the capability to boot from that entry. + */ + if (!EFI_ERROR(Status)) + { + Status = FindElToritoBootEntry(pBlockIo, pDiskIo); + if (!EFI_ERROR(Status)) + Status = EFI_UNSUPPORTED; + else Status = EFI_SUCCESS; } #endif