0014 — Bootable memtest86+ (ESP-staged, kexec + GRUB seam)
Status: accepted (2026-06-22) — ratified by maintainer; proposed 2026-06-05
Context
SPEC §3 ships a userland memtester in the recovery shell, but it only tests kernel-allocatable RAM. A bootable memtest86+ tests all physical RAM, and it’s the one diagnostic you want before any disk/crypto/pool exists — so it should run the moment keyboot’s env is up, disk-independent. The standout use: trigger it over SSH on a headless box (reboot → keyboot comes up networked, pre-unlock → SSH in → memtest), watching progress over IPMI serial-over-LAN.
memtest86+ ships two relevant artifacts: an EFI app (memtest.efi, for a
firmware/GRUB chainload) and a kexec-loadable image (memtest.bin,
bzImage-compatible). They suit two different launch paths.
Decision
Stage memtest on the keyboot-owned ESP at /EFI/keyboot/memtest.{efi,bin}
(read pre-unlock — the ESP is already mounted ro at /esp in stage-1 for the
boot-once marker). Keeps the keyboot initramfs lean (relevant to the A/B ESP
slots, ADR 0009) and lets memtest be updated per-host without rebuilding the
initramfs. Three entry points:
keyboot.mode=memtest— keyboot runs stage-1 (console + udev + ESP mount), then kexecsmemtest.bininstead of unlocking. Scriptable + SSH/IPMI-friendly; the headless killer feature.- stage-8 menu action
m— for an operator already at the console/SSH during a normal boot, anm) memtestaction kexecs it. - GRUB
11_keyboot_memtestseam — a grub.d snippet emitting amenuentry 'memtest86+'that chainloads/EFI/keyboot/memtest.efidirectly. No kexec, so it’s the reliable fallback that works before keyboot even starts.
Serial by default: the kexec append carries console=ttyS0,115200 so
memtest86+ 6.x’s serial output reaches IPMI SoL on a headless box.
The kexec form is best-effort/unverified
kexec -l memtest.bin --append=… ; kexec -e is the documented memtest86+ 6.x
kexec path, but the exact loader behaviour (bzImage vs multiboot, EFI vs BIOS
image) is only confirmable on real hardware (QEMU/OVMF is not a faithful
proxy). Per the operator decision we ship it now as best-effort with a clear
log marker; if a box can’t kexec it, the GRUB seam (chainload) is the reliable
path and is unaffected. Real-hardware verification + correction is a follow-up.
Sourcing the binaries
memtest86+ is GPLv2 but a build artifact, not vendored here. Staging is
conditional on KEYBOOT_MEMTEST_DIR (a dir holding memtest.efi/memtest.bin)
at build/install time; absent it, the memtest entries are simply not emitted
(graceful). Docs point at memtest.org for the images.
Alternatives considered
- Bundle in the initramfs — always-available even with no readable ESP, but costs initramfs size (× the A/B slots) for a rarely-used tool; the ESP is already mounted pre-unlock, so ESP-staging gets ~the same availability cheaper.
- Netboot/iPXE only — zero local footprint, but needs the network + a netboot server; doesn’t cover “diagnose this box right now, no net”. (The iPXE menu remains a good addition — deferred, not chosen this pass.)
- kexec the
.efi— rejected: kexec loads kernels/bzImages, not EFI apps; the.efiis for the GRUB/firmware chainload path.
Consequences
- Two artifacts staged per host (efi + bin), a few MiB on the ESP.
- The kexec entry points (mode + stage-8) are unverified until real hardware; the GRUB chainload seam is the dependable path meanwhile.
- Pure bits (the kexec argv builder, the GRUB snippet render) are unit-tested; the kexec execution is what needs hardware.
- Follow-ups: real-hardware kexec verification; the iPXE netboot menu (keyboot/memtest/rescue); auto-staging memtest in the build/CI image.