Operating Systems

Create an OpenBSD Installation Image with a FAT32 ESP and Firmware

By David Uhden Collado - Updated

Build an OpenBSD amd64 installation image with a 260 MiB FAT32 ESP, 1,536 MiB of FFS space, and optional firmware without rebuilding the base system.

Prebuilt Download

As an alternative to rebuilding the image manually, install79-fat32.img is available. It is a custom, unofficial modification of OpenBSD amd64 installNN.img installation image, not an independent OpenBSD distribution or build. Update the filename and checksum together when publishing a new release.

Prebuilt image details
Name install79-fat32.img
Platform and architecture OpenBSD, amd64
Partitioning MBR, following the official installation image
ESP 260 MiB FAT32
Base content Derived from the official installNN.img image
Additional firmware None
SHA256 8521010252d97d2d4fe3becc47c58363640c74bff5fcea4b5267fed10f9f6f7f

The prebuilt image does not include any additional firmware. No proprietary Wi-Fi firmware or other externally distributed firmware has been bundled with it, to avoid potential licensing or redistribution restrictions. Users who require firmware should add it themselves with OpenBSD's official mechanisms, such as fw_update.

Scope and Preparation

Run the whole procedure as root. It starts with the official installNN.img and copies its contents to a larger image; it neither rebuilds OpenBSD nor changes the bsd.rd ramdisk. The result retains Legacy BIOS and UEFI boot support.

Before reusing mount points, leave them and inspect active mounts and vnd devices:

cd /
mount | grep '/mnt/'
vnconfig -l

Unmount only resources from a prior attempt and detach only its vnd devices:

umount /mnt/dst-efi 2>/dev/null || :
umount /mnt/dst 2>/dev/null || :
umount /mnt/src-efi 2>/dev/null || :
umount /mnt/src 2>/dev/null || :
vnconfig -u vnd1 2>/dev/null || :
vnconfig -u vnd0 2>/dev/null || :

The last two commands are only examples; do not detach other vnd devices. Create the working directory and mount points, and make sure /home has several GiB free for both the official and custom images:

mkdir -p /home/openbsd-custom
cd /home/openbsd-custom
df -h /home
mkdir -p /mnt/src /mnt/src-efi /mnt/dst /mnt/dst-efi

The proposed layout uses 260 MiB for the FAT32 ESP and 1,536 MiB for FFS, for 1,796 MiB total. At 512-byte sectors, that is 532480 sectors for the ESP, 3145728 for FFS, and 3678208 in total.

Download and Mount the Official Image

Before running the commands, set the release in both its published and dotless forms. When OpenBSD is updated, change these values and keep the rest of the procedure:

VERSION=7.9
VERSION_NUMBER=79
ARCH=amd64
IMAGE="install${VERSION_NUMBER}.img"
CUSTOM_IMAGE="install${VERSION_NUMBER}-fat32.img"

Download the amd64 image, checksum, and signature. Verify the SHA-256 checksum first, then the signature:

ftp https://cdn.openbsd.org/pub/OpenBSD/${VERSION}/${ARCH}/${IMAGE}
ftp https://cdn.openbsd.org/pub/OpenBSD/${VERSION}/${ARCH}/SHA256
ftp https://cdn.openbsd.org/pub/OpenBSD/${VERSION}/${ARCH}/SHA256.sig
sha256 -C SHA256 "$IMAGE"
signify -Cp "/etc/signify/openbsd-${VERSION_NUMBER}-base.pub" \
    -x SHA256.sig "$IMAGE"

The checksum must report ${IMAGE}: OK, and the signature verification must include Signature Verified. Attach the image; vnconfig selects a free vnd device and writes its name to standard output:

SRCVND=$(vnconfig "/home/openbsd-custom/${IMAGE}")
echo "$SRCVND"
fdisk "$SRCVND"
disklabel "$SRCVND"
mount -o ro "/dev/${SRCVND}a" /mnt/src
mount -t msdos -o ro "/dev/${SRCVND}i" /mnt/src-efi
df -h /mnt/src /mnt/src-efi
ls -la /mnt/src
ls -la /mnt/src-efi/efi/boot
du -sh /mnt/src

The original ESP must contain BOOTIA32.EFI and BOOTX64.EFI. The official image allocates roughly 800 MiB for FFS and is tightly packed; the target image leaves more space for the sets and firmware.

Create and Format the Target Image

Remove only a failed custom image and create the new 1,796 MiB image. Attach it and record the assigned device:

cd /home/openbsd-custom
rm -f "$CUSTOM_IMAGE"
dd if=/dev/zero of="$CUSTOM_IMAGE" bs=1m count=1796
ls -lh "$IMAGE" "$CUSTOM_IMAGE"
DSTVND=$(vnconfig "/home/openbsd-custom/${CUSTOM_IMAGE}")
echo "$DSTVND"
vnconfig -l

