library: the last three protocols speak the envelope
These were the awkward ones. Each began with an operation packed into a single byte — two of them with a version wedged in beside it — so there was no wrapping them: the layouts had to be rebuilt. The device manager's own enumerate and subscribe become the reserved verbs that mean the same thing everywhere, its replies lose three status structs the envelope already carries, and a device id becomes the packet's target. Power drops the version it repeated on every request, because describe is the handshake, and stops claiming a 64-byte ceiling it never needed for calls. USB moves a control transfer's data to the packet tail in both directions, which makes the status length the transferred length and retires a field that had been saying the same thing twice. The danger in this one was not the protocols but their readers. Init recognised a power button by two bytes at the head of a message, the ACPI service dispatched on the first byte, the xHCI driver read its operation with a raw integer load, and the HID drivers reinterpreted a report wholesale — none of which would have failed to compile once the layouts moved. They would simply have stopped: no shutdown on the power button, no reports from the keyboard. Every one of them now reads through the generated types, and the shutdown gate that answers only a subscriber is the same code it was. Two sizes were decided by measuring rather than assuming. The child-added message is both a request and the event broadcast to subscribers, and alignment rounds it to 48 bytes, which puts its packet exactly on the 64-byte push floor — a test pins that, because a field added carelessly would now overflow it. The interrupt report gives up eight bytes of inline room to make space for the header; the two drivers that produce reports send eight and four. Suite 110/110.
This commit is contained in:
@@ -12,15 +12,18 @@ pub fn build(b: *std.Build) void {
|
||||
.imports = &.{
|
||||
"block-protocol",
|
||||
"channel",
|
||||
"device-manager-protocol",
|
||||
"display-protocol",
|
||||
"envelope",
|
||||
"file-system",
|
||||
"input-protocol",
|
||||
"ipc",
|
||||
"logging",
|
||||
"power-protocol",
|
||||
"process",
|
||||
"scanout-protocol",
|
||||
"time",
|
||||
"usb-transfer-protocol",
|
||||
"vfs-protocol",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -24,31 +24,37 @@
|
||||
//! exactly the two contracts its scenario boots, and an ungranted name is absent
|
||||
//! for it like any other client's.
|
||||
//!
|
||||
//! **What it covers, and what it cannot — the honest list at P4a.** The scenario
|
||||
//! boots the registry, the input service, and the compositor, so `input` and
|
||||
//! `display` are checked end to end over real IPC. The other three protocols P4a
|
||||
//! rebased are not asked here, and the reason is the provider, not the protocol:
|
||||
//! **What it covers, and what it cannot — the honest list.** The scenario boots
|
||||
//! the registry, the input service, and the compositor, so `input` and `display`
|
||||
//! are checked end to end over real IPC. The other six contracts in the table
|
||||
//! are not asked here, and the reason is the provider, not the protocol:
|
||||
//!
|
||||
//! - `vfs` — the FAT server, which needs a mounted volume behind the whole USB
|
||||
//! storage chain (the `fat-mount` scenario);
|
||||
//! - `block` — the usb-storage driver, which the device manager spawns after
|
||||
//! enumerating an xHCI bus (the `usb-storage` scenario);
|
||||
//! - `scanout` — the virtio-gpu driver, which needs an emulated virtio-gpu the
|
||||
//! default harness does not attach (the `virtio-gpu` scenario).
|
||||
//! default harness does not attach (the `virtio-gpu` scenario);
|
||||
//! - `device-manager`, `power` and `usb-transfer` — the three P4b rebased. All
|
||||
//! three come with the device manager: it *is* the first, it spawns the
|
||||
//! discovery service that binds the second, and the xHCI driver it spawns
|
||||
//! binds the third. So booting a provider for any one of them means booting
|
||||
//! the whole driver tree here.
|
||||
//!
|
||||
//! Booting any of those chains here would buy conformance for a third and fourth
|
||||
//! provider at the price of a case that boots half the system to send two
|
||||
//! packets; their rebase is proven instead by the scenarios that already drive
|
||||
//! them. All three sit in the table below anyway, so if a future scenario binds
|
||||
//! one, this fixture checks it without being edited — and prints, every run, the
|
||||
//! ones it found no provider for.
|
||||
//! That is the reason this scenario stays at two providers rather than five or
|
||||
//! eight. It is not only the cost of booting half the system to send two
|
||||
//! packets: this fixture takes **one snapshot** of `/protocol` and checks what
|
||||
//! is in it, so a scenario whose bound set depends on how far a driver tree got
|
||||
//! by that instant would make the case's own summary a boot race. What proves
|
||||
//! the six instead is the scenarios that already drive them end to end —
|
||||
//! `fat-mount`, `usb-storage`, `virtio-gpu`, and for the P4b three the
|
||||
//! `device-list`, `driver-restart`, `pci-scan`, `usb-*`, `power-button` and
|
||||
//! `orderly-shutdown` cases, every one of which is a live conversation over
|
||||
//! these wires.
|
||||
//!
|
||||
//! **And the ones it must not ask.** `device-manager`, `power` and
|
||||
//! `usb-transfer` are still hand-numbered (P4b): to them, operation 0 is a verb
|
||||
//! of their own, not `describe`. So the table is not "every contract" but "every
|
||||
//! contract already built on `Define`" — anything listed that is not in it is
|
||||
//! reported as skipped by name, never silently. P4b adds three rows here and the
|
||||
//! coverage follows.
|
||||
//! All six sit in the table below regardless, so a scenario that binds one gets
|
||||
//! it conformance-checked without this file being edited — and every run prints,
|
||||
//! by name, the ones it found no provider for.
|
||||
//!
|
||||
//! The registry itself — PID 1 serving `/protocol` — is the one vfs backend
|
||||
//! deliberately NOT dispatched through the generated table (it reads a
|
||||
@@ -68,9 +74,12 @@ const logging = @import("logging");
|
||||
const process = @import("process");
|
||||
const time = @import("time");
|
||||
const block_protocol = @import("block-protocol");
|
||||
const device_manager_protocol = @import("device-manager-protocol");
|
||||
const display_protocol = @import("display-protocol");
|
||||
const input_protocol = @import("input-protocol");
|
||||
const power_protocol = @import("power-protocol");
|
||||
const scanout_protocol = @import("scanout-protocol");
|
||||
const usb_transfer_protocol = @import("usb-transfer-protocol");
|
||||
const vfs_protocol = @import("vfs-protocol");
|
||||
|
||||
// --- what conformance means, per contract -----------------------------------
|
||||
@@ -100,16 +109,23 @@ fn contractOf(comptime Protocol: type, required: bool) Contract {
|
||||
};
|
||||
}
|
||||
|
||||
/// The protocols built on `envelope.Define`, and nothing else. A name listed by
|
||||
/// `/protocol` that is absent from here is reported and left alone — see the
|
||||
/// header: asking a hand-numbered provider for operation 0 would name one of its
|
||||
/// own verbs.
|
||||
/// The protocols built on `envelope.Define`. A name listed by `/protocol` that
|
||||
/// is absent from here is reported and left alone rather than probed: a
|
||||
/// hand-numbered provider would read operation 0 as one of its own verbs, so
|
||||
/// asking it for `describe` would *do* something. Only `ps2-bus` is still in
|
||||
/// that state today.
|
||||
const contracts = [_]Contract{
|
||||
contractOf(input_protocol.Protocol, true), // the input fan-out service
|
||||
contractOf(display_protocol.Protocol, true), // the compositor
|
||||
contractOf(vfs_protocol.Protocol, false), // the FAT server — needs a volume
|
||||
contractOf(block_protocol.Protocol, false), // usb-storage — needs the xHCI chain
|
||||
contractOf(scanout_protocol.Protocol, false), // virtio-gpu — needs the device
|
||||
// The three P4b rebased. Each needs the device manager (and, for the last
|
||||
// two, what the device manager starts), which is more than this scenario
|
||||
// boots — see the header.
|
||||
contractOf(device_manager_protocol.Protocol, false),
|
||||
contractOf(power_protocol.Protocol, false), // the discovery service
|
||||
contractOf(usb_transfer_protocol.Protocol, false), // the xHCI bus driver
|
||||
};
|
||||
|
||||
/// A verb number no protocol in the system defines, and none plausibly will: far
|
||||
|
||||
Reference in New Issue
Block a user