ADR-022 — Freestanding CRT / libctos
- Status: Accepted (CRT mile Verified when the serial / tests pass; Track A / app hosting still Planned)
- Date: 2026-09-12
Context
Track A (issue #31) wants a freestanding program to call the A1 ABI without glibc or POSIX. Issue #33 is this mile: a documented, probed CRT + libctos that wraps ADR-021 numbers 16–18.
A1 already proved the kernel performs exit / uart_write / yield for a hand-encoded trampoline. That is not a library a program can link. A3 (ELF loader) must not start until something exists to link against.
Options:
- Wait for a loader. Would block A2 on A3.
- C/asm static lib only. Fine later; this tree is Rust-first and already uses
aarch64-ctos. no_stdcrate + asm stubs + a hello payload copied onto today’s standing EL0 page. Proves link + run without a guest ELF loader.
Decision
libctoscrate (libctos/).no_stdwrappersexit/uart_write/yield_nowover asm stubs (sys.S:ctos_exit/ctos_uart_write/ctos_yield). SVC immediates are 16 / 17 / 18. Reserved 0–2 stay ADR-013 probes — the CRT must not issue them.- CRT is
_startinlibctos/src/crt0.S: kernelERETalready setSP_EL0;_startcallsmain, thenctos_exit. No argv, noenviron, no libc init. Not glibc/muslcrt0. - Hello payload (
user/hello-libctos). Ano_std/no_mainprogram linkslibctos, printslibctos: hiviauart_write,yields, printslibctos: ok, returns 0. Linked atpaging::EL0_PAGE(0x80002000) withuser/hello-libctos/linker.ld. - Not a guest loader.
build.rscompiles that program on the host and extractsPT_LOADbytes at/afterEL0_PAGE(size metadata + publish). The kernel copies a flatten of FAT/helloonto the standing EL0 page andERETs — same style as A1. Host flatten inbuild.rsis not A3. Guest flatten of the FAT ELF (ADR-032) is still A2 memcpy, not the A3 map. - Code page + stack page. The image must fit in 3584 bytes on
EL0_PAGE(EL0-exec, no EL0 data — same AP as A1). Rustmainsavesx30on SP; that store cannot land on the code page (SCTLR.WXNforbids making it W+X). A second map-window page is EL0-RW NX. rust-lld’s extra ELF-headerPT_LOADat0x80000000is discarded at extract time. - Fail-closed probe. Hello serial
libctos: hi+libctos: ok(from the payload viauart_write) + kernellibctos: linked.scripts/qemu-smoke.shgreps those and rejectslibctos: probe missed.#[test_case]covers the trip and that the blob encodes SVC #16/#17/#18 and not #0/#1/#2. Existingsvc:/el0:markers stay. - Honesty. Say “a program linked against libctos issued the A1 ABI and the kernel performed the documented effect” only when the serial / tests pass. Do not say: app hosting is done, Linux ABI, POSIX, userspace, “EL0 isolated,” or “secure OS.” Track A A3–A9 stay Planned.
- NFR-10 text is revised in place (ID unchanged) to name this CRT mile. Do not mint FR-16+ or NFR-15+. Guest ELF load is ADR-023, not this ADR.
Consequences
- Code:
libctos/,user/hello-libctos/,build.rs,src/libctos.rs. - Docs: syscall.md, el0.md, building-or-porting.md. Roadmap cites #33 / Track A #31.
- A3 (ELF / raw loader into user TTBR0) may load a separate image. It is not this PR.