M13: IPC capability passing
ipc_call and ipc_reply_wait grow a `send_cap` argument (r9) and a `received_cap` return (r8): an endpoint travels alongside a message, installed into the receiver's handle table. The transfer is a share, not a move — the endpoint's refcount is bumped and the sender keeps its handle. If the receiver's table is full the call fails -ENOSPC and the message is NOT delivered (a half-delivered capability is worse than a failed send); a bad handle fails -EBADF. Both directions carry a cap: a client's call hands one to the server (seen in the server's replyWait), and the server's reply hands one back (seen in the client's call return). This is the "open" primitive the driver model was blocked on: a bus driver mints a per-device endpoint and hands it to a class driver, giving it a private channel to one device without the 8-slot global name registry. Kernel: shareCapability in ipc-synchronous.zig at both copy points; new setSystemCallResult3 (r8, saved/restored by the syscall stub); Task gains ipc_send_cap / ipc_received_cap. Runtime: callCap + Reply, replyWait gains send_cap and Received.cap; plain call/replyWait delegate with no_cap. New abi.no_cap. New ipc-cap test (two kernel tasks exercise both directions, each verifying the endpoint it received is the same object shared, refcount bumped to 2). No class driver consumes callCap yet — it lands with the first one. Suite 37/37 plus host tests.
This commit is contained in:
+11
-1
@@ -132,6 +132,12 @@ If a class driver needs `mmio`, it has become an HCD and should be one.
|
||||
- **M11** — `irq_bind` / `irq_ack`. IRQ delivered as an IPC notification; mask before
|
||||
EOI; `irq_ack` is the unmask.
|
||||
- **M12** — `parent` in `DeviceDesc`, `device_register` with resource containment.
|
||||
- **M13** — capability passing. `ipc_call` / `ipc_reply_wait` grew a `send_cap` argument
|
||||
and a `received_cap` return (r8): an endpoint travels with a message, installed into
|
||||
the receiver's handle table (shared, refcount-bumped — a copy, not a move). A full
|
||||
table fails `-ENOSPC` and does not half-deliver. This is the "open" primitive — a bus
|
||||
driver mints a per-device endpoint and hands it to a class driver. The runtime exposes
|
||||
`callCap` and `replyWait(..., send_cap)`; no class driver consumes it yet.
|
||||
- **`system_spawn`** — a user-space supervisor starts a driver: `system_spawn(name)`
|
||||
loads a binary bundled in the initial-ramdisk as a fresh ring-3 process. This is what
|
||||
turned the device manager from "log the match" into "run the driver": the kernel now
|
||||
@@ -146,7 +152,11 @@ HCDs and class drivers do not work yet. Here is exactly why, and exactly what wo
|
||||
|
||||
# Proposed ABI
|
||||
|
||||
## M13 — capability passing, for class drivers
|
||||
## M13 — capability passing, for class drivers ✅ done
|
||||
|
||||
*Implemented as described below (see "What exists today"). The signatures landed
|
||||
verbatim: `send_cap` in r9, `received_cap` returned in r8, `-ENOSPC` on a full receiver
|
||||
table with no delivery. The rest of this section is the original design note.*
|
||||
|
||||
**The blocker.** A class driver has to reach *its* device. Today the only way to find
|
||||
an endpoint is the name registry: `ipc_register(service_id, h)` / `ipc_lookup(id)`,
|
||||
|
||||
Reference in New Issue
Block a user