Manipulating ISO Images for BIOS/UEFI Boot Support

An example of how to repack a BIOS only ISO image for BIOS/UEFI dual boot

Manipulating ISO Images for BIOS/UEFI Boot Support

Status: 15 Sept 2020 - Verified with FreeBSD 10.04 ISO


Model x86 machines are now all using UEFI for boot support, typically with the ability to configure legacy (BIOS) boot support. ISO image boot support for BIOS is provided by the "El Torito" extensions and this mechanism has been extended for UEFI boot by using extra Boot Catalog entries.

My example is to allow older FreeBSD ISO to be bootable on a UEFI only VM.


FreeBSD BIOS vs Dual Boot ISO

The starting point for repacking an ISO is to find out the boot image locations. FreeBSD has a utility etdump (El Torito Dump, the Linux equivalent is dumpet) that provides a dump of the El Torito Boot Catalog contents.  This provides details required to extract out the required parts from a existing ISO image.

This example uses FreeBSD BIOS (10.4) ISO and Dual Boot FreeBSD (11.4) ISO to compare El Torito Boot Catalog (note this is from FreeBSD machine) and create a Dual Boot 10.04 FreeBSD ISO image.

We start by dumping the boot catalogs (using FreeBSD etdump):

# etdump FreeBSD-10.4-RELEASE-amd64-disc1.iso
Image in FreeBSD-10.4-RELEASE-amd64-disc1.iso
Default entry
	System i386
	Start LBA 20 (0x14), sector count 4 (0x4)
	Media type: no emulation

For 10.4 example there is a single entry image at Block Offset 20 (1 CD Block = 2048 bytes)

# etdump FreeBSD-11.4-RELEASE-amd64-dvd1.iso
Image in FreeBSD-11.4-RELEASE-amd64-dvd1.iso
Default entry
	System i386
	Start LBA 420 (0x1a4), sector count 4 (0x4)
	Media type: no emulation

Section header: efi, final
	Section entry
		System i386
		Start LBA 20 (0x14), sector count 1600 (0x640)
		Media type: no emulation

For 11.4 case there are two boot catalog entries, one for BIOS and one for UEFI.

Looking at this from Ubuntu machine for same FreeBSD 11.4 ISO:

$ isoinfo -i FreeBSD-11.4-RELEASE-amd64-dvd1.iso -d
CD-ROM is in ISO 9660 format
System id: FreeBSD
Volume id: 11_4_RELEASE_AMD64_DVD
Volume set id: 
Publisher id: THE FREEBSD PROJECT.  HTTP://WWW.FREEBSD.ORG/
Data preparer id: 
Application id: 
Copyright File id: 
Abstract File id: 
Bibliographic File id: 
Volume set size is: 1
Volume set sequence number is: 1
Logical block size is: 2048
Volume size is: 1868279
El Torito VD version 1 found, boot catalog is in sector 19
NO Joliet present
Rock Ridge signatures version 1 found
Eltorito validation header:
    Hid 1
    Arch 0 (x86)
    ID ''
    Key 55 AA
    Eltorito defaultboot header:
        Bootid 88 (bootable)
        Boot media 0 (No Emulation Boot)
        Load segment 0
        Sys type 0
        Nsect 4
        Bootoff 1A4 420

For 11.4 Dual Boot case there is BIOS entry at Block Offset 420 and UEFI entry at Block Offset 20.  To see what the disk structure looks like, lets extract the UEFI image and examine it.

NOTE: isoinfo does not provide the required information to extract the UEFI boot sector, as it is only providing the BIOS boot catalog entry.


Extracting FreeBSD UEFI Image

Using the FreeBSD 11.4 example from above we can extract the UEFI section by using "dd" and see content type using file (all on Ubuntu):

---
--- 1. Copy out the UEFI image by skipping 20 Blocks
---

$ dd if=FreeBSD-11.4-RELEASE-amd64-dvd1.iso of=freebsd-11.4-uefi-part-1.img skip=20 bs=2048 count=1600
1600+0 records in
1600+0 records out
3276800 bytes (3.3 MB, 3.1 MiB) copied, 0.0197891 s, 166 MB/s

---
--- 2. Have a look at Image type..
---

$ file freebsd-11.4-uefi-part.img 
freebsd-11.4-uefi-part.img: DOS/MBR boot sector, code offset 0x3c+2, OEM-ID "BSD4.4  ", root entries 512, sectors 1600 (volumes <=32 MB), Media descriptor 0xf8, sectors/FAT 5, sectors/track 63, heads 1, reserved 0x1, serial number 0x25ef1a16, unlabeled, FAT (12 bit)

