Skip to content

feat: x86-64 live/installer ISO (MAD-846) - #10

Merged
madeofpendletonwool merged 2 commits into
mainfrom
feat/x86-iso
Oct 15, 2026
Merged

madeofpendletonwool merged 2 commits into
mainfrom
feat/x86-iso

Conversation

@madeofpendletonwool

Copy link
Copy Markdown
Owner

Closes MAD-846. Any x86-64 PC or mini-PC can now be a box.

What it adds

syncphony-box-<version>-amd64.iso is a hybrid ISO: it boots from a DVD or from a USB stick it was written straight onto, on UEFI or legacy BIOS (Secure Boot must be off). It has two boot entries:

  • Syncphony Box is the live box. The root is a read-only squashfs with writes going to RAM (live-boot). If the stick has a syncphony-data partition, it becomes /data and /boot/firmware (via /data/boot-firmware), so pairing and setup survive reboots.
  • Install Syncphony Box to disk runs syncphony-install, a whiptail script on tty1. You pick a disk (never the boot medium) and confirm, and can add an optional admin user with sudo. It lays the disk out as GPT: BIOS boot + ESP (SB-BOOT, mounted at /boot/firmware) + root + syncphony-data. It copies the pristine squashfs, runs grub-install for both UEFI (removable path, no NVRAM) and BIOS, then boots into the Pi's layout: boot=overlay, read-only root, /data.

How

  • Shared stage layer first (rootfs/). customise.sh pi|x86 DEB runs inside the target root and installs packages/common.list plus the platform list, the .deb, then steps/*.sh. It has no on_chroot, no ROOTFS_DIR, no /boot/firmware. stage-syncphony/ is now a thin pi-gen wrapper (00-customise) plus the Pi's boot partition (01-pi-boot). x86/live is the live-build wrapper: a chroot hook runs the same script, and a binary hook writes the menu. x86/root holds the ISO-only files.
  • Builder: Debian live-build on Trixie, in a privileged debian:trixie container (./build-iso.sh, make iso).
  • boxd:
    • On x86, cmdline.txt becomes /boot/firmware/cmdline.cfg, a one-line GRUB script that grub.cfg sources. boxd edits that set line when the file exists.
    • With no command line file at all (the live session), boxd skips resolution=/rotate= instead of writing a file and rebooting.
    • Thermals come from /sys/class/thermal when vcgencmd is missing. /v1/info then reports temperatureC only, with no throttle flags claimed.
  • audio-setup: on a PC, hdmi/hdmi2 are the first and second HDMI/DisplayPort sinks and analog is the built-in output. A Pi with HDMI0 absent still never falls back to HDMI1 (tested).
  • Package:
    • An initramfs hook carries e2fsck and the overlay module. initramfs-tools' fsck hook only adds e2fsck when fstab has an ext4 root line, and the live-built root has none.
    • The nightly update has ConditionKernelCommandLine=!boot=live.
    • Both changes are no-ops on the Pi.
  • CEC: none on x86 (boxd already tolerates no /dev/cec*). The watchdog is RuntimeWatchdogSec on iTCO and similar.
  • CI: a new iso job on ubuntu-latest runs make iso and then the smoke test, which now takes an .iso: the same rootfs checks against the squashfs, plus the ISO menu, the EFI/BIOS loaders, the initramfs contents, the installer and the live units.
  • Release: publishes the ISO and its .sha256. SHA256SUMS now covers all four files. The amd64 .deb goes into the apt repo so installed PCs update. The Imager listing stays Pi-only.
  • Docs: ADR 0013 (builder choice, shared layout, boot and installer design, trade-offs), README "On a PC", the VM procedure in docs/testing.md, persistent paths, releasing, hardware, CHANGELOG.

Verified

  • make lint, make test: 63 bats tests (4 new PC audio cases) and go test, including new tests for the cmdline.cfg format, the skip with no command line file, and sysfs thermals.
  • A full ISO build locally (amd64 under emulation): 709 MB. The smoke test passes on it, 144 checks. The initramfs has live-boot's scripts, the box's overlay script and e2fsck.
  • The installer, run from inside the built ISO's squashfs onto a loop-backed 10 GB disk: partitions, filesystems, both grub-install targets, grub.cfg and cmdline.cfg, UUID fstab, kernel links, admin user.
  • That installed disk, booted in QEMU on both BIOS (SeaBIOS) and UEFI (OVMF):
    • GRUB sourced cmdline.cfg (boot=overlay … on the kernel command line).
    • The login prompt came up in about 40 s.
    • /data was mounted: config.env written, machine-id saved, and the kiosk's Chromium profile created.
    • The real root's /etc/machine-id was still empty, so the root stayed read-only.

Not verified (needs a person and a VM or PC)

  • The live ISO booting in a VM (BIOS and UEFI) to the pairing screen. Only the installed disk was booted.
  • Audio playback once paired.
  • Pairing that survives a reboot, on the live stick's data partition and on an installed disk.
  • The whiptail flow by hand (only the unattended path was run).
  • The Pi image hasn't been rebuilt with the refactored stage. The image job on this PR is the check for that.

The steps for all of these are in docs/testing.md → "The x86 ISO in a VM".

Known limits (in the ADR)

  • video=HDMI-A-1: may not be the PC's connector name.
  • With two syncphony-data partitions attached, which one mounts is ambiguous, so the installer says to remove the stick.
  • No qcow2/raw VM image yet.

🤖 Generated with Claude Code

madeofpendletonwool and others added 2 commits October 15, 2026 11:35
Any x86-64 PC can now be a box: syncphony-box-<version>-amd64.iso is a
hybrid ISO (USB stick or DVD, UEFI and legacy BIOS) with two entries:
the live box, which keeps its pairing on a syncphony-data partition on
the stick when there is one, and "Install to disk", a whiptail
installer on tty1 that lays the disk out as BIOS boot + EFI (SB-BOOT,
at /boot/firmware) + root + syncphony-data and boots it read-only
behind the Pi's overlay.

- Shared stage layer: rootfs/customise.sh runs inside either builder's
  chroot (package lists, the .deb, the steps). stage-syncphony/ is now a
  thin pi-gen wrapper plus the Pi's boot partition; x86/live is the
  live-build wrapper (Debian Trixie), x86/root the ISO-only files.
- boxd: kernel command line from GRUB's /boot/firmware/cmdline.cfg when
  present, no write or reboot when there is no command line file (live
  session); thermals from /sys/class/thermal without vcgencmd, with no
  throttle flags claimed.
- audio-setup: hdmi/hdmi2/analog on a PC's sinks, never on a Pi.
- Package: initramfs hook carrying e2fsck and overlay; nightly update off
  in a live session.
- build-iso.sh / make iso, an iso CI job with the smoke test extended to
  the ISO, and releases publishing the ISO and the amd64 .deb.
- ADR 0013, README, testing (VM procedure), docs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…race in the initramfs check

pi-gen's on_chroot mounts a tmpfs over /tmp on its first call in a
stage, hiding rootfs/ copied there just before. The smoke test's
printf | grep -q could fail under pipefail when grep quit early.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@madeofpendletonwool
madeofpendletonwool merged commit c721812 into main Oct 15, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant