A bootable image: busybox + the self-hosting compiler, under qemu-system
tools/mkkiosk.sh — --selfhost adds the compiler sources, --interactive
drops to the kiosk prompt and then a shell instead of running a scripted session.
The decision the umbrella asked for, made by measurement
Which kernel + rootfs. Answered in two parts, and the first part deletes most of the question:
No rootfs is needed. file compiler/pascal26 says statically linked, and so
is every binary it emits. So the image needs no libc, no dynamic loader, no distro
userland — a kernel plus an initramfs of static binaries is a complete system.
That is why this is 15 MB and 2 seconds rather than a distro image. Had the
compiler been dynamically linked this rung would have been a rootfs project.
The kernel is fetched, not built. Measured: 12 MB, 1 second. Building one
is hours. The host's own /boot/vmlinuz is 0600 root-only, so the zero-download
path needs sudo and buys nothing. Re-decide per target if a cross image needs one —
qemu-system is installed for every pxx backend.
Measured
Host: qemu 10.2.1, /dev/kvm readable by the agent user (no sudo needed to run).
kernel (Alpine vmlinuz-virt, 6.12.81) |
12 MB, 1 s to fetch |
| initramfs, default | 4.7 MB |
initramfs, --selfhost |
7.5 MB |
| boot → kiosk → poweroff | ~2 s |
| boot → in-vm self-host fixedpoint → poweroff | 40 s end to end |
=== pxx kiosk: kernel 6.12.81-0-virt on x86_64 ===
ok: /bin/hello [code=65304B ...]
compiled inside the vm
ok: ./pascal26.stage1 [code=9752344B data=461168B bss=100985812B procs=3782]
ok: ./pascal26.stage2 [code=9752344B data=461168B bss=100985812B procs=3782]
SELF-HOST FIXEDPOINT INSIDE THE VM: stage1 == stage2
kiosk> sum 1..100 = 5050
kiosk> primes below 1000 = 168
Rung 4 is reached, and the claim wants stating precisely
The umbrella's rung 4 is "the compiler self-hosting inside the image". That is
what SELF-HOST FIXEDPOINT INSIDE THE VM is: pascal26 compiled compiler.pas to
stage1, stage1 compiled it to stage2, and cmp says they are byte-identical
(md5 a90ea54b948d82c4c20202df4fe49d96).
What this is NOT, because the claims-discipline rule applies: this is x86-64
under KVM, i.e. the native architecture on a different kernel and userland. It
is not the cross-CPU self-host that
[[bug-a-the-cross-self-host-proof-runs-a-different-configuration-than-the-native-one]]
is about. Running it under qemu-system-aarch64 without KVM is the next step and is a
strictly stronger claim.
DONE for the app, BLOCKED for the compiler (2026-08-30).
tools/mkkiosk.sh --arch=aarch64 builds and boots a 13 MB aarch64 image in
6 s, emulated with no KVM, uname -m = aarch64, running the kiosk app
cross-compiled by pxx and answering identically (5050, 168). So a
pxx-generated binary for a genuinely different CPU runs under a real kernel.
The compiler is not in that image, and the reason is measured:
pascal26 --target=<t> compiler/compiler.pas fails for every cross target —
i386, aarch64 and arm32 all at cpreproc.inc:2105
(LoadFile expects a managed-string destination), riscv32 separately on a jal
displacement out of range. Filed as
[[bug-a-no-cross-target-can-build-the-compiler-itself]]. Ordinary programs
cross-build and run fine; it is specifically the compiler that cannot be built
for a cross target. So the cross-CPU self-host stays open and is blocked on
that ticket, not on this rung.
One userland difference worth recording: the host's own busybox is static x86-64, so the x86_64 image needs no rootfs at all. Alpine's aarch64 busybox is musl-dynamic, so that image carries the 3.8 MB minirootfs for its loader and libc. Our binaries stay static and need none of it — the rootfs is there for busybox, not for us, which keeps the "no rootfs needed" finding intact rather than contradicting it.
Three facts worth not re-deriving
- The compiler resolves units relative to its own binary (
<bindir>/../lib/rtl,<bindir>/builtin). A stage built into/tmplooks for/tmp/../lib/rtland fails withunit source not found. Every stage must live beside the sources. Cost one boot to find. Makefile:22names the full unit payload —compiler/*.inc + compiler/builtin/*.pas + lib/rtl/*.pas + lib/asmcore/*.pas.lib/asmcoreis the one that is easy to miss and is not undercompiler/.- An initramfs needs
/tmpto exist. It is not created for you, and the failure surfaces assh: not foundfor a binary that was just built successfully — which reads like a linkage problem and is not one.
Gate
make lib-test is unaffected (nothing in lib/ changed). The artifact is
verified by running it: both modes reproduced end-to-end from the committed
script, output above.