Freebsd – How to create a FreeBSD ISO with mkisofs that will boot in VirtualBox under UEFI

freebsdiso

I am trying to write a script that will unpack and repack a FreeBSD ISO such that I can then do an installation with it. The goal is an unattended installation.

I've got the following script written but it doesn't work. While the original ISO will boot in VirtualBox under UEFI mode, the newly created ISO won't.

#!/bin/sh

inst_cfg="$1"
src_iso="$2"
dst_iso="$3"

iso_mnt=$(mktemp -d /tmp/freebsd-mnt-XXXXXX)
iso_wrk=$(mktemp -d /tmp/freebsd-wrk-XXXXXX)

vol_id=$(isoinfo -d -i "${src_iso}" | sed -n -e 's/^Volume id: \(.*\)$/\1/p')

md_name=$(mdconfig -a -t vnode -f "${src_iso}")
mount -t cd9660 "/dev/${md_name}" "${iso_mnt}"

cp -a -v "${iso_mnt}/" "${iso_wrk}"
cp "${inst_cfg}" "${iso_wrk}/etc/installerconfig"
mkisofs -J -R -no-emul-boot -V "${vol_id}" -b boot/cdboot -o "${dst_iso}" "${iso_wrk}"

umount "${iso_mnt}" # cd9660
mdconfig -d -u "${md_name}"

rm -rf "${iso_mnt}"
rm -rf "${iso_wrk}"

The created filesystem looks good. I've diff'ed the files of the original and custom ISOs and the only differences are the installerconfig file added and boot.catalog (which I understand mkisofs adds, but why? Could this be the problem?)

I've tried various combinations of options to mkisofs, including -R -U, -L -D -R, -J -R, but nothing makes a difference.

Additionally, the FreeBSD Handbook interestingly has the following commentary:

So, if /tmp/myboot holds a bootable FreeBSD system with the boot image
in /tmp/myboot/boot/cdboot, this command would produce
/tmp/bootable.iso:

mkisofs -R -no-emul-boot -b boot/cdboot -o /tmp/bootable.iso /tmp/myboot

This does not produce an ISO that boots under VirtualBox in UEFI mode.

Does anyone have an idea what's wrong?

Best Answer

The problem is not in the filesystem content but in the boot records and partitions:


$ xorriso -indev FreeBSD-12.0-RELEASE-amd64-bootonly.iso -report_el_torito plain -report_system_area plain
...
libisofs: WARNING : Found hidden El-Torito image. Its size could not be figured out, so image modify or boot image patching may lead to bad results.
libisofs: NOTE : Found hidden El-Torito image for EFI.
libisofs: NOTE : EFI image start and size: 20 * 2048 , 1600 * 512
...
Boot record  : El Torito , MBR protective-msdos-label cyl-align-off GPT
...
El Torito catalog  : 19  1
El Torito images   :   N  Pltf  B   Emul  Ld_seg  Hdpt  Ldsiz         LBA
El Torito boot img :   1  BIOS  y   none  0x0000  0x00      4         420
El Torito boot img :   2  UEFI  y   none  0x0000  0x00   1600          20
El Torito img blks :   1  1204
El Torito img blks :   2  400
System area options: 0x00000201
System area summary: MBR protective-msdos-label cyl-align-off GPT
ISO image size/512 : 675508
Partition offset   : 0
MBR heads per cyl  : 0
MBR secs per head  : 0
MBR partition table:   N Status  Type        Start       Blocks
MBR partition      :   1   0x00  0xee            1       676107
GPT                :   N  Info
GPT backup problems:      Not a GPT 1.0 header of 92 bytes for 128 bytes per entry
GPT disk GUID      :      7ce0bf52def9e8118c360cc47ad8b808
GPT entry array    :      2  2  separated
GPT lba range      :      3  676105  676107
GPT partition name :   1  
GPT partition GUID :   1  6de0bf52def9e8118c360cc47ad8b808
GPT type GUID      :   1  28732ac11ff8d211ba4b00a0c93ec93b
GPT partition flags:   1  0x0000000000000000
GPT start and size :   1  80  1600
GPT partition name :   2  
GPT partition GUID :   2  73e0bf52def9e8118c360cc47ad8b808
GPT type GUID      :   2  9d6bbd83417fdc11be0b001560b84f0f
GPT partition flags:   2  0x0000000000000000
GPT start and size :   2  3  29

Both, the BIOS boot image and the EFI System Partition are not files in the ISO but rather unnamed block areas.

If you don't go the way of appending a session by fixed growisofs or by


cp FreeBSD-12.0-RELEASE-amd64-bootonly.iso new.iso
xorriso -boot_image any keep \
        -dev new.iso \
        -map /path/to/your_installerconfig /etc/installerconfig
        [other -map commands for files or directory trees ...]

then you need to extract those areas


dd if=FreeBSD-12.0-RELEASE-amd64-bootonly.iso bs=512 skip=80 count=1600 \
   of=efi_part.img
dd if=FreeBSD-12.0-RELEASE-amd64-bootonly.iso bs=512 skip=1680 count=4816 \
   of=bios_boot.img

(El Torito gives LBAs in blocks of 2048 but sizes in blocks of 512. 4 * 420 = 1680. The BIOS image size of 1204 blocks of 2048 bytes is estimated by the lowest filesystem object LBA that's above 420. Possibly it is smaller but any oversize should not harm.)

Then there is the MBR code for BIOS booting from USB stick:


dd if=FreeBSD-12.0-RELEASE-amd64-bootonly.iso bs=1 count=446 \
   of=mbr_code.img

If you do not plan to boot by BIOS, then bios_boot.img and mbr_code.img are not needed.

Building a new ISO from unpacked and mainpulated tree $HOME/files_for_iso and the extracted image files


xorriso -as mkisofs \
        -o new.iso \
        -d -l -r \
        -V "12_0_RELEASE_AMD64_BO" \
        -G mbr_code.img \
        -b /bios_boot.img \
           -no-emul-boot -boot-load-size 4 \
        -eltorito-alt-boot \
        -append_partition 2 0xef efi_part.img \
        -e '--interval:appended_partition_2:all::' \
           -no-emul-boot \
        bios_boot.img $HOME/files_for_iso

This will yield no GPT but rather an MBR partition table with two partitions of type 0x83 for the ISO filesystem and 0xef for the EFI System Partition.

(Whether BIOS boots from USB stick would have to be tested. Many MBRs need info patched in to find the next stage of boot programs.)

Related Question