From 28918bad153dce1c809114729b177bf9629a2a44 Mon Sep 17 00:00:00 2001 From: josh Date: Sat, 18 Apr 2026 13:38:40 -0400 Subject: [PATCH] live-image: fix firmware so i915 actually loads at boot Previous attempt (c962d6d) added firmware-linux-nonfree to mkosi.conf, but the CI bundle was still 63 MB and Tiger Lake wedged on tgl_guc. Two reasons: (1) firmware-linux-nonfree on bookworm is a thin metapackage that doesn't include firmware-misc-nonfree, which is where i915 GuC/HuC blobs actually live; (2) Ubuntu's apt-packaged mkosi is old enough that Repositories=non-free-firmware shorthand likely isn't wired through to the debootstrap invocation, so firmware packages silently miss the bootstrap step entirely. Changes: - Enumerate firmware packages explicitly in mkosi.conf (firmware- misc-nonfree, firmware-iwlwifi, firmware-realtek, firmware-amd- graphics, firmware-intel-sound, intel/amd64-microcode). - Ship mkosi.sources.d/debian.sources with explicit deb822 so the non-free-firmware component is unambiguously available. - Install mkosi 24.3 via pip in CI instead of apt's older build. - Pin MODULES=most and COMPRESS=zstd via a tracked initramfs-tools config under mkosi.extra/. - Narrow .gitignore so only the generated agent binary is ignored, not the whole mkosi.extra/ tree. - New check-initrd Makefile target asserts both size (>=150 MB) and actual presence of i915/tgl_guc_*.bin inside the built initrd, so a silent firmware-drop regression fails the build loudly. Co-Authored-By: Claude Opus 4.7 --- .gitea/workflows/e2e.yml | 7 ++-- .gitea/workflows/release.yml | 9 +++-- .gitignore | 4 ++- live-image/Makefile | 34 +++++++++++++++++-- live-image/mkosi.conf | 17 ++++++++++ .../etc/initramfs-tools/initramfs.conf | 4 +++ live-image/mkosi.sources.d/debian.sources | 5 +++ 7 files changed, 73 insertions(+), 7 deletions(-) create mode 100644 live-image/mkosi.extra/etc/initramfs-tools/initramfs.conf create mode 100644 live-image/mkosi.sources.d/debian.sources diff --git a/.gitea/workflows/e2e.yml b/.gitea/workflows/e2e.yml index f454826..c214aa3 100644 --- a/.gitea/workflows/e2e.yml +++ b/.gitea/workflows/e2e.yml @@ -36,11 +36,14 @@ jobs: run: | sudo apt-get update sudo apt-get install -y --no-install-recommends \ - mkosi debootstrap squashfs-tools \ + debootstrap squashfs-tools \ systemd-ukify systemd-boot kmod \ - debian-archive-keyring \ + debian-archive-keyring python3-pip zstd \ qemu-system-x86 qemu-utils \ dnsmasq iperf3 ipxe-qemu + # See release.yml for rationale — Ubuntu's apt mkosi is too old + # to handle bookworm's non-free-firmware component correctly. + sudo pip install --break-system-packages mkosi==24.3 - name: Install templ run: go install github.com/a-h/templ/cmd/templ@v0.3.1001 diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index b09d2b6..3b60d01 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -33,9 +33,14 @@ jobs: run: | sudo apt-get update sudo apt-get install -y --no-install-recommends \ - mkosi debootstrap squashfs-tools dosfstools \ + debootstrap squashfs-tools dosfstools \ systemd-ukify systemd-boot kmod \ - debian-archive-keyring + debian-archive-keyring python3-pip zstd + # Ubuntu's apt-packaged mkosi is too old to wire + # non-free-firmware shorthand through to debootstrap. + # Install a pinned recent version directly; mkosi is + # pure-Python so --break-system-packages is harmless here. + sudo pip install --break-system-packages mkosi==24.3 - name: Install templ run: go install github.com/a-h/templ/cmd/templ@v0.3.1001 diff --git a/.gitignore b/.gitignore index 2832fd5..72d5262 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,9 @@ vetting.yaml !deploy/vetting.example.yaml live-image/out/ -live-image/mkosi.extra/ +# Only the generated agent binary is ignored — source-controlled +# files under mkosi.extra/ (e.g. initramfs-tools config) must ship. +live-image/mkosi.extra/usr/local/sbin/vetting-agent live-image/mkosi.cache/ live-image/mkosi.output/ live-image/build/ diff --git a/live-image/Makefile b/live-image/Makefile index 9a2eb7a..a8d28e7 100644 --- a/live-image/Makefile +++ b/live-image/Makefile @@ -12,9 +12,38 @@ REPO_ROOT := $(abspath ..) AGENT_BIN := $(REPO_ROOT)/bin/vetting-agent.linux-amd64 MKOSI_EXTRA_AGENT := mkosi.extra/usr/local/sbin/vetting-agent -.PHONY: all check-linux agent clean +.PHONY: all check-linux check-initrd agent clean all: check-linux $(MKOSI_EXTRA_AGENT) mkosi --force build + $(MAKE) check-initrd + +# Fail the build if the initrd doesn't actually contain the firmware +# blobs we need. Catches two failure modes: +# 1. Packages didn't install (apt/bootstrap component misconfigured) — +# the size check trips. +# 2. Packages installed but update-initramfs didn't pack them +# (MODULES=dep regression, initramfs-tools default drift) — the +# blob presence check trips. +# Requires unmkinitramfs (from initramfs-tools on the build host). +check-initrd: + @size=$$(stat -c%s build/initrd.img); \ + min=$$((150 * 1024 * 1024)); \ + if [ "$$size" -lt "$$min" ]; then \ + echo "ERROR: initrd.img is $$size bytes (< $$min) — firmware almost certainly missing."; \ + echo " Check mkosi build log for missing packages or apt failures."; \ + exit 1; \ + fi + @tmp=$$(mktemp -d); \ + trap 'rm -rf "$$tmp"' EXIT; \ + unmkinitramfs build/initrd.img "$$tmp" >/dev/null 2>&1 || { \ + echo "ERROR: unmkinitramfs failed — initrd.img may be corrupt."; exit 1; }; \ + if ! find "$$tmp" -path '*lib/firmware/i915/tgl_guc*' -print -quit | grep -q .; then \ + echo "ERROR: i915/tgl_guc firmware missing from initrd."; \ + echo " Package installed but update-initramfs didn't pack /lib/firmware."; \ + echo " Check MODULES= in /etc/initramfs-tools/initramfs.conf."; \ + exit 1; \ + fi + @echo "initrd.img OK ($$(du -h build/initrd.img | cut -f1), i915 firmware present)" agent: $(AGENT_BIN) @@ -35,4 +64,5 @@ endif @command -v mkosi >/dev/null 2>&1 || { echo "ERROR: mkosi not installed. Try: apt install mkosi"; exit 1; } clean: - rm -rf build mkosi.output mkosi.cache mkosi.extra + rm -rf build mkosi.output mkosi.cache + rm -f $(MKOSI_EXTRA_AGENT) diff --git a/live-image/mkosi.conf b/live-image/mkosi.conf index 46d17c3..f4456bb 100644 --- a/live-image/mkosi.conf +++ b/live-image/mkosi.conf @@ -12,6 +12,11 @@ Release=bookworm # amdgpu, nvidia-*, realtek NIC firmware, etc. — anything we'd want # when PXE-booting a random repaired host. Without it i915 wedges # on Tiger Lake+ and drags the serial console with it. +# +# Belt-and-suspenders: mkosi.sources.d/debian.sources ships an +# explicit deb822 sources drop-in so the bootstrap step sees the +# component regardless of how this shorthand is interpreted by the +# mkosi version doing the build. Repositories=main non-free-firmware [Output] @@ -39,6 +44,18 @@ Packages= dmidecode pciutils usbutils + initramfs-tools + # Firmware. firmware-linux-nonfree on bookworm is a thin metapackage + # that does NOT pull i915 GuC/HuC — those live in firmware-misc-nonfree. + # Enumerate explicitly so the blob for whatever hardware we boot on + # actually lands in /lib/firmware and then in the initrd. + firmware-misc-nonfree + firmware-iwlwifi + firmware-realtek + firmware-amd-graphics + firmware-intel-sound + intel-microcode + amd64-microcode firmware-linux-nonfree # Phase 4 will add: smartmontools stress-ng fio iperf3 lshw lm-sensors diff --git a/live-image/mkosi.extra/etc/initramfs-tools/initramfs.conf b/live-image/mkosi.extra/etc/initramfs-tools/initramfs.conf new file mode 100644 index 0000000..e1f1b54 --- /dev/null +++ b/live-image/mkosi.extra/etc/initramfs-tools/initramfs.conf @@ -0,0 +1,4 @@ +MODULES=most +BUSYBOX=auto +KEYMAP=n +COMPRESS=zstd diff --git a/live-image/mkosi.sources.d/debian.sources b/live-image/mkosi.sources.d/debian.sources new file mode 100644 index 0000000..ba0cf8c --- /dev/null +++ b/live-image/mkosi.sources.d/debian.sources @@ -0,0 +1,5 @@ +Types: deb +URIs: http://deb.debian.org/debian +Suites: bookworm +Components: main non-free-firmware +Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg