Kore ABI
Service protocols
How Kore services talk across a process boundary: payloads on shared rings, authority by rendezvous, and wire records that admit any bit pattern.
Source: svc.rsPayloads on rings, authority by rendezvous
Kore's system services are ordinary user-space tasks, and their protocols follow one rule: payloads ride rings; authority rides rendezvous; nothing else exists.
- Each client and service pair shares one leased window holding a request ring and a reply ring, each single-producer, single-consumer.
- A channel beside the window carries only doorbell notices ("look at your ring") and capability transfers.
- A record on a ring is data. It names capabilities by arena slot index, ones the peer already holds or was delivered, and never carries one.
- A reply that grants capabilities says only how many to collect. The capabilities themselves land in the client's receive posts, pinned in advance.
An in-memory enum can't cross a process boundary, so the wire form is the contract and the enum is the convenience. Each service keeps its Request and Response enums in its own crate, with codecs between enum and wire; the wire structs live in kore-abi's svc module beside every other frozen layout, so the two sides of a ring can't drift.
Layout doctrine
Every service wire record follows the same rules as the boot block:
#[repr(C)], little-endian, readable at any byte offset, and size-pinned by assertion.- No parser. Every field admits any bit pattern, so a record read off a shared ring, whose peer is untrusted, can be reinterpreted in place without undefined behavior.
- Validation belongs to the codec: an out-of-vocabulary discriminant decodes to
None, failing closed. - Discriminants are 1-based, so an all-zero, never-written record is invalid rather than "the first verb".
- Changes after the freeze are additive only: new op and tag values, and meanings for reserved bytes.
kore::abi::svc defines the wire for the memory, monitor, swap, block, device, time, exec, image, input, hypervisor, accelerator, network, surface and filesystem services. Which of them a program can reach depends entirely on the endpoints its founder handed it.
The loader wire
image (IMAGE_ABI = 3) describes how code gets into a task: ImageName, a 64-byte name; ModuleDescriptor, with up to 9 segments and 8 dependencies as image-relative offsets plus a TLS shape; the parent-written LdBlock on the boot page; and a passive module page of up to 16 records for debuggers and late linking.
Loading happens in two phases. The parent's spawn session creates the address space, delegates pages and founds the task. Then a startup-only linker stub inside the child relocates the image, acquires its libraries through a generation-bound loader face, seals RELRO and sets up TLS before main. A name is never launch authority: ordinary callers launch through affine, generation-bound executable endpoints.
Packages
A .pkg manifest (PACKAGE_ABI = 1) lists up to 48 members, apps or libraries, projected into the filesystem as link edges under apps/ and libs/. A manifest is data only: a member runs only if its image carries the executable stamp and the exec service binds it.
Guest rings
The hypervisor's virtual machine monitor is a service too. Each virtual CPU has one 4096-byte page holding two single-producer rings of 512-byte records: an exit ring from the kernel to the monitor, and a control ring back.
| Ring | Kinds |
|---|---|
| Exit | MMIO, PORT_IO, CPUID, MSR, HLT, STAGE_FAULT, ARCH, RETIRED, OP_REFUSED |
| Control | WRITE_STATE, INJECT, RESUME, RETIRE |
A 40-word register image travels with each exit, with an optional decode-assist tail carrying the instruction bytes or the access. Only x86-64 register positions are defined in this export; the AArch64 and RISC-V guest backends aren't implemented yet. A virtual CPU is founded with DERIVE_KIND_GUEST_FOUND.
Pointer input
Pointer devices report on the 16-byte input ring in frames: BEGIN, typed records (axis, resolution, contact, attribute, motion, scroll, buttons, scan time, reset), then END, which repeats the sequence number and counts the frame's records. Frames are never interleaved and never applied as a prefix: an unknown kind, a duplicate field, truncation or overflow invalidates the whole frame.