ajhahn.de
← FlashOS
Flash 63 lines
// Payload for [TEST] flibc — exercises three flibc layers:
// printf (comptime format + sys_writeConsole flush),
// malloc (bump-over-sbrk), and exit (sys_exit). fork/wait/execve are
// covered indirectly by the existing fork-stress / exec-elf scenarios
// running through their flibc-equivalent SVC wrappers, so the demo
// stays single-PT_LOAD by avoiding a self-fork.
//
// Build: aarch64-freestanding ET_EXEC via build.zig (pie=false, strip,
// ReleaseSmall, hello-style page caps). Embedded in the kernel image
// via .incbin in tools/flibc_demo_elf.S so the harness can hand its
// bytes to sys_exec without an initramfs.
//
// Trace contract verified by the test scenario in
// user_space/kernel_tests.zig:
//   "flibc hello 42\n"      — printf %d round-trip
//   "flibc malloc ok\n"     — bump-allocate 32 B, write+verify pattern
//
// Bespoke `_start` (entry .disabled in build.zig, no flibc_start shim):
// a Flash `export fn` lowers to the C-ABI export Zig already gives an
// `export fn`, and the kernel erets straight to the symbol, so the
// calling convention of a no-arg noreturn entry is immaterial. Uses an
// `orelse { … }` block handler on malloc and a value `if` for the
// pass/fail string — both land 1:1 in the lowered Zig.

use flibc

const ALLOC_BYTES u64 = 32

export fn _start() noreturn {
    flibc.printf("flibc hello %d\n", .{#as(u32, 42)})

    maybe := flibc.malloc(ALLOC_BYTES)
    if maybe == null {
        flibc.puts("flibc malloc fail")
        flibc.exit()
    }
    buf := maybe.?

    // Demand-allocate the heap page on first write — do_data_abort
    // classifies the fault as in-range heap and stamps a fresh RW+UXN
    // page before retrying. The pattern is round-trip-verified below
    // so a stale TLB / wrong-PA bug surfaces as a "flibc malloc bad"
    // line in the trace instead of a silent pass.
    var i u64 = 0
    while i < ALLOC_BYTES {
        buf[i] = #as(u8, #intCast(i)) +% 0x55
        i += 1
    }

    var ok bool = true
    i = 0
    while i < ALLOC_BYTES {
        expected := #as(u8, #intCast(i)) +% 0x55
        if buf[i] != expected {
            ok = false
        }
        i += 1
    }

    flibc.puts(if (ok) "flibc malloc ok" else "flibc malloc bad")
    flibc.exit()
}