VirtualBox

Ticket #19910: vbox-el-torito-boot-fix.patch

File vbox-el-torito-boot-fix.patch, 6.5 KB (added by Martin Whitaker, 4 years ago)

Patch that fixes this bug for me

  • VirtualBox-6.1.16/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_efi.c

    a b  
    387387}
    388388#endif
    389389
     390#if defined(VBOX)
     391//
     392// Extract INT32 from char array
     393//
     394#define UNPACK_INT32(a) (INT32)( (((UINT8 *) a)[0] <<  0) |    \
     395                                 (((UINT8 *) a)[1] <<  8) |    \
     396                                 (((UINT8 *) a)[2] << 16) |    \
     397                                 (((UINT8 *) a)[3] << 24) )
     398
     399/**
     400  Test for presence of one or more El Torito EFI boot entries.
     401
     402  @param[in]  BlockIo             BlockIo interface.
     403  @param[in]  DiskIo              DiskIo interface.
     404
     405  @retval EFI_SUCCESS             An El Torito EFI boot entry was found.
     406  @retval EFI_NOT_FOUND           An El Torito EFI boot entry was not found.
     407  @retval other                   Failed to perform disk I/O.
     408
     409**/
     410EFI_STATUS
     411FindElToritoBootEntry (
     412  IN EFI_BLOCK_IO_PROTOCOL  *BlockIo,
     413  IN EFI_DISK_IO_PROTOCOL   *DiskIo
     414  )
     415{
     416  EFI_STATUS                   Status;
     417  EFI_BLOCK_IO_MEDIA           *Media;
     418  CDROM_VOLUME_DESCRIPTOR      *VolDescriptor;
     419  ELTORITO_CATALOG             *Catalog;
     420  UINT64                       VolDescriptorOffset;
     421  UINT32                       Lba2KB;
     422  UINTN                        Check;
     423  UINT16                       *CheckBuffer;
     424  UINTN                        Index;
     425  UINTN                        InEfiSection;
     426  UINTN                        MaxIndex;
     427  EFI_STATUS                   Found;
     428
     429  Found         = EFI_NOT_FOUND;
     430  Media         = BlockIo->Media;
     431
     432  //
     433  // CD_ROM has the fixed block size as 2048 bytes (SIZE_2KB)
     434  //
     435
     436  // If the ISO image has been copied onto a different storage media
     437  // then the block size might be different (eg: USB).
     438  // Ensure 2048 (SIZE_2KB) is a multiple of block size
     439  if (((SIZE_2KB % Media->BlockSize) != 0) || (Media->BlockSize > SIZE_2KB)) {
     440    return EFI_NOT_FOUND;
     441  }
     442
     443  VolDescriptor = AllocatePool ((UINTN)SIZE_2KB);
     444
     445  if (VolDescriptor == NULL) {
     446    return EFI_NOT_FOUND;
     447  }
     448
     449  Catalog = (ELTORITO_CATALOG *) VolDescriptor;
     450
     451  //
     452  // Loop: handle one volume descriptor per time
     453  //       The ISO-9660 volume descriptor starts at 32k on the media
     454  //
     455  for (VolDescriptorOffset = SIZE_32KB;
     456       VolDescriptorOffset <= MultU64x32 (Media->LastBlock, Media->BlockSize);
     457       VolDescriptorOffset += SIZE_2KB) {
     458    Status = DiskIo->ReadDisk (
     459                       DiskIo,
     460                       Media->MediaId,
     461                       VolDescriptorOffset,
     462                       SIZE_2KB,
     463                       VolDescriptor
     464                       );
     465    if (EFI_ERROR (Status)) {
     466      Found = Status;
     467      break;
     468    }
     469    //
     470    // Check for valid volume descriptor signature
     471    //
     472    if (VolDescriptor->Unknown.Type == CDVOL_TYPE_END ||
     473        CompareMem (VolDescriptor->Unknown.Id, CDVOL_ID, sizeof (VolDescriptor->Unknown.Id)) != 0
     474        ) {
     475      //
     476      // end of Volume descriptor list
     477      //
     478      break;
     479    }
     480    //
     481    // Is it an El Torito volume descriptor?
     482    //
     483    if (CompareMem (VolDescriptor->BootRecordVolume.SystemId, CDVOL_ELTORITO_ID, sizeof (CDVOL_ELTORITO_ID) - 1) != 0) {
     484      continue;
     485    }
     486    //
     487    // Read in the boot El Torito boot catalog
     488    // The LBA unit used by El Torito boot catalog is 2KB unit
     489    //
     490    Lba2KB = UNPACK_INT32 (VolDescriptor->BootRecordVolume.EltCatalog);
     491    // Ensure the LBA (in 2KB unit) fits into our media
     492    if (Lba2KB * (SIZE_2KB / Media->BlockSize) > Media->LastBlock) {
     493      continue;
     494    }
     495
     496    Status = DiskIo->ReadDisk (
     497                       DiskIo,
     498                       Media->MediaId,
     499                       MultU64x32 (Lba2KB, SIZE_2KB),
     500                       SIZE_2KB,
     501                       Catalog
     502                       );
     503    if (EFI_ERROR (Status)) {
     504      DEBUG ((EFI_D_ERROR, "EltCheckDevice: error reading catalog %r\n", Status));
     505      continue;
     506    }
     507    //
     508    // We don't care too much about the Catalog header's contents, but we do want
     509    // to make sure it looks like a Catalog header
     510    //
     511    if (Catalog->Catalog.Indicator != ELTORITO_ID_CATALOG || Catalog->Catalog.Id55AA != 0xAA55) {
     512      DEBUG ((EFI_D_ERROR, "EltCheckBootCatalog: El Torito boot catalog header IDs not correct\n"));
     513      continue;
     514    }
     515
     516    Check       = 0;
     517    CheckBuffer = (UINT16 *) Catalog;
     518    for (Index = 0; Index < sizeof (ELTORITO_CATALOG) / sizeof (UINT16); Index += 1) {
     519      Check += CheckBuffer[Index];
     520    }
     521
     522    if ((Check & 0xFFFF) != 0) {
     523      DEBUG ((EFI_D_ERROR, "EltCheckBootCatalog: El Torito boot catalog header checksum failed\n"));
     524      continue;
     525    }
     526
     527    InEfiSection = 0;
     528
     529    //
     530    // Here we limit the scan to a single media block. In theory
     531    // an El Torito catalog can extend beyond that; in practice
     532    // that's unlikely.
     533    //
     534    MaxIndex = Media->BlockSize / sizeof (ELTORITO_CATALOG);
     535    for (Index = 1; Index < MaxIndex; Index += 1) {
     536      //
     537      // Next entry
     538      //
     539      Catalog += 1;
     540
     541      //
     542      // Check this entry
     543      //
     544      if (Catalog->Section.Indicator == ELTORITO_ID_SECTION_HEADER ||
     545          Catalog->Section.Indicator == ELTORITO_ID_SECTION_HEADER_FINAL) {
     546        InEfiSection = Catalog->Section.PlatformId == 0xEF;
     547        continue;
     548      }
     549      if (InEfiSection &&
     550          Catalog->Boot.Indicator == ELTORITO_ID_SECTION_BOOTABLE &&
     551          Catalog->Boot.MediaType == ELTORITO_NO_EMULATION &&
     552          Catalog->Boot.Lba != 0) {
     553        Found = EFI_SUCCESS;
     554        break;
     555      }
     556    }
     557  }
     558
     559  FreePool (VolDescriptor);
     560
     561  return Found;
     562}
     563#endif
     564
    390565static EFI_STATUS fsw_efi_ReMount(IN FSW_VOLUME_DATA *pVolume,
    391566                                       IN EFI_HANDLE      ControllerHandle,
    392567                                       EFI_DISK_IO        *pDiskIo,
     
    414589        if (!EFI_ERROR(Status))
    415590            Status = EFI_UNSUPPORTED;
    416591        else
     592            Status = EFI_SUCCESS;
     593    }
     594#endif
     595#if defined(VBOX)
     596    /*
     597     * Don't give the iso9660 filesystem driver a chance to claim a volume which contains
     598     * an El Torito EFI boot entry or we lose the capability to boot from that entry.
     599     */
     600    if (!EFI_ERROR(Status))
     601    {
     602        Status = FindElToritoBootEntry(pBlockIo, pDiskIo);
     603        if (!EFI_ERROR(Status))
     604            Status = EFI_UNSUPPORTED;
     605        else
    417606            Status = EFI_SUCCESS;
    418607    }
    419608#endif

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy