runtime: consolidate the device-manager hello into runtime.device_manager
Every supervised driver owes the device manager a hello at startup, and the retry-lookup-call-check for it had been copied into five drivers: usb.helloManager (misfiled in the USB client) plus hand-rolled twins in display, virtio-gpu, pci-bus, and usb-xhci-bus. Extract it once as a runtime client, runtime.device_manager.hello(role, device_id) ?Handle — returns the manager endpoint (bus drivers keep it to report children through), null when there is no manager or it refused the handshake, and logs the outcome itself so each call site is one line. Also correct two roles while collapsing their calls: virtio-gpu and the display driver each claim one PCI function and report no children, so they are Role.device, not Role.bus. The manager ignores role today, so this is cosmetic, but it matches the protocol's own definition (bus = reports children via child_added). Behavior-preserving otherwise: pci-bus and usb-xhci-bus move their hello logging from raw serial writes to std.log, which the kernel renders with the same "<path>: " prefix, so driver-restart still matches "usb-xhci-bus: hello acknowledged". zig build clean; 8 QEMU cases pass (driver-restart, pci-scan, usb-hid, usb-storage, virtio-gpu, display-reattach, device-list, device-manager).
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
//! Client side of the device-manager protocol (docs/device-manager.md): the
|
||||
//! calls a supervised driver makes *to* the manager, as opposed to
|
||||
//! `device-manager-protocol.zig`, which is the wire contract both sides share.
|
||||
//!
|
||||
//! Today this is just the hello handshake every spawned driver owes. The
|
||||
//! manager arms a hello deadline when it spawns a driver
|
||||
//! (system/services/device-manager/device-manager.zig): a driver that stays
|
||||
//! silent past it is assumed wedged before `main` and stopped, so every driver
|
||||
//! calls `hello` early in its startup. The retry-lookup-call-check this used to
|
||||
//! be — copied byte-for-byte into each bus and class driver — lives here once.
|
||||
|
||||
const std = @import("std");
|
||||
const ipc = @import("ipc.zig");
|
||||
const system = @import("system.zig");
|
||||
const protocol = @import("device-manager-protocol");
|
||||
|
||||
/// What kind of driver is announcing itself (a bus that reports children, or a
|
||||
/// leaf device). Re-exported so callers name it without importing the protocol.
|
||||
pub const Role = protocol.Role;
|
||||
|
||||
/// Endpoint lookups while the manager is still registering, and the pause
|
||||
/// between them: 100 x 20 ms = ~2 s, comfortably inside the manager's 3 s hello
|
||||
/// deadline (device-manager.zig `hello_deadline_ms`).
|
||||
const lookup_attempts: u32 = 100;
|
||||
const lookup_pause_ms: u64 = 20;
|
||||
|
||||
/// Say hello to the device manager and return its endpoint, or null if there is
|
||||
/// no manager (best-effort standalone bring-up) or it refused the handshake
|
||||
/// (version mismatch, unknown sender). Bus drivers keep the returned handle to
|
||||
/// report children through; a driver that runs fine unsupervised discards it
|
||||
/// with `_ =`, and a driver that requires supervision bails on null.
|
||||
///
|
||||
/// Logs the outcome itself (attribution is the kernel's, via the process's
|
||||
/// binary path), so callers stay a single line.
|
||||
pub fn hello(role: Role, device_id: u64) ?ipc.Handle {
|
||||
var attempts: u32 = 0;
|
||||
const manager = while (attempts < lookup_attempts) : (attempts += 1) {
|
||||
if (ipc.lookup(.device_manager)) |handle| break handle;
|
||||
system.sleep(lookup_pause_ms);
|
||||
} else {
|
||||
std.log.info("no device manager to hello", .{});
|
||||
return null;
|
||||
};
|
||||
|
||||
const message = protocol.Hello{ .role = @intFromEnum(role), .device_id = device_id };
|
||||
var reply: [protocol.reply_size]u8 = undefined;
|
||||
const length = ipc.call(manager, std.mem.asBytes(&message), &reply) catch {
|
||||
std.log.info("hello call failed", .{});
|
||||
return null;
|
||||
};
|
||||
if (length < protocol.reply_size or
|
||||
std.mem.bytesToValue(protocol.HelloReply, reply[0..protocol.reply_size]).status != 0)
|
||||
{
|
||||
std.log.info("hello refused", .{});
|
||||
return null;
|
||||
}
|
||||
std.log.info("hello acknowledged", .{});
|
||||
return manager;
|
||||
}
|
||||
Reference in New Issue
Block a user