# live-image/Makefile — builds the Debian live image that PXE-booted # hosts land in. Requires a Linux host (or WSL) with mkosi installed. # On native Windows this Makefile short-circuits with a clear message. ifeq ($(OS),Windows_NT) UNAME_S := Windows else UNAME_S := $(shell uname -s) endif 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 check-initrd repack-initrd agent clean all: check-linux $(MKOSI_EXTRA_AGENT) mkosi --force build $(MAKE) repack-initrd $(MAKE) check-initrd # mkosi + initramfs-tools produce a *boot stub* initrd (~50 MB) that # expects to mount a separate rootfs (squashfs / disk / NFS). Our PXE # channel only delivers vmlinuz+initrd.img, so there's nothing for the # stub to pivot to and boot wedges right after the kernel hands off. # # Fix: pack the entire rootfs as the initrd. Kernel unpacks the cpio.zst # into tmpfs and runs /init from it — no pivot, no live-boot, no rootfs # param. Size balloons to a few hundred MB but that's the real cost of # shipping firmware + modules + userspace in a diskless boot. repack-initrd: @# Materialize symlinked kernel/initrd into real files so downstream @# copies (release tarball) don't have to follow links. @cp -fL build/vmlinuz build/vmlinuz.real && mv build/vmlinuz.real build/vmlinuz @rm -f build/initrd.img build/initrd.img.old build/vmlinuz.old @# /init ships via mkosi.extra/init as a shell script that sets up @# api-vfs mounts and execs systemd. Force the exec bit on here — @# Windows checkouts don't preserve +x, and mkosi.extra copies the @# source-tree mode straight through. @chmod 0755 build/init @# Skip /boot: holds the old kernel + stub initrd, both superseded. @# Write to a sibling temp path so find doesn't race with the @# archive being written into the dir it's walking. @cd build && \ find . -path ./boot -prune -o -print0 \ | cpio --null --create --format=newc --quiet \ | zstd -T0 -10 -q > ../build.initrd.img.tmp @mv build.initrd.img.tmp build/initrd.img # Fail the build if the repacked initrd doesn't actually contain the # firmware we need. Two failure modes: # 1. Packages didn't install (apt/bootstrap misconfigured) → size check. # 2. Packages installed but repack-initrd missed /lib/firmware → blob # presence check. # cpio -t lists the archive; zstd -dc streams it without extracting. check-initrd: @# With repack-initrd the initrd is the full rootfs (cpio.zst), so @# 200 MB is the floor — anything smaller means firmware/userspace @# is missing or the repack step silently produced a stub. @size=$$(wc -c < build/initrd.img); \ min=$$((200 * 1024 * 1024)); \ if [ "$$size" -lt "$$min" ]; then \ echo "ERROR: initrd.img is $$size bytes (< $$min) — firmware/rootfs almost certainly missing."; \ echo " Check mkosi build log and repack-initrd output."; \ exit 1; \ fi @if ! zstd -dc build/initrd.img | cpio -t --quiet 2>/dev/null | grep -q 'lib/firmware/i915/tgl_guc'; then \ echo "ERROR: i915/tgl_guc firmware missing from initrd."; \ echo " firmware-misc-nonfree likely didn't install during bootstrap."; \ exit 1; \ fi @echo "initrd.img OK ($$(du -hL build/initrd.img | cut -f1), i915 firmware present)" agent: $(AGENT_BIN) $(AGENT_BIN): cd $(REPO_ROOT) && GOOS=linux GOARCH=amd64 go build -o $(AGENT_BIN) ./cmd/vetting-agent # Stage the prebuilt agent into mkosi.extra/ so mkosi copies it into the # image root without the postinst needing to reach outside the source tree. $(MKOSI_EXTRA_AGENT): $(AGENT_BIN) install -D -m 0755 $< $@ check-linux: ifneq ($(UNAME_S),Linux) @echo "ERROR: live-image must be built on Linux (you're on $(UNAME_S))." @echo "Run 'wsl make -C live-image all' from Windows instead." @exit 1 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 rm -f $(MKOSI_EXTRA_AGENT)