library: five protocols speak the envelope
The folded header stops being a rule in a document and becomes the layout on the wire. Verbs number from sixteen, leaving describe, enumerate, subscribe and unsubscribe reserved and answered the same way by every provider — none of them writes a line to do it. What each protocol used to carry in a field of its own now travels in the header: a vfs node and a display layer are the packet's target, and a reply opens with a status the envelope stamps rather than one each protocol spelled for itself. Display gains the most. One forty-byte request had served eleven verbs, so attach_scanout smuggled stride through x, refresh through y and format through colour, and every coordinate crossed as a bitcast. Per-operation structs end all three: the fields have their own names and their own signs, and the tile payload grows to 224 bytes because the prefix shrank. Scanout loses a message maximum of 64 it had no business declaring — it answers calls, and the floor for a call is 256 — and virtio-gpu stops hard-coding that number at its harness. Two changes are semantic rather than notational. A directory now ends at an entry with no name, because the fixed part of a reply always travels and a zero-length reply no longer exists to mean anything. And input joins the service harness, the last loop in the tree that answered no ping and heard no terminate; its subscriber table, its pruning and its fan-out are the same code, and a shutdown now asks it to stop instead of killing it. A new conformance case reads the registry's own listing and asks every protocol it finds for its name, its version and its verb count, then offers a verb nobody defines and requires -ENOSYS — the envelope's promise, checked against providers rather than against itself. What it cannot reach in that boot it names on the serial line instead of passing quietly. Suite 110/110.
This commit is contained in:
@@ -250,6 +250,8 @@ pub fn run(case: []const u8, boot_information: *const BootInformation) void {
|
||||
protocolRegistryTest(boot_information);
|
||||
} else if (eql(case, "protocol-denied")) {
|
||||
protocolDeniedTest(boot_information);
|
||||
} else if (eql(case, "protocol-conformance")) {
|
||||
protocolConformanceTest(boot_information);
|
||||
} else if (eql(case, "reboot")) {
|
||||
rebootTest();
|
||||
} else {
|
||||
@@ -3898,6 +3900,68 @@ fn protocolDeniedTest(boot_information: *const BootInformation) void {
|
||||
result();
|
||||
}
|
||||
|
||||
/// P4a — the reserved verbs, asked of live providers
|
||||
/// (docs/security-track-plan.md P4a; docs/os-development/protocol-namespace.md).
|
||||
/// Every protocol rebased onto `envelope.Define` gets `describe` answered from its
|
||||
/// specification and `-ENOSYS` for a verb it does not define, without its provider
|
||||
/// implementing either — this case is where that stops being a host unit test of
|
||||
/// the generated dispatch and becomes an observation of real providers over real
|
||||
/// IPC.
|
||||
///
|
||||
/// The scenario is the assertion's scaffolding, the same shape `protocol-denied`
|
||||
/// uses: `/protocol` (init in its registry role) plus the providers the fixture is
|
||||
/// granted to reach — the **input service** and the **compositor**, two protocols
|
||||
/// of different sizes and different verb counts, so "uniform" means something. The
|
||||
/// fixture reads `/protocol`'s own listing rather than a list compiled into it, so
|
||||
/// what it checks is what this boot actually bound; the three other P4a protocols
|
||||
/// (vfs, block, scanout) sit behind hardware chains this scenario deliberately does
|
||||
/// not boot, and the fixture names them on serial as unchecked rather than passing
|
||||
/// over them.
|
||||
///
|
||||
/// The fixture's `protocol-conformance: ok` is the marker; each contract it checks
|
||||
/// prints its own line, which the harness's ordered regex reads.
|
||||
fn protocolConformanceTest(boot_information: *const BootInformation) void {
|
||||
log("DANOS-TEST-BEGIN: protocol-conformance\n", .{});
|
||||
if (boot_information.initial_ramdisk_len == 0) {
|
||||
check("bootloader handed over an initial_ramdisk", false);
|
||||
result();
|
||||
return;
|
||||
}
|
||||
const image = @as([*]const u8, @ptrFromInt(boot_handoff.physicalToVirtual(boot_information.initial_ramdisk_base)))[0..boot_information.initial_ramdisk_len];
|
||||
const rd = initial_ramdisk.Reader.init(image) orelse {
|
||||
check("initial_ramdisk image is valid", false);
|
||||
result();
|
||||
return;
|
||||
};
|
||||
|
||||
process.setInitialRamdisk(image);
|
||||
check("registry (init) spawned", spawnRegistry(rd));
|
||||
// The two providers under test. Neither needs hardware beyond the framebuffer
|
||||
// the kernel already seeded: input binds /protocol/input and waits for
|
||||
// subscribers, and the compositor binds /protocol/display and composes into
|
||||
// that framebuffer (the display-service scenario boots it exactly this way).
|
||||
check("input service spawned", spawnNamed(rd, "input"));
|
||||
check("display service spawned", spawnNamed(rd, "display"));
|
||||
check("protocol-conformance-test spawned", spawnNamedWithArg(rd, "protocol-conformance-test", "run"));
|
||||
|
||||
const pass_marker = "protocol-conformance: ok";
|
||||
const fail_marker = "protocol-conformance: FAIL";
|
||||
scheduler.setPriority(1);
|
||||
const deadline = architecture.millis() + 20000;
|
||||
var saw_pass = false;
|
||||
var saw_fail = false;
|
||||
while (architecture.millis() < deadline and !saw_pass and !saw_fail) {
|
||||
if (bufferHas(pass_marker)) saw_pass = true;
|
||||
if (bufferHas(fail_marker)) saw_fail = true;
|
||||
scheduler.yield();
|
||||
}
|
||||
scheduler.setPriority(4);
|
||||
|
||||
check("no provider failed the reserved-verb contract", !saw_fail);
|
||||
check("the fixture conformance-checked every provider its scenario boots", saw_pass);
|
||||
result();
|
||||
}
|
||||
|
||||
fn deviceManagerTest(boot_information: *const BootInformation) void {
|
||||
log("DANOS-TEST-BEGIN: device-manager\n", .{});
|
||||
if (boot_information.initial_ramdisk_len == 0) {
|
||||
|
||||
Reference in New Issue
Block a user