FlashOS tour · 7 / 15
7. The Syscall Boundary
An EL0 program cannot call a kernel Rust function directly. It places the
syscall number in x8, arguments in x0 through x5, and executes svc #0.
The raw wrappers live in the FlashSDK flashsdk-rt crate (syscall.rs).
Exception entry lives in arch/aarch64/entry.S; handler logic and the relocated
dispatch table live in crates/kernel/src/syscall/sys.rs.
Entry frame
The vector saves a 272-byte KeRegs frame on the current task's dedicated
kernel stack. It validates that x8 < 56, looks up the relocated function
pointer, invokes the handler, places the return value back in the saved frame,
and restores state for eret.
EL0 wrapper
→ svc #0
→ vector saves KeRegs
→ bounds check x8
→ Rust handler table
→ result in x0
→ eret to EL0
ABI ownership
The FlashSDK flashsdk-abi crate defines syscall IDs and shared value types
such as Dirent; the kernel and every user program consume it at one pinned
revision. FlashSDK is the narrow public syscall/userspace ABI, runtime, base
library, and target-and-link contract. Private task records, saved frames, VFS
objects, descriptor internals, and the user-page descriptor bits stay private in
the repository's own crates/kernel-abi.
Current syscall groups
| Slots | Purpose |
|---|---|
| 1–13 | process lifecycle, open/seek, heap, diagnostics |
| 18 | anonymous pipe |
| 25–26, 30 | console mode and test input seam |
| 31 | path-resolved ELF execve |
| 32–35 | unified read, write, close, dup2 |
| 36–38, 48 | CWD, readdir, kernel log, getcwd |
| 39–47 | credentials, auth, password change, reboot |
| 49–52 | memory, uptime, CPU temperature/frequency |
| 53–55 | FAT32 create, unlink, rename |
Retired slots return an error rather than silently changing meaning. Reserved slots remain stubs.
User pointers are data, not references
Handlers use bounded copy helpers to validate and prefault complete user
ranges. An invalid pointer produces an error such as EFAULT; it must not be
converted into a trusted Rust reference or allowed to fault deep inside the
kernel.
Synchronous aborts decode ESR and the fault address. Legal heap and stack
translation faults can be recovered; terminal invalid entries print
ERROR CAUGHT, a hard watchdog failure.
[!CAUTION] The kernel stack is only one 4 KiB page, with the saved frame at its top. Large syscall-local values are a correctness risk; substantial scratch data belongs in bounded dedicated storage.
Next, we inspect what the ELF loader hands to a Rust user program.