prometeu-runtime/docs/runtime/specs/16-host-abi-and-syscalls.md
2026-03-24 13:40:51 +00:00

5.7 KiB

Host ABI and Syscalls

Domain: host ABI structure Function: normative

This chapter defines the structural ABI between the PVM and the host environment.

It focuses on:

  • syscall identity;
  • load-time resolution;
  • instruction-level call semantics;
  • metadata shape;
  • argument and return-slot contract.

Operational policies such as capabilities, fault classes, determinism, GC interaction, budgeting, and blocking are split into a companion chapter.

1 Design Principles

The syscall ABI follows these rules:

  1. Stack-based ABI: arguments and return values are passed through VM slots.
  2. Canonical identity: host services are named by stable (module, name, version).
  3. Load-time resolution: symbolic host bindings are resolved before execution.
  4. Metadata-driven execution: arity and result shape come from syscall metadata.
  5. Not first-class: syscalls are callable but not ordinary function values.

2 Canonical Syscall Identity

Syscalls are identified by a canonical triple:

(module, name, version)

Example:

("gfx", "present", 1)
("audio", "play", 2)

This identity is:

  • language-independent;
  • toolchain-stable;
  • used for linking and capability gating.

Input queries are VM-owned intrinsic calls in v1 and are outside the syscall identity space.

3 Syscall Resolution

The host maintains a registry:

(module, name, version) -> syscall_id

At load time:

  1. the cartridge declares required syscalls by canonical identity;
  2. bytecode encodes host-backed call sites as HOSTCALL <sysc_index>;
  3. the loader validates and resolves those identities;
  4. the loader rewrites HOSTCALL <sysc_index> into SYSCALL <id>;
  5. the executable image uses only numeric syscall ids at runtime.

Raw SYSCALL <id> is not valid in a PBX pre-load artifact and must be rejected there.

4 Syscall Instruction Semantics

Pre-load artifact form:

HOSTCALL <sysc_index>

Final executable form:

SYSCALL <id>

Where:

  • <sysc_index> indexes the program-declared syscall table;
  • <id> is the final numeric host syscall id.

Execution steps:

  1. the VM looks up syscall metadata by <id>;
  2. the VM ensures the argument contract is satisfiable;
  3. the syscall executes in the host environment;
  4. the syscall produces exactly the declared ret_slots.

5 Syscall Metadata Table

Each syscall is defined by metadata.

Conceptual structure:

SyscallMeta {
    id: u32
    module: string
    name: string
    version: u16
    arg_slots: u8
    ret_slots: u8
    capability: CapabilityId
    may_allocate: bool
    cost_hint: u32
}

Fields:

Field Description
id Unique numeric syscall identifier
module Canonical module name
name Canonical syscall name
version ABI version of the syscall
arg_slots Number of input stack slots
ret_slots Number of return stack slots
capability Required capability
may_allocate Whether the syscall may allocate VM heap objects
cost_hint Expected cycle cost

The loader uses this table to resolve identities and validate declared ABI shape.

6 Arguments and Return Values

Syscalls use the same slot-oriented argument/return philosophy as ordinary calls.

Argument passing

Arguments are pushed before the syscall.

Example:

push a
push b
SYSCALL X

Return values

After execution, the syscall leaves exactly ret_slots values on the stack.

Composite results use multiple stack slots rather than implicit hidden structures.

Return shape must also follow the operational policy in 16a-syscall-policies.md:

  • operations with observable operational failure paths should expose an explicit status:int return;
  • operations with no real operational error path may remain void (ret_slots = 0);
  • stack shape remains strict in both cases and must match syscall metadata exactly.

MEMCARD game surface (mem, v1)

The game memcard profile uses module mem with status-first return shapes. mem is a domain layer backed by runtime fs (it is not a separate storage backend).

Canonical operations in v1 are:

  • mem.slot_count() -> (status, count)
  • mem.slot_stat(slot) -> (status, state, used_bytes, generation, checksum)
  • mem.slot_read(slot, offset, max_bytes) -> (status, payload_hex, bytes_read)
  • mem.slot_write(slot, offset, payload_hex) -> (status, bytes_written)
  • mem.slot_commit(slot) -> status
  • mem.slot_clear(slot) -> status

Semantics and domain status catalog are defined by 08-save-memory-and-memcard.md.

7 Syscalls as Callable Entities (Not First-Class)

Syscalls behave like call sites, not like first-class guest values.

This means:

  • syscalls can be invoked;
  • syscalls cannot be stored in variables;
  • syscalls cannot be passed as function values;
  • syscalls cannot be returned as closures.

Only user-defined functions and closures are first-class.

8 Relationship to Other Specs