Create the MBR with an EF EFI partition and an A6 OpenBSD partition. This follows the official USB image layout with larger sizes:

fdisk -yi \
    -l 3145728 \
    -b 532480 \
    -f /usr/mdec/mbr \
    "$DSTVND"
fdisk "$DSTVND"
echo '/ *' | disklabel -wAT- "$DSTVND"
disklabel "$DSTVND"

Before continuing, confirm that EF has 532480 sectors and A6 has about 3145728. The disklabel must include a as 4.2BSD, c as unused, and i as MSDOS.

Explicitly format the ESP as FAT32 and create FFS1. Do not use -c: it controls fragments per cylinder group, not filesystem size; newfs takes the size from partition a.

newfs_msdos -F 32 "/dev/r${DSTVND}i"
newfs -O 1 -m 0 -o space -i 524288 "/dev/r${DSTVND}a"
mount "/dev/${DSTVND}a" /mnt/dst
mount -t msdos "/dev/${DSTVND}i" /mnt/dst-efi
df -h /mnt/src /mnt/dst /mnt/dst-efi
df -i /mnt/src /mnt/dst

/mnt/dst must show about 1.5 GiB. If it shows about 800 MiB, stop and review the partition table before copying data.

Copy the Installer, Boot Files, and Firmware

Copy the installer tree while preserving permissions and other attributes. The copy should no longer end with No space left on device:

cd /mnt/src
pax -rw -pe . /mnt/dst
cd /
df -h /mnt/dst
ls -lah /mnt/dst
ls -lh "/mnt/dst/${VERSION}/${ARCH}/"

The sets directory must contain the sets for the selected release, along with bsd, bsd.mp, and bsd.rd. Also copy the EFI bootloaders and reinstall BIOS boot support; run the non-writing mode first:

mkdir -p /mnt/dst-efi/efi/boot
cp -p /mnt/src-efi/efi/boot/* /mnt/dst-efi/efi/boot/
ls -lah /mnt/dst-efi/efi/boot/
installboot -nv -r /mnt/dst "$DSTVND" \
    /usr/mdec/biosboot /mnt/dst/boot
installboot -v -r /mnt/dst "$DSTVND" \
    /usr/mdec/biosboot /mnt/dst/boot

Add firmware for the installed system if required. Firmware does not make Wi-Fi work inside bsd.rd during installation; that would require modifying its ramdisk, which is a separate procedure.

cd /mnt/dst
fw_update -Fv iwx
fw_update -Fv iwm
cd /
fw_update -Fln iwx
find /mnt/dst -maxdepth 2 -type f -name '*firmware*.tgz' -o \
    -name '*firmware*.tgz.sig'

fw_update -F downloads firmware and its signatures to the current directory. Use one or several drivers according to the destination hardware.

Unmount and Verify the Image

Synchronize data and unmount the ESP before FFS, for both the target and source. Detach both vnd devices as well:

cd /
sync
umount /mnt/dst-efi
umount /mnt/dst
umount /mnt/src-efi
umount /mnt/src
mount | grep '/mnt/'
vnconfig -u "$DSTVND"
vnconfig -u "$SRCVND"
vnconfig -l

Attach the final image again from scratch. Filesystem checks must not report errors that require repair:

cd /home/openbsd-custom
VERIFYVND=$(vnconfig "$CUSTOM_IMAGE")
echo "$VERIFYVND"
fdisk "$VERIFYVND"
disklabel "$VERIFYVND"
fsck_msdos -n "/dev/r${VERIFYVND}i"
fsck_ffs -n "/dev/r${VERIFYVND}a"
mount -t msdos -o ro "/dev/${VERIFYVND}i" /mnt
df -h /mnt
ls -lah /mnt/efi/boot
umount /mnt
mount -o ro "/dev/${VERIFYVND}a" /mnt
ls -lah /mnt
ls -lh /mnt/bsd.rd
ls -lh "/mnt/${VERSION}/${ARCH}/"
umount /mnt
vnconfig -u "$VERIFYVND"
vnconfig -l
mount | grep '/mnt/'

The finished image is /home/openbsd-custom/${CUSTOM_IMAGE}. It contains an MBR, a FAT32 ESP with EFI/BOOT/BOOTX64.EFI and BOOTIA32.EFI, and an FFS1 partition with the installer, boot, bsd, bsd.rd, the sets, and, if added, firmware files.

Write It to a USB Drive

Identify the USB drive unambiguously before writing. For example, if sd2 is truly the correct device:

sysctl hw.disknames
disklabel sd2
dd if="/home/openbsd-custom/${CUSTOM_IMAGE}" \
    of=/dev/rsd2c bs=1m
sync

Do not use /dev/rsd2c without verifying the disk: dd writes directly over the destination device.