live-image: pack full rootfs as initrd so PXE actually boots userspace
update-initramfs produces a boot stub (~50 MB) that expects to mount a separate rootfs over squashfs/disk/NFS. Our PXE channel only ships vmlinuz+initrd.img, so the stub had nothing to pivot to — kernel finished hand-off and the system wedged with firmware, modules, and userspace stranded in the 545 MB rootfs dir we never delivered. Replace with an everything-in-initramfs build: cpio.zst the full rootfs (minus /boot) as the initrd, add /init -> sbin/init for the kernel's runtime entrypoint, materialize the kernel symlink into a real file. Bump check-initrd floor to 200 MB and switch the firmware grep from unmkinitramfs (boot-stub-specific) to zstd | cpio -t. Also add cpio to the CI apt deps.
This commit is contained in:
@@ -39,7 +39,7 @@ jobs:
|
|||||||
debootstrap squashfs-tools \
|
debootstrap squashfs-tools \
|
||||||
systemd-ukify systemd-boot kmod bubblewrap \
|
systemd-ukify systemd-boot kmod bubblewrap \
|
||||||
debian-archive-keyring python3-pip git zstd \
|
debian-archive-keyring python3-pip git zstd \
|
||||||
qemu-system-x86 qemu-utils \
|
qemu-system-x86 qemu-utils cpio \
|
||||||
dnsmasq iperf3 ipxe-qemu
|
dnsmasq iperf3 ipxe-qemu
|
||||||
# See release.yml for rationale — Ubuntu's apt mkosi is too old
|
# See release.yml for rationale — Ubuntu's apt mkosi is too old
|
||||||
# to handle bookworm's non-free-firmware component correctly.
|
# to handle bookworm's non-free-firmware component correctly.
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ jobs:
|
|||||||
sudo apt-get install -y --no-install-recommends \
|
sudo apt-get install -y --no-install-recommends \
|
||||||
debootstrap squashfs-tools dosfstools \
|
debootstrap squashfs-tools dosfstools \
|
||||||
systemd-ukify systemd-boot kmod bubblewrap \
|
systemd-ukify systemd-boot kmod bubblewrap \
|
||||||
debian-archive-keyring python3-pip git zstd
|
debian-archive-keyring python3-pip git zstd cpio
|
||||||
# Ubuntu's apt-packaged mkosi is too old to wire
|
# Ubuntu's apt-packaged mkosi is too old to wire
|
||||||
# non-free-firmware shorthand through to debootstrap.
|
# non-free-firmware shorthand through to debootstrap.
|
||||||
# mkosi isn't published on PyPI under v24+ — install the
|
# mkosi isn't published on PyPI under v24+ — install the
|
||||||
|
|||||||
+42
-22
@@ -12,38 +12,58 @@ REPO_ROOT := $(abspath ..)
|
|||||||
AGENT_BIN := $(REPO_ROOT)/bin/vetting-agent.linux-amd64
|
AGENT_BIN := $(REPO_ROOT)/bin/vetting-agent.linux-amd64
|
||||||
MKOSI_EXTRA_AGENT := mkosi.extra/usr/local/sbin/vetting-agent
|
MKOSI_EXTRA_AGENT := mkosi.extra/usr/local/sbin/vetting-agent
|
||||||
|
|
||||||
.PHONY: all check-linux check-initrd agent clean
|
.PHONY: all check-linux check-initrd repack-initrd agent clean
|
||||||
all: check-linux $(MKOSI_EXTRA_AGENT)
|
all: check-linux $(MKOSI_EXTRA_AGENT)
|
||||||
mkosi --force build
|
mkosi --force build
|
||||||
|
$(MAKE) repack-initrd
|
||||||
$(MAKE) check-initrd
|
$(MAKE) check-initrd
|
||||||
|
|
||||||
# Fail the build if the initrd doesn't actually contain the firmware
|
# mkosi + initramfs-tools produce a *boot stub* initrd (~50 MB) that
|
||||||
# blobs we need. Catches two failure modes:
|
# expects to mount a separate rootfs (squashfs / disk / NFS). Our PXE
|
||||||
# 1. Packages didn't install (apt/bootstrap component misconfigured) —
|
# channel only delivers vmlinuz+initrd.img, so there's nothing for the
|
||||||
# the size check trips.
|
# stub to pivot to and boot wedges right after the kernel hands off.
|
||||||
# 2. Packages installed but update-initramfs didn't pack them
|
#
|
||||||
# (MODULES=dep regression, initramfs-tools default drift) — the
|
# Fix: pack the entire rootfs as the initrd. Kernel unpacks the cpio.zst
|
||||||
# blob presence check trips.
|
# into tmpfs and runs /init from it — no pivot, no live-boot, no rootfs
|
||||||
# Requires unmkinitramfs (from initramfs-tools on the build host).
|
# 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
|
||||||
|
@# Kernel execs /init from the unpacked initramfs. systemd-sysv puts
|
||||||
|
@# init at /sbin/init; add the top-level symlink the kernel looks for.
|
||||||
|
@[ -e build/init ] || ln -sf sbin/init 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:
|
check-initrd:
|
||||||
@# build/initrd.img is a symlink into build/boot/; use wc -c (which
|
@# With repack-initrd the initrd is the full rootfs (cpio.zst), so
|
||||||
@# follows symlinks) to get the real byte count. `stat -c%s` without
|
@# 200 MB is the floor — anything smaller means firmware/userspace
|
||||||
@# -L returns the symlink's path length instead of the target size.
|
@# is missing or the repack step silently produced a stub.
|
||||||
@size=$$(wc -c < build/initrd.img); \
|
@size=$$(wc -c < build/initrd.img); \
|
||||||
min=$$((150 * 1024 * 1024)); \
|
min=$$((200 * 1024 * 1024)); \
|
||||||
if [ "$$size" -lt "$$min" ]; then \
|
if [ "$$size" -lt "$$min" ]; then \
|
||||||
echo "ERROR: initrd.img is $$size bytes (< $$min) — firmware almost certainly missing."; \
|
echo "ERROR: initrd.img is $$size bytes (< $$min) — firmware/rootfs almost certainly missing."; \
|
||||||
echo " Check mkosi build log for missing packages or apt failures."; \
|
echo " Check mkosi build log and repack-initrd output."; \
|
||||||
exit 1; \
|
exit 1; \
|
||||||
fi
|
fi
|
||||||
@tmp=$$(mktemp -d); \
|
@if ! zstd -dc build/initrd.img | cpio -t --quiet 2>/dev/null | grep -q 'lib/firmware/i915/tgl_guc'; then \
|
||||||
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 "ERROR: i915/tgl_guc firmware missing from initrd."; \
|
||||||
echo " Package installed but update-initramfs didn't pack /lib/firmware."; \
|
echo " firmware-misc-nonfree likely didn't install during bootstrap."; \
|
||||||
echo " Check MODULES= in /etc/initramfs-tools/initramfs.conf."; \
|
|
||||||
exit 1; \
|
exit 1; \
|
||||||
fi
|
fi
|
||||||
@echo "initrd.img OK ($$(du -hL build/initrd.img | cut -f1), i915 firmware present)"
|
@echo "initrd.img OK ($$(du -hL build/initrd.img | cut -f1), i915 firmware present)"
|
||||||
|
|||||||
Reference in New Issue
Block a user