So we can see that the UEFI sector is a DOS/MBR based image. This is because for UEFI boot the image is first copied to memory and then mounted to get a FAT "/efi/boot" file system containing the bootx64.efi boot program. This is different to the BIOS case which just has the binary boot program stored directly in the MBR boot sector.

Having extracted the 11.4 UEFI part you are ready to reburn your 10.4 ISO as dual boot.


Repacking a BIOS FreeBSD ISO for Dual Boot

The motivation for this was to repack the FreeBSD 10.4 ISO with a UEFI boot entry. Having extracted the UEFI boot image from FreeBSD 11.4 ISO we now need to rebuilt the ISO with this as well as default BIOS boot.

To do this (using Ubuntu) we should:

  1. Mount the 10.4 CD image
  2. Copy the 11.04 UEFI sector image into the boot directory
  3. Use "xorriso" to create new dual boot ISO
  4. Do test boot
---
--- 0. Create directories
---
mkdir LOOP && mkdir DUAL

---
--- 1. Mount ISO
---

$ sudo mount -t iso9660 -o ro,loop FreeBSD-10.4-RELEASE-amd64-disc1.iso /home/USER/LOOP

---
--- 2. Copy Contents & add the extracted UEFI image
---

$ cd DUAL
$ sudo rsync -a ../LOOP .

---
--- Copy the UEFI sectors we extract above
---

$ sudo cp USER-DIR/freebsd-11.4-uefi-part-1.img LOOP/boot/uefiboot.img

---
--- 3. Create new image
---

$ sudo xorriso -as mkisofs -V "10_4_RELEASE_AMD64_CD" -o /home/USER/freebsd-10.04-alt-dvd.iso -b boot/cdboot -boot-load-size 4 -no-emul-boot -boot-info-table -eltorito-alt-boot -e boot/uefiboot.img -no-emul-boot .
[sudo] password for USER: 
xorriso 1.5.2 : RockRidge filesystem manipulator, libburnia project.

Drive current: -outdev 'stdio:/home/USER/freebsd-10.04-alt-dvd.iso'
Media current: stdio file, overwriteable
Media status : is blank
Media summary: 0 sessions, 0 data blocks, 0 data, 7853m free
Added to ISO image: directory '/'='/home/USER/DUAL/LOOP'
xorriso : UPDATE :   18050 files added in 1 seconds
xorriso : UPDATE :   18050 files added in 1 seconds
xorriso : UPDATE :  3.81% done
xorriso : UPDATE :  59.02% done
ISO image produced: 332178 sectors
Written to medium : 332178 sectors at LBA 0
Writing to 'stdio:/home/USER/freebsd-10.04-alt-dvd.iso' completed successfully.

Some explanation:

  • BIOS Boot - "-b boot/cdboot -boot-load-size 4 -n0-emu-boot -boot-info-table" : provide the directives for the BIOS El Torito entry, where the cdboot image is what was already on the FreeBSD 10.04 to handle the BIOS CD boot (note that the sector size == 4 is as per 10.04 etdump details).
  • UEFI Boot - "-eltorito-alt-boot -e boot/uefiboot.img -no-emul-boot" : are the extra boot catalog items for the UEFI boot and reference the UEFI boot image that was extracted from the 11.04 ISO

NOTE: Futher checking of FreeBSD ISO, reveals that the BIOS & UEFI boot sector are on CD here:

  • /boot/cdboot - the MBR loader
  • /boot/boot1.efifat - the EFI (file systsem) image which contains  bootx64.efi loader

So you can use boot1.efifat as the input into xorriso "-elstorito-alt-boot -e IMG" command. See here for additional details here:

---
--- 1. Mount example ISO with BIOS/UEFI boot support
---

$ sudo mount -t iso9660 -o ro,loop FreeBSD-11.4-RELEASE-amd64-dvd1.iso /home/USER/LOOP
$ ls LOOP
bin        docbook.css  HARDWARE.HTM  media     proc          RELNOTES.TXT  sys
boot       ERRATA.HTM   HARDWARE.TXT  mnt       README.HTM    rescue        tmp
COPYRIGHT  ERRATA.TXT   lib           net       README.TXT    root          usr
dev        etc          libexec       packages  RELNOTES.HTM  sbin          var

---
--- 2. Look at the boot directory on FreeBSD iso
---

