Userspace & syscalls
Real EL0 user programs run under VirelaiOS, loaded from the host share by exec
and scheduled as processes. The syscall boundary is a frozen, numbered ABI.
The ABI (ADR 0007)
The syscall ABI is frozen in docs/decisions/0007-syscall-abi.md: the syscall
number goes in x8, arguments in x0–x5, the result in x0, dispatched through a
runtime-built 128-slot table. Eighty-eight slots are implemented
(0–87); the remaining slots return ENOSYS.
| Slot | Name | What it does |
|---|---|---|
| 0 | ping |
round-trip identity check |
| 1 | write |
bounded console write from an EL0 aperture |
| 2 | yield |
cooperative yield |
| 3 | exit |
terminate with a status |
| 4 | sleep |
block for N scheduler ticks |
| 5/6 | ipc_send / ipc_recv |
bounded per-process mailbox |
| 7 | procs |
read-only process-table snapshot |
| 8 | wait |
block until a peer exits, return its status |
| 9/10/11 | udp_listen / udp_send / udp_recv |
UDP from EL0 |
| 12–20 | win_* |
open/fill/present/close/move/raise/get/query/set_visible |
| 21/22 | poll_event / wait_event |
non-blocking / blocking event queue reads |
| 23–27 | file_open / file_read / file_write / file_close / dir_list |
the userland file ABI |
| 28 | exec |
launch another EL0 program (the desktop launcher's seam) |
| 29 | kill |
terminate a running EL0 program (the process monitor's kill button; TOP.BIN was retired to GOTOP.ELF) |
| 30–33 | tcp_connect / tcp_send / tcp_recv / tcp_close |
bounded TCP from EL0 |
| 34–37 | file_delete / file_rename / file_truncate / file_free |
mutate the file store from EL0 (host share since M34 HF6) |
| 38/39 | clipboard_set / clipboard_get |
the machine-global shared clipboard (the text apps' copy/paste) |
| 40/41 | timer_set / timer_cancel |
one countdown timer per process, posting TIMER events |
| 42/43 | audio_info / audio_play |
the EL0 audio seam: learn the negotiated PCM state, play bounded chunks |
| 44/45 | audio_volume / audio_mute |
bounded, process-only sound-state control |
| 46 | win_fill_batch |
batched window fills for the compositor |
| 47 | win_resize |
drag-to-resize (Arc2) |
| 48 | drag_start |
begin a drag-and-drop gesture (Arc4 #237) |
| 49 | win_raise_front |
raise to the front of the z-order |
| 50 | win_lower_back |
lower to the back of the z-order |
| 51 | notify |
post a system notification |
| 52 | win_move_to_workspace |
move a window to a workspace (Arc4 #241) |
| 53 | win_set_unsaved |
unsaved-changes marker (Arc4/Arc5) |
| 54 | setrlimit |
self-only resource limits (Arc5 #246) |
| 55 | drag_read |
read a drag-and-drop payload (Arc4) |
| 56/57 | pipe_read / pipe_write |
the M19 shell pipe (4 KiB bounded) |
| 58 | font_size |
terminal font size (M20) |
| 59/60 | ping_send / ping_poll |
the M26 ICMP-ping seam |
| 61 | win_set_title |
set a window title |
| 62 | net_stats |
net-stats snapshot (M26) |
| 63/64 | mmap / munmap |
anonymous user memory (M29) |
| 65 | wmctl |
the registered WM server's exclusive control surface (M32, ADR 0015) |
| 66 | time |
Unix wall-clock seconds from the EFI epoch or SNTP-set clock (#1058, #1775) |
| 67 | tty_attach |
attach/detach the controlling terminal front-end (ADR 0020) |
| 68 | principal |
read the calling process's {uid, caps} (M50, ADR 0024) |
| 69 | file_mode |
owner-only chmod, persisted to OWNERS.TXT (M50, ADR 0024) |
| 70 | secret_get |
read SECRETS.TXT entries — never logged (M50, ADR 0024) |
| 71 | tty_net_auth |
the delegated net-auth challenge channel — never logged (M50, ADR 0024) |
| 72 | getrandom |
capped read from the kernel CSPRNG (M51, ADR 0025) |
| 73/74 | thread / futex |
the GOOS=virelai thread + futex seam (ADR 0027) |
| 75 | exnotify |
EL0 fault-handler register (#1228) |
| 76 | sock_ready |
socket readiness for the Go netpoll (#1163) |
| 77 | file_sync |
fsync for EL0 — push /host writes to the live fd (M66a, ADR 0007 amendment) |
| 78 | time_set |
set the guest wall clock within the documented epoch range (M83b, ADR 0007 amendment) |
| 79 | fs_metadata |
bounded filesystem metadata and contained operations (B3); also the /disk VLFS surface since M100c |
| 80 | socket |
op-dispatched native socket handles (B6 #1873, ADR 0007 amendment) |
| 81/82/83 | trace / profile / memstat |
the M94 observability seam: tracer, 100 Hz sampler, heap/memory stats (ADR 0043) |
| 84–86 | udp_send_from / udp_recv_from / udp_close |
bound-source-port UDP send, sender-prefixed receive, and listen-port release (ADR 0007 amendment) |
| 87 | getpid |
an unforgeable self-pid answer (ADR 0048) |
Fault-safe uaccess
Pointer-taking syscalls copy through a uaccess layer that enforces the EL0
apertures (text read-only, stack read-write) and returns EFAULT (-3)
rather than faulting the kernel. A masked recovery window latches a real EL1
data abort, advances ELR past the faulting instruction, and converts it into a
clean EFAULT. The uaccess command proves the recovery live.
Exec and processes
exec <file> [args...] streams a flat image out of the host share (a
stateless channel read), strips its header, rebuilds the EL0 user root
around its page, packs a bounded argv
block into the text page, and spawns it. Dynamic ELF executables (M30/M31)
ride the same seam: LD.SO inspects PT_DYNAMIC, resolves imports against
the pre-staged shared-library aperture, relocates the GOT, and jumps to
AT_ENTRY — still zero libc, zero POSIX. Programs are real processes with a
lifecycle: running → exited → zombie → reaped, with exit status preserved
past the reap.
Inter-process communication
- Mailbox —
sys_ipc_send/sys_ipc_recvmove bytes between two live processes through bounded per-process rings. - Wait —
sys_wait(target)blocks the caller until the target exits and returns its status (event-driven, not POSIX wait). - Kill — the monitor's
kill <pid|name>ends a never-exiting program with the reserved status 137; the kernel owns lifetime, not the program.
What EL0 cannot do
EL0 reaches only its own text and stack leaves. It cannot touch kernel RAM, firmware, or MMIO, and its windows and sockets are kernel-owned — the owner-restricted window and UDP syscalls refuse cross-process access.