Userspace Runtime
The userspace runtime owns the repeated mechanics that every service needs: bootstrap validation, heap initialization, typed capability lookup, ring submission, completion matching, application exception decoding, and handle lifetime.
Status: Partially implemented. capos-rt provides a no_std entry ABI, fixed heap, typed CapSet lookup, a
single-owner ring client, typed Console and ProcessSpawner clients, result-cap
adoption, and release-on-drop for owned handles. Full generated bindings,
promise pipelining, language runtimes, and broad transport semantics remain
future work.
Current Behavior
Runtime-owned _start receives (ring_addr, pid, capset_addr), initializes a
fixed heap, validates the ring address, reads the read-only CapSet page, installs
an emergency Console panic path when available, calls capos_rt_main(runtime),
and exits with the returned code.
The Runtime lends out at most one RuntimeRingClient at a time. The client
wraps the raw ring page, keeps request buffers alive until completions are
matched, handles out-of-order completions, packs copy-transfer descriptors, and
parses result-cap records. Owned runtime handles queue CAP_OP_RELEASE when the
last local reference is dropped; the release queue flushes when a ring client is
borrowed or dropped, or when code calls Runtime::flush_releases() explicitly.
Promise placeholders are currently bookkeeping only; their future SQE
coordinates map AnswerId.raw() to pipeline_dep and a result-cap record index
to pipeline_field.
Design
The runtime separates non-owning bootstrap references from owned local handles.
CapSet entries produce typed Capability<T> values only when the interface ID
matches the requested type. Result-cap adoption performs the same interface
check before producing OwnedCapability<T>.
Typed clients are thin wrappers over the ring client. They encode Cap’n Proto
params, submit CALL SQEs, wait for a matching CQE, decode transport errors, and
decode kernel-produced CapException payloads into client errors.
Future generated clients should preserve this split: transport lifetime and completion matching belong in the runtime, while interface-specific encoding belongs in generated or handwritten client wrappers.
Invariants
ring_addrmust equalRING_VADDR; runtime bootstrap rejects any other address.- The CapSet header magic/version must validate before lookup.
- CapSet handles are non-owning unless explicitly adopted.
- Only one runtime ring client may be live at a time for a process.
- Request params and result buffers must outlive their matching CQE.
- A result cap can be consumed only once and only with the expected interface ID.
- Promise placeholders must map to sideband result-cap record indexes, not schema field paths.
- Dropping the final owned handle queues exactly one local
CAP_OP_RELEASE;Runtime::flush_releases()forces queued releases and reports rejected kernel release results. - Release flushing treats stale or already-removed caps as non-fatal cleanup.
Code Map
capos-rt/src/entry.rs-_start,Runtime, bootstrap validation, single-owner ring token, release queue flushing.capos-rt/src/alloc.rs- fixed userspace heap initialization.capos-rt/src/capset.rs- typed CapSet lookup wrappers.capos-rt/src/ring.rs- ring client, pending calls, completion matching, copy-transfer packing, result-cap parsing.capos-rt/src/client.rs- Console, ProcessSpawner, ProcessHandle clients and exception decoding.capos-rt/src/lib.rs- typed capability marker types and owned handle reference counting.capos-rt/src/panic.rs- emergency Console output path.init/src/main.rsandcapos-rt/src/bin/smoke.rs- current runtime users.
Validation
make capos-rt-checkbuilds the runtime smoke binary with userspace relocation constraints.make runvalidates runtime entry, typed Console calls, exception decoding, owned handle release, result-cap parsing through IPC, and clean process exit.make run-spawnvalidatesProcessSpawnerClient,ProcessHandleClient, result-cap adoption, and release behavior under init spawning.cd capos-rt && cargo test --lib --target x86_64-unknown-linux-gnucovers host-testable runtime invariants when run explicitly.
Open Work
- Add generated client bindings after the schema surface stabilizes.
- Implement promise/answer transport semantics beyond current placeholders.
- Define release behavior for queued handles when a process exits before the release queue flushes.