$ cd LOOP/boot
$ ls -la
total 6183
drwxr-xr-x  9 root root   8192 Jun 13 04:46 .
drwxr-xr-x 19 root root   6144 Jun 13 04:50 ..
-r--r--r--  1 root root   3554 Jun 13 04:42 beastie.4th
-r--r--r--  1 root root   8192 Jun 13 04:42 boot
-r--r--r--  1 root root    512 Jun 13 04:42 boot0
-r--r--r--  1 root root    512 Jun 13 04:42 boot0sio
-r--r--r--  1 root root    512 Jun 13 04:42 boot1
-r-xr-xr-x  1 root root  81408 Jun 13 04:42 boot1.efi
-r--r--r--  1 root root 819200 Jun 13 04:42 boot1.efifat
-r--r--r--  1 root root   7680 Jun 13 04:42 boot2
-r--r--r--  1 root root   2806 Jun 13 04:42 brand.4th
-r--r--r--  1 root root   2126 Jun 13 04:42 brand-fbsd.4th
-r--r--r--  1 root root   1185 Jun 13 04:42 cdboot
-r--r--r--  1 root root   6277 Jun 13 04:42 check-password.4th
-r--r--r--  1 root root   2111 Jun 13 04:42 color.4th
drwxr-xr-x  2 root root   2048 Jun 13 04:42 defaults
-r--r--r--  1 root root   4053 Jun 13 04:42 delay.4th
-r--r--r--  1 root root    829 Jun 13 04:44 device.hints
drwxr-xr-x  3 root root   2048 Jun 13 04:40 dtb
drwxr-xr-x  2 root root   2048 Jun 13 04:40 firmware
-r--r--r--  1 root root   4176 Jun 13 04:42 frames.4th
-r--r--r--  1 root root  58582 Jun 13 04:42 gptboot
-r--r--r--  1 root root 100582 Jun 13 04:42 gptzfsboot
-r--r--r--  1 root root  14659 Jun 13 04:42 isoboot
drwxr-xr-x  2 root root 122880 Jun 13 04:40 kernel
-r-xr-xr-x  3 root root 335872 Jun 13 04:42 loader
-r--r--r--  1 root root   7490 Jun 13 04:42 loader.4th
-r-xr-xr-x  3 root root 335872 Jun 13 04:42 loader_4th
-r-xr-xr-x  2 root root 391168 Jun 13 04:42 loader_4th.efi
-rw-r--r--  1 root root     27 Jun 13 04:46 loader.conf
-r-xr-xr-x  2 root root 391168 Jun 13 04:42 loader.efi
-r-xr-xr-x  1 root root 380928 Jun 13 04:42 loader_lua
-r-xr-xr-x  1 root root 454144 Jun 13 04:42 loader_lua.efi
-r--r--r--  1 root root    427 Jun 13 04:42 loader.rc
-r-xr-xr-x  1 root root 282624 Jun 13 04:42 loader_simp
-r-xr-xr-x  1 root root 331264 Jun 13 04:42 loader_simp.efi
-r--r--r--  1 root root   3110 Jun 13 04:42 logo-beastie.4th
-r--r--r--  1 root root   2636 Jun 13 04:42 logo-beastiebw.4th
-r--r--r--  1 root root   2214 Jun 13 04:42 logo-fbsdbw.4th
-r--r--r--  1 root root   2631 Jun 13 04:42 logo-orb.4th
-r--r--r--  1 root root   2354 Jun 13 04:42 logo-orbbw.4th
drwxr-xr-x  2 root root   4096 Jun 13 04:42 lua
-r--r--r--  1 root root    512 Jun 13 04:42 mbr
-r--r--r--  1 root root  36016 Jun 13 04:42 menu.4th
-r--r--r--  1 root root   9260 Jun 13 04:42 menu-commands.4th
-r--r--r--  1 root root   6328 Jun 13 04:42 menu.rc
-r--r--r--  1 root root  18597 Jun 13 04:42 menusets.4th
drwxr-xr-x  2 root root   2048 Jun 13 04:40 modules
-r--r--r--  1 root root    512 Jun 13 04:42 pmbr
-r--r--r--  1 root root 337920 Jun 13 04:42 pxeboot
-r--r--r--  1 root root   2738 Jun 13 04:42 screen.4th
-r--r--r--  1 root root   2613 Jun 13 04:42 shortcuts.4th
-r--r--r--  1 root root  36285 Jun 13 04:42 support.4th
-r--r--r--  2 root root 335992 Jun 13 04:42 userboot_4th.so
-r--r--r--  1 root root 402936 Jun 13 04:42 userboot_lua.so
-r--r--r--  2 root root 335992 Jun 13 04:42 userboot.so
-r--r--r--  1 root root   3065 Jun 13 04:42 version.4th
drwxr-xr-x  2 root root   2048 Jun 13 04:40 zfs
-r--r--r--  1 root root 262656 Jun 13 04:42 zfsboot
-r-xr-xr-x  3 root root 335872 Jun 13 04:42 zfsloader

