Trap ABI Reference
Implemented
The contract is the protocol
This page documents the Trap ABI — the unavoidable CPU-facing entry layer (ecall / svc #0 / syscall). It is an implementation detail of how a fiber enters the kernel, not the application contract.
The stable contract that applications depend on is the Kernel Protocol: typed ION Ring packets, signed BKDL descriptors, and capability verbs. Read that page first.
Scope of this page
The Trap ABI is what libnexus, language runtimes, and the Membrane POSIX bridge use to perform the four mechanical operations the protocol needs:
- submit a packet to a TX ring
- await a reply from an RX ring (yielding if empty)
- invoke a capability verb against a cap bundle
- yield the remaining quantum
The table below documents the current implementation surface of those entry points. Several operations carry POSIX-style names (SYS_OPEN, SYS_READ, integer file descriptors) because the current implementation exposes a transitional shim. The long-term path is the Native Interface: typed channels, capability handles, structured objects, no int fd. Applications that target the long-term contract should link against libnexus rather than reach for the raw trap numbers below.
Entry convention
Rumpk traps are invoked via ecall (RISC-V) or svc #0 (ARM64). The syscall number is in a7/x8, arguments in a0-a2/x0-x2, return value in a0/x0.
VFS Operations
| Nr | Name | Args | Returns | Description |
|---|---|---|---|---|
0x200 | SYS_OPEN | path, flags | fd or -1 | Open file in VFS (/sysro, /nexus, /state) |
0x201 | SYS_CLOSE | fd | 0 or -1 | Close file descriptor |
0x202 | SYS_LIST | buf, maxlen | count | List directory entries |
0x203 | SYS_READ | fd, buf, len | bytes read | Read from fd (stdin blocks until input) |
0x204 | SYS_WRITE | fd, buf, len | bytes written | Write to fd (stdout/stderr to PTY or console) |
0x205 | SYS_IOCTL | fd, request | 0 | I/O control (stub) |
0x206 | SYS_FCNTL | fd, cmd, arg | varies | File control (F_DUPFD supported) |
Process Control
| Nr | Name | Args | Returns | Description |
|---|---|---|---|---|
0x01 | SYS_EXIT | status | — | Terminate current fiber |
0x65 | SYS_NANOSLEEP | ns | 0 | Sleep for ns nanoseconds |
0x66 | SYS_GET_TIME | — | ns | Get current time in nanoseconds |
0x100 | SYS_SPAWN | path, arg | fiber_id | Spawn new fiber from ELF |
0x101 | SYS_PLEDGE | mask | 0 or -1 | Narrow pledge mask (can only restrict, never widen) |
0x102 | SYS_JOIN | fiber_id | 0 | Wait for fiber to exit |
0x500 | SYS_CHECKPOINT | blob_ptr, blob_len | 0 or -1 | Save fiber checkpoint (Phase 6.4) |
Three time surfaces — pick the right one
SYS_GET_TIME / SYS_NANOSLEEP expose the boot clock (nanoseconds since kernel start) for scheduling and timeout use. They are not the application time contract.
Nexus exposes three time surfaces; the Trap ABI is the lowest:
| Surface | Type | Unit | Use case |
|---|---|---|---|
| Trap ABI (this page) | u64 boot_ns | nanoseconds since boot | Kernel scheduling, timeouts, fiber quantum accounting |
| STP / Chronology (SPEC-106) | StpTimestamp (i64) | TAI nanoseconds since Nexus Epoch (JD 2460000.0) | Application time, event timestamps, wire encoding (UTCP TLV 0x0106), package metadata, STL events |
| STP Duration (SPEC-106) | StpDuration (i64) | nanoseconds | General durations, intervals, latency |
| STP Precise Duration (SPEC-106 §2.3) | StpDuration128 (i128) | attoseconds | Scientific measurements, RF, space, physics — sub-nanosecond precision without overflow |
| NST SovereignTick (SPEC-105) | 128-bit {epoch_ns, entropy_hash} | nanoseconds + tamper-evidence hash | Space missions, distributed consensus, causal ordering |
Why nanoseconds, not attoseconds, as the canonical timestamp unit? A signed 64-bit nanosecond counter covers ±292 years — enough for any terrestrial or near-space mission. An attosecond counter overflows the same 64 bits in ~9.2 seconds, which is unusable as a global timestamp. Sub-nanosecond precision is reserved for durations (where the range requirement is bounded) via StpDuration128, not for timestamps.
The Chronology and NST surfaces are accessed via their respective userland services over Storage Channels, not via Trap ABI. This is consistent with the Kernel Protocol doctrine: the kernel exposes a minimal entry surface; rich semantics live in userland services that speak the protocol.
LWF Operations (Sovereign Networking)
| Nr | Name | Args | Returns | Description |
|---|---|---|---|---|
0x700 | SYS_LWF_RECV | buf, maxlen | frame_len or 0 | Pop LWF frame from chan_lwf_rx (non-blocking) |
0x701 | SYS_LWF_SEND | buf, len | len or 0 | Push LWF frame to chan_lwf_tx |
0x702 | SYS_UTCP_RECV | buf, maxlen | frame_len or 0 | Pop UTCP frame from chan_utcp_rx |
0x703 | SYS_UTCP_SEND | buf, len | len or 0 | Push UTCP frame to chan_utcp_tx |
Capability gating: LWF_RECV requires capability 0x600 (PERM_READ). LWF_SEND requires 0x601 (PERM_WRITE). Capabilities are granted via BKDL manifest embedded in the capsule ELF.
User buffer bounce: For fibers with per-fiber address spaces (Cell 1+), the kernel uses user_copy_in/user_copy_out to translate between per-fiber VA and kernel PA. The bounce temporarily activates the fiber's worker SATP with interrupts disabled, copies the data, then restores the kernel identity map.
Native path
For new applications, network I/O should be expressed as a Flow over a typed channel rather than the explicit LWF_SEND/LWF_RECV trap pair. The traps remain available for the POSIX bridge and low-level diagnostics.
AEAD Cryptography (M5.2 Membrane-Capsule Bridge)
| Nr | Name | Args | Returns | Description |
|---|---|---|---|---|
0x800 | SYS_AEAD_SEAL | args_ptr, args_len | sealed_len or 0 | XChaCha20-Poly1305 encrypt |
0x801 | SYS_AEAD_UNSEAL | args_ptr, args_len | plaintext_len or 0 | XChaCha20-Poly1305 decrypt |
Backend: Monocypher crypto_aead_lock/crypto_aead_unlock (C reference implementation).
SYS_AEAD_SEAL (0x800)
Encrypts plaintext with XChaCha20-Poly1305. Output format: [24-byte nonce][ciphertext][16-byte Poly1305 tag].
Args struct (56 bytes at a0, a1 = struct size):
| Offset | Size | Field | Description |
|---|---|---|---|
| 0 | 32 | key | 256-bit symmetric key |
| 32 | 8 | plaintext_ptr | Pointer to plaintext in user memory |
| 40 | 8 | plaintext_len | Plaintext length (max 2000 bytes) |
| 48 | 8 | ad_ptr | Pointer to additional authenticated data |
| 56 | 8 | ad_len | AD length (max 256 bytes) |
| 64 | 8 | out_ptr | Pointer to output buffer in user memory |
| 72 | 8 | out_len | Output buffer max size |
Returns: Sealed length (plaintext_len + 40) on success, 0 on error.
SYS_AEAD_UNSEAL (0x801)
Decrypts and authenticates XChaCha20-Poly1305 sealed payload. Rejects tampered data.
Args struct (same layout as SEAL, with sealed data instead of plaintext):
| Offset | Size | Field | Description |
|---|---|---|---|
| 0 | 32 | key | 256-bit symmetric key |
| 32 | 8 | sealed_ptr | Pointer to sealed data [nonce][ct][tag] |
| 40 | 8 | sealed_len | Sealed length (must be >= 40) |
| 48 | 8 | ad_ptr | Pointer to AD (must match what was used for sealing) |
| 56 | 8 | ad_len | AD length |
| 64 | 8 | out_ptr | Pointer to plaintext output buffer |
| 72 | 8 | out_len | Output buffer max size |
Returns: Plaintext length (sealed_len - 40) on success, 0 on authentication failure.
Pledge Enforcement
Every syscall is checked against the fiber's pledge mask before dispatch. Pledges can only be narrowed (SYS_PLEDGE with a mask that's a subset of the current mask). Attempting to widen returns -1.
| Pledge Bit | Name | Syscalls Gated |
|---|---|---|
| 0x01 | PLEDGE_STDIO | SYS_READ (fd=0), SYS_WRITE (fd=1,2) |
| 0x02 | PLEDGE_RPATH | SYS_OPEN (read), SYS_READ (fd>=3) |
| 0x04 | PLEDGE_WPATH | SYS_OPEN (write), SYS_WRITE (fd>=3) |
| 0x08 | PLEDGE_INET | SYS_LWF_, SYS_UTCP_, SYS_AEAD_* |
| 0x10 | PLEDGE_EXEC | SYS_SPAWN |