Kore ABI
Sessions: the authority plane
How capability authority moves on Kore: a batch of operations committed as one transaction in one kernel crossing, all or nothing.
Source: session.rsThree verbs
The whole authority vocabulary is three op-codes:
| Code | Op | Meaning |
|---|---|---|
| 0 | Derive | Carve an attenuated child capability into a result slot |
| 1 | Revoke | Retire a capability; its subtree dies by closure at commit |
| 2 | Rendezvous | Transfer a capability over a channel endpoint |
Code 3 is retired and refused; it will never be reused. There is no read, write, map or call primitive. Mapping memory, spawning a task, killing one, programming an interrupt and notifying a peer are each one of the three, with a flavor selected by the operation's kind byte and the kind of resource it acts on.
A session
A session is a batch of operations the kernel commits as one transaction, in one trap:
- Validate. Every operation is checked against the caller's arena: bounds, vacancy, resource kind, rights and the holder stamp.
- Prepare. The batch is folded without side effects.
- Commit. All of it applies, or none of it does, with a single revocation pass for the whole batch.
- Write back. Results land in the caller's arena slots, and the return word reports the status and, on refusal, the index of the operation that failed.
Operations can name the results of earlier operations in the same session by slot, so a session reads like straight-line code over slots. A forward reference is Malformed. Building a process — its address space, pages and capabilities — is one session, which ends by founding it. A founded process is dormant; starting it is a second session, a TASK_START on the returned handle.
Commits are optimistic: two sessions whose capability footprints don't overlap commit in parallel, and a lost race reports Conflict, which means retry.
The descriptor
All fields are little-endian and readable at any byte offset.
SessionHeader 8 bytes
count u16 @0 number of operations
abi u16 @2 DESCRIPTOR_ABI (4)
flags u16 @4 parking flags
reserved u16 @6 must be zero
InvocationWire[count] 16 bytes each
op u16 @0 Derive, Revoke or Rendezvous
requested u8 @2 rights requested for the result
kind u8 @3 resource kind, or a flavor selector
subject u32 @4 slot of the capability acted on
result u32 @8 slot the result lands in
arg u32 @12 offset into the argument region, or u32::MAX for none
Argument region follows the operations
[park block, if flags request one] then each operation's payloadThe kind byte disambiguates op × kind. Zero means unspecified, values in the resource-kind band name the kind to produce, and high values (from 0xdd) select a flavor. An unknown flavor byte on a derive is refused, never run as a plain derive.
Derive flavors
Most of the system's verbs are derive flavors. The full roster, with byte values and argument structs, is in session.rs; by purpose:
| Purpose | Flavors and payloads |
|---|---|
| Memory | LeaseReq (carve a lease from a physical region), ShareReq (map a lease into an address space), VIEW_MAP, OWNED_MAP, PROTECT (can only clear permissions), ARENA_EXTEND, SUPPLY_RELEASE |
| Tasks | Founding (kind = Task on a staged address space, with FoundReq), TASK_START, TASK_EXIT, TASK_JOIN, TASK_NAME, TASK_IDENTITY, PROCESS_DRAIN, SET_TP |
| Devices | BarReq (claim a register window), DeviceShareReq (map DMA into the device's IOMMU), DEVICE_ACTIVATE, DEVICE_QUIESCE, DEVICE_RECORD, inventory and claim flavors |
| Interrupts | IrqReq (MSI or MSI-X), IRQ_ROUTE_MSIX (strict MSI-X), IRQ_ROUTE_LINE (the firmware INTx line) |
| Crashes | CRASH_BIND, CRASH_READ, PANIC_REPORT |
| Virtualization | GUEST_FOUND, GuestShareReq |
Some flavors are effects: they mint nothing, and their result slot stays vacant or receives a bind-inert report. A few effects apply after the capability fold commits, because hardware can refuse at that point (DEVICE_ACTIVATE, DEVICE_QUIESCE, ARENA_EXTEND); they must stand alone in their session. A spawn session must end with its founding run.
Revoke flavors
| Value | Flavor | Effect |
|---|---|---|
| 0 | Plain | Retire the capability; its subtree dies by closure |
| 1 | PAGED | Lessor eviction, leaving paged-out markers |
| 2 | UNMAP | Yield the bare physical extent into the result |
| 3 | RETURN | Lessor take-back, reporting the returned window |
| 4 | UNSHARE | Exactly unshare one leased region |
| 5 | EXEC | Turn a writable lease executable, removing every writable alias |
| 6 | UNSHARE_IOVA | Unshare a peer device mapping |
| 7 | EXEC_RETURN | Turn an executable lease writable again, for JIT reuse |
| 8 | UNSHARE_IOVA_LIVE | Unshare a device mapping while keeping bus mastering open |
EXEC and EXEC_RETURN are the only ways memory changes between writable and executable, which is how Kore keeps W^X above the page tables.
Rendezvous
Channels have two ends, ChanSend and ChanRecv:
- A rendezvous on a receive end posts a landing slot for the next transfer. An optional
RecvPolicyReqtypes the post: the kind and minimum rights it will accept. - A rendezvous on a send end re-derives the capability in its
resultslot into the peer's posted slot, with the rights inrequested. Sending requiresDERIVEon the presented capability. The receiver's copy is re-stamped to the receiver as holder; the sender's bytes are never shared. - Sending with no posted peer refuses the whole session with
WouldBlock, which means it did not commit.
A send can instead carry a NoticeReq (a cookie and a payload): a bind-inert doorbell notice that needs only ACCESS on the send end. RENDEZVOUS_KIND_REQUEST_KICK (0xff) is the argument-free service-request kick, and RENDEZVOUS_KIND_EXACT_MOVE (0xfe) moves an affine capability keeping its kind, rights, lineage and tag.
Status codes
| Code | Status | Meaning |
|---|---|---|
| 0 | Ok | Committed |
| 1 | Denied | Not permitted |
| 2 | Forged | Bad stamp, or presented by the wrong holder |
| 3 | Revoked | The capability or an ancestor has been retired |
| 4 | Conflict | Lost an optimistic commit race: retry |
| 5 | Malformed | Bad slot, forward reference or over-length descriptor |
| 6 | WouldBlock | Did not commit: re-stage and retry |
| 7 | Deadline | A park's deadline passed |
| 8 | Irq | A park ended on an interrupt |
| 9 | Exited | A joined task exited |
| 10 | AltDelivery | A park ended on the alternate post |
| 11 | Unfounded | Committed, but the terminal founding couldn't be assembled: never replay |
| 12–17 | FabricRoute* | Memory-fabric route refusals |
Faults are reported coarsely by design: Forged doesn't say which check failed.
Parking
A session can park its thread after it commits. The header's flags pick what wakes it:
| Flag | Wakes on |
|---|---|
WAIT_DELIVERY (1 << 0) | A capability or notice delivered to a posted slot |
WAIT_IRQ (1 << 1) | An interrupt on a held route |
WAIT_SLEEP (1 << 2) | An absolute monotonic deadline |
WAIT_TASK (1 << 3) | A joined task's exit |
WAIT_DELIVERY_ALT (1 << 4) | Delivery to an alternate post |
WAIT_IRQ_SELECTED (1 << 5) | An interrupt on a selected route |
Unknown bits are Malformed. When several conditions are armed, the first to fire wins and sets the status. The park block sits at the front of the argument region: ParkReq entries, then SleepReq (deadline in nanoseconds) and IrqParkReq as selected.
Limits
| Limit | Value |
|---|---|
Operations per session (MAX_INVOCATIONS) | 107 |
Task foundings per session (MAX_SESSION_FOUNDS) | 12 |
Capabilities delivered per founding (MAX_FOUND_DELIVERIES) | 78 |
| Maximum descriptor | 8160 bytes |
Derivation depth (MAX_DEPTH) | 16 |