---
--- 3. Lets look at boot1.efifat
---

 $ file boot1.efifat
boot1.efifat: DOS/MBR boot sector, code offset 0x3c+2, OEM-ID "BSD4.4  ", root entries 512, sectors 1600 (volumes <=32 mb), sectors fat 5, track 63, heads 1, serial number 0xbd4111ee, label: "efisys ", (12 bit), followed by --- 4. lets verify that this is a valid uefi image file $ mkdir ~ loop2 sudo mount -o loop boot1.efifat home user [sudo] password for user: ls -r loop2: efi efi: boot boot: bootx64.efi startup.nsh < code>

References & Links:

ISO Image Extract - Provides a simple explanation of how ISO image is structured and getting the El Torito details from the image, but does not solve the UEFI/BIOS problem

Debian Repacking Bootable ISO - provides information on what is required to repack a BIOS bootable CD with UEFI extension for dual boot support

etdump - FreeBSD tool that provides dump of El Torito boot catalog (Linux equivalent is "dumpet")

Fedora - Bootable CDs - a simper explanation but specific to Fedora tools

Setup, and create a custom FreeBSD ISO - article provides the FreeBSD way of achieving some of this, again with passing reference to "cdboot"

FreeBSD CD Creation - does not use xorriso but does have passing reference to "cdboot" which is the BIOS CD boot loader

xorriso - only GNU has tools with command lines a complicated this ;-), I think you could likely do the required extract/rewrite just using this, but this will require some time to read all of the options available

Image/Photo - So whats with "Salt-n-Pepa" ? The answer is, "They have a member "Spinderella" and we are doing some CD spinning".


Ubuntu Boot Catalog Example

Here is example from Linux (Ubuntu) Desktop 20-04 (FreeBSD - etdump & Ubuntu/Linux - isoinfo)

$ etdump ubuntu-20.04-desktop-amd64.iso 
Image in ubuntu-20.04-desktop-amd64.iso
Default entry
	System i386
	Start LBA 1050673 (0x100831), sector count 4 (0x4)
	Media type: no emulation

Section header: efi, final
	Section entry
		System i386
		Start LBA 1055660 (0x101bac), sector count 7936 (0x1f00)
		Media type: no emulation

This shows that there are two boot catalog entries, the default (BIOS) and extra (UEFI). The layout has BIOS boot ahead of EFI (with sector count 4 (x 512 Blocks = 2,048 Bytes == 1 CD Block), and UEFI (with sector cound 7,936 (x 512 Blocks = 4,063,232 Byes == 1,984 CD Blocks)

$ isoinfo -i ubuntu-20.04-desktop-amd64.iso -d
CD-ROM is in ISO 9660 format
System id: 
Volume id: Ubuntu 20.04 LTS amd64
Volume set id: 
Publisher id: 
Data preparer id: XORRISO-1.2.4 2012.07.20.130001, LIBISOBURN-1.2.4, LIBISOFS-1.2.4, LIBBURN-1.2.4
Application id: 
Copyright File id: 
Abstract File id: 
Bibliographic File id: 
Volume set size is: 1
Volume set sequence number is: 1
Logical block size is: 2048
Volume size is: 1325808
El Torito VD version 1 found, boot catalog is in sector 335
Joliet with UCS level 3 found
Rock Ridge signatures version 1 found
Eltorito validation header:
    Hid 1
    Arch 0 (x86)
    ID ''
    Key 55 AA
    Eltorito defaultboot header:
        Bootid 88 (bootable)
        Boot media 0 (No Emulation Boot)
        Load segment 0
        Sys type 0
        Nsect 4
        Bootoff 100831 1050673

The isoinfo "Bootoff" (Boot Offset) 1,050,673 corresponds to the boot catalog "Default Entry - Start LBA" of 1,050,673. The HEX / Decimal representations are flipped with the two tools.