From 7284b4ec0b3cc692c35d420fa318ca40ca164cda Mon Sep 17 00:00:00 2001 From: Blake Ridgway Date: Fri, 21 Aug 2026 18:53:31 -0500 Subject: [PATCH] fix: ensure the ISO is actually UEFI-bootable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BOOT=efi only changed the GRUB inside the rootfs squashfs — grub-mkrescue builds the ISO bootloader from the build host's GRUB, so an ISO assembled on a host without the x86_64-efi modules + mtools shipped with NO UEFI boot entry. Booting that ISO on a UEFI machine showed: "make sure there is a bootable uefi x64 image" - check-host-deps.sh now verifies the GRUB module dirs it needs for a hybrid ISO (/usr/lib/grub/x86_64-efi from grub-efi-amd64-bin, /usr/lib/grub/i386-pc from grub-pc-bin) and mtools, not just grub-mkrescue. - build-iso.sh verifies the finished ISO has both EFI and BIOS boot entries (xorriso El Torito report) and prints the result; BOOT=efi builds FAIL if the EFI entry is missing. - GitLab CI build image gains grub-pc-bin, grub-efi-amd64-bin, mtools. - docs/building.md: hybrid-ISO burning instructions (dd) and the "bootable uefi x64 image" troubleshooting path. --- ci/.gitlab-ci.yml | 2 +- docs/building.md | 30 ++++++++++++++++++++++++++++++ scripts/build-iso.sh | 27 +++++++++++++++++++++++++++ scripts/check-host-deps.sh | 15 +++++++++++++++ 4 files changed, 73 insertions(+), 1 deletion(-) diff --git a/ci/.gitlab-ci.yml b/ci/.gitlab-ci.yml index 9996e44..9765c36 100644 --- a/ci/.gitlab-ci.yml +++ b/ci/.gitlab-ci.yml @@ -31,7 +31,7 @@ validate: image: debian:trixie before_script: - apt-get update -qq - - apt-get install -y -qq debootstrap squashfs-tools grub2-common xorriso cpio curl git make bash gdisk parted rsync dosfstools qemu-utils unzip dpkg openssl sbsigntool + - apt-get install -y -qq debootstrap squashfs-tools grub2-common grub-pc-bin grub-efi-amd64-bin mtools xorriso cpio curl git make bash gdisk parted rsync dosfstools qemu-utils unzip dpkg openssl sbsigntool script: - make ${TARGET:-iso}-${EDITION} artifacts: diff --git a/docs/building.md b/docs/building.md index 1d7c1c2..f3842c5 100644 --- a/docs/building.md +++ b/docs/building.md @@ -120,3 +120,33 @@ The ISO boots a **live** system (via `live-boot`): the rootfs is compressed to a squashfs and mounted on boot, so you can try an edition before installing it to disk. The same rootfs can be installed with the btrfs layout via `btrfs/init.sh` (the installer is follow-up work — see `docs/architecture.md`). + +### Burning the ISO + +The ISO is **hybrid** (BIOS + UEFI). Write it to a USB stick with `dd` (or +Ventoy), not as a file copy: + +```bash +sudo dd if=build/artifacts/arcline-server-0.1.0-amd64.iso of=/dev/sdX bs=4M status=progress +``` + +The build verifies the finished ISO actually contains **both** boot entries and +prints `✓ EFI boot entry present` / `✓ BIOS boot entry present`; `BOOT=efi` +builds **fail** if the EFI entry is missing. + +### UEFI says "make sure there is a bootable uefi x64 image" + +That firmware error means the ISO had no UEFI boot entry. `grub-mkrescue` +builds the ISO bootloader from the **build host's** GRUB, so the host needs the +UEFI modules even though the image is `BOOT=efi`: + +```bash +sudo apt-get install -y grub-efi-amd64-bin grub-pc-bin mtools +scripts/check-host-deps.sh # should now pass; rebuild the ISO +``` + +If the entry was present but it still won't boot, enable/disable Secure Boot +(our `BOOT=bios` ISOs are unsigned and will be refused by Secure Boot — use +`BOOT=efi make iso-server` plus the MOK flow in `docs/secureboot.md` for +signed, Secure-Boot-friendly media). + diff --git a/scripts/build-iso.sh b/scripts/build-iso.sh index 5bde7e4..7005c05 100755 --- a/scripts/build-iso.sh +++ b/scripts/build-iso.sh @@ -87,5 +87,32 @@ grub-mkrescue -o "$ARTIFACT" "$ISOFILES" -- \ -volume-label "ARCLINE_${EDITION^^}" 2>/dev/null || \ grub-mkrescue -o "$ARTIFACT" "$ISOFILES" +# ── 5. verify hybrid boot entries ─────────────────────────────────────────── +# grub-mkrescue builds the ISO bootloader from the HOST's GRUB modules. If the +# host lacks the x86_64-efi modules or mtools, the ISO has no UEFI boot entry +# and UEFI firmware shows "make sure there is a bootable uefi x64 image". +# Check the finished ISO instead of trusting the host. +if command -v xorriso >/dev/null 2>&1; then + log "verifying ISO boot entries" + ET="$(xorriso -indev "$ARTIFACT" -report_el_torito cmd 2>/dev/null || true)" + + HAS_EFI=0 + echo "$ET" | grep -qiE 'boot_image efi|efi\.img|BOOTX64\.EFI' && HAS_EFI=1 + if [[ $HAS_EFI -eq 0 ]]; then + # fallback: some xorriso versions name it differently — look in the fs + xorriso -indev "$ARTIFACT" -find / -name 'efi.img' 2>/dev/null | grep -qi 'efi\.img' && HAS_EFI=1 + fi + + HAS_BIOS=0 + echo "$ET" | grep -qiE 'boot_image isolinux|boot_image grub' && HAS_BIOS=1 + + [[ $HAS_EFI -eq 1 ]] && log " ✓ EFI boot entry present" || warn " ISO has NO EFI boot entry (UEFI will refuse it)" + [[ $HAS_BIOS -eq 1 ]] && log " ✓ BIOS boot entry present" || warn " ISO has NO BIOS boot entry (legacy BIOS will refuse it)" + + if [[ "$BOOT" == "efi" && $HAS_EFI -eq 0 ]]; then + die "BOOT=efi but the ISO has no EFI boot entry — install grub-efi-amd64-bin + mtools on the build host (scripts/check-host-deps.sh --install), then rebuild" + fi +fi + log "ISO artifact: $ARTIFACT" sha256sum "$ARTIFACT" | tee "$ARTIFACT.sha256" diff --git a/scripts/check-host-deps.sh b/scripts/check-host-deps.sh index 243f123..ab5a05d 100755 --- a/scripts/check-host-deps.sh +++ b/scripts/check-host-deps.sh @@ -31,6 +31,8 @@ NEEDED=( "openssl|openssl" "sbsign|sbsigntool" "sbverify|sbsigntool" + # hybrid ISO: mtools builds the embedded EFI image that grub-mkrescue uses + "mformat|mtools" ) MISSING=() @@ -49,6 +51,19 @@ for entry in "${NEEDED[@]}"; do fi done +# grub-mkrescue assembles the ISO bootloader from the HOST's GRUB modules. +# A missing x86_64-efi module set produces an ISO with no UEFI boot entry — +# the exact cause of "make sure there is a bootable uefi x64 image" on UEFI +# machines. Verify the module dirs directly (they are not binaries). +for spec in "/usr/lib/grub/x86_64-efi:grub-efi-amd64-bin:UEFI" \ + "/usr/lib/grub/i386-pc:grub-pc-bin:BIOS"; do + dir="${spec%%:*}"; rest="${spec#*:}"; pkg="${rest%%:*}"; what="${rest##*:}" + if [[ ! -d "$dir" ]]; then + warn "missing: GRUB $what modules in $dir (package: $pkg) — ISO will not boot via $what" + MISSING+=("$pkg") + fi +done + if [[ ${#MISSING[@]} -eq 0 ]]; then log "all host build dependencies present ✓" exit 0