Writing U-mode Apps

How it works

userapp.aero (Aero code)
    ↓ aero compiler --emit-obj --target riscv64-unknown-none
userapp.o (RISC-V object)
    ↓ aero-ld + linker.ld → AeroOS-26R1-riscv64.elf
Kernel image (S-mode + U-mode linked together)
    ↓ QEMU -kernel → OpenSBI → kernel_start
scheduler_create2(userapp_main, 1)
    ↓ timer interrupt / sret
userapp_main() runs in U-mode!

Key concept: 26R1 has no filesystem. U-mode programs are not independent ELFs — they compile to .o and link with the S-mode kernel into one image. This is single-address-space design.

Minimal Example

myapp.aero:

extern "C" fn sys_write(s: str, n: i64) -> i64;
extern "C" fn sys_yield();

#[no_mangle]
fn myapp_main() {
    let mut count = 0;
    loop {
        sys_write("hello from myapp\n", 17);
        count = count + 1;
        sys_yield();
    }
}

Known Limitations (26R1)

Limitation Reason Fix
No inline asm Aero v1.2.4 26R2+ or C shims
No stdlib Bare-metal kernel Lightweight lib needed
No U-mode malloc No heap allocator exposed P2+
No filesystem No initrd / virtio-blk 26R3 or 27
No PMP protection OpenSBI allows all Security-driven