runtime: std.log for every user binary — kernel-stamped attribution

library/runtime/log.zig wires std.log to the tagged ring: the root shim
installs std_options for every binary (programs may override), logFn
formats one line per record and emits it with its level via
debug_write — the payload no longer carries the process's name; the
kernel stamps identity structurally and the serial renderer prints the
'<binary path>: ' prefix, so the transcript keeps its shape.

Migrate every writeLine/logLine/log helper family (init, vfs, fat,
device-manager, acpi, pci-bus, ps2-bus x3, usb-hid x2, usb-storage,
usb-xhci-bus, virtio-gpu — 104 call sites) to std.log.info, dropping
the hand-written prefixes. A leveled record is a complete line by
contract (raw emissions may still build lines from pieces). Test
fixtures and the display/input services keep raw writes for now — their
ring records are attributed by the kernel regardless.

Harness regexes follow the renamed prefixes (usb-hid-keyboard,
discovery) and path-named restart lines.
This commit is contained in:
Daniel Samson
2026-07-21 15:39:51 +01:00
parent 9f18d8340e
commit f480c5d790
19 changed files with 172 additions and 193 deletions
+6 -11
View File
@@ -16,11 +16,6 @@ const protocol = runtime.device_manager_protocol;
const device = runtime.device;
const pci_class = @import("pci-class");
fn writeLine(comptime fmt: []const u8, arguments: anytype) void {
var line: [128]u8 = undefined;
_ = runtime.system.write(std.fmt.bufPrint(&line, fmt, arguments) catch return);
}
/// Log a discovered function with its (class / subclass / prog-IF) triple decoded
/// to human names — the boot-log breadcrumb that says *what* the hardware is, so
/// "class 0x01 (Mass Storage Controller) subclass 0x06 (Serial ATA Controller)
@@ -74,7 +69,7 @@ fn configWrite16(bus: u64, dev: u64, function: u64, offset: u64, value: u16) voi
fn initialise(endpoint: runtime.ipc.Handle) bool {
_ = endpoint;
if (!device.claim(bridge_id)) {
writeLine("/system/drivers/pci-bus: unable to claim bridge device {d}\n", .{bridge_id});
std.log.info("unable to claim bridge device {d}", .{bridge_id});
return false;
}
const buffer = runtime.allocator().alloc(device.DeviceDescriptor, 64) catch {
@@ -85,7 +80,7 @@ fn initialise(endpoint: runtime.ipc.Handle) bool {
const descriptor = for (buffer[0..@min(total, buffer.len)]) |d| {
if (d.id == bridge_id) break d;
} else {
writeLine("/system/drivers/pci-bus: device {d} not in the device tree\n", .{bridge_id});
std.log.info("device {d} not in the device tree", .{bridge_id});
return false;
};
// Resource 0 is the ECAM window (1 MiB of config space per bus); the bus
@@ -159,7 +154,7 @@ fn scan() void {
}
}
}
writeLine("/system/drivers/pci-bus: {d} functions found\n", .{found});
std.log.info("{d} functions found", .{found});
}
/// Register one function under the bridge and report it to the manager. The
@@ -229,7 +224,7 @@ fn registerAndReport(bus: u64, dev: u64, function: u64, class_triple: u32) void
}
const registered = device.register(bridge_id, &descriptor) orelse {
writeLine("/system/drivers/pci-bus: register refused for {d}:{d}.{d}\n", .{ bus, dev, function });
std.log.info("register refused for {d}:{d}.{d}", .{ bus, dev, function });
return;
};
const report = protocol.ChildAdded{
@@ -240,7 +235,7 @@ fn registerAndReport(bus: u64, dev: u64, function: u64, class_triple: u32) void
};
var reply: [protocol.message_maximum]u8 = undefined;
_ = runtime.ipc.call(manager_handle, std.mem.asBytes(&report), &reply) catch {
writeLine("/system/drivers/pci-bus: child report for {d}:{d}.{d} failed\n", .{ bus, dev, function });
std.log.info("child report for {d}:{d}.{d} failed", .{ bus, dev, function });
};
}
@@ -255,7 +250,7 @@ fn onMessage(message: []const u8, reply: []u8, sender: u32, capability: ?runtime
pub fn main(init: runtime.process.Init) void {
const argument = init.arguments.get(1) orelse return; // bare (ramdisk sweep): stay silent
bridge_id = std.fmt.parseInt(u64, argument, 10) catch {
writeLine("/system/drivers/pci-bus: malformed bridge device id '{s}'\n", .{argument});
std.log.info("malformed bridge device id '{s}'", .{argument});
return;
};
runtime.service.run(protocol.message_maximum, .{
+3 -8
View File
@@ -23,11 +23,6 @@ const device = runtime.device;
const ipc = runtime.ipc;
const protocol = runtime.input_protocol;
fn writeLine(comptime fmt: []const u8, arguments: anytype) void {
var line: [128]u8 = undefined;
_ = runtime.system.write(std.fmt.bufPrint(&line, fmt, arguments) catch return);
}
/// Look up the ps2-bus service, retrying while the bus (which spawned us before
/// registering) is still coming up.
fn lookupBus() ?ipc.Handle {
@@ -75,14 +70,14 @@ pub fn main(init: runtime.process.Init) void {
_ = runtime.system.write("/system/drivers/ps2-bus/keyboard: no HID argument\n");
return;
}
writeLine("/system/drivers/ps2-bus/keyboard: starting for hid {s}\n", .{hid});
std.log.info("starting for hid {s}", .{hid});
const buffer = runtime.allocator().alloc(device.DeviceDescriptor, 64) catch {
_ = runtime.system.write("/system/drivers/ps2-bus/keyboard: out of memory\n");
return;
};
if (device.findDeviceDescriptorByHid(buffer, hid) == null) {
writeLine("/system/drivers/ps2-bus/keyboard: no device for hid {s}\n", .{hid});
std.log.info("no device for hid {s}", .{hid});
return;
}
@@ -90,7 +85,7 @@ pub fn main(init: runtime.process.Init) void {
// absent (as today) it defaults to us.
const layout_name = init.arguments.get(2) orelse "us";
const layout = xkb.byName(layout_name) orelse xkb.us;
writeLine("/system/drivers/ps2-bus/keyboard: layout {s}\n", .{layout.name});
std.log.info("layout {s}", .{layout.name});
// Attach to the bus: hand it our endpoint, and it forwards every byte the
// keyboard sends (it owns the controller; we own the decoding).
+2 -7
View File
@@ -22,11 +22,6 @@ const device = runtime.device;
const ipc = runtime.ipc;
const protocol = runtime.input_protocol;
fn writeLine(comptime fmt: []const u8, arguments: anytype) void {
var line: [128]u8 = undefined;
_ = runtime.system.write(std.fmt.bufPrint(&line, fmt, arguments) catch return);
}
/// Look up the ps2-bus service, retrying while the bus (which spawned us before
/// registering) is still coming up.
fn lookupBus() ?ipc.Handle {
@@ -54,14 +49,14 @@ pub fn main(init: runtime.process.Init) void {
_ = runtime.system.write("/system/drivers/ps2-bus/mouse: no HID argument\n");
return;
}
writeLine("/system/drivers/ps2-bus/mouse: starting for hid {s}\n", .{hid});
std.log.info("starting for hid {s}", .{hid});
const buffer = runtime.allocator().alloc(device.DeviceDescriptor, 64) catch {
_ = runtime.system.write("/system/drivers/ps2-bus/mouse: out of memory\n");
return;
};
if (ps2.findMouseDescriptor(buffer) == null) {
writeLine("/system/drivers/ps2-bus/mouse: no device for hid {s}\n", .{hid});
std.log.info("no device for hid {s}", .{hid});
return;
}
+5 -12
View File
@@ -16,13 +16,6 @@ const ps2 = @import("ps2-library.zig");
const device = runtime.device;
const ipc = runtime.ipc;
/// Format one whole log line and emit it in a single `debug_write`, so output
/// from the child drivers (which run concurrently) can never interleave with it.
fn writeLine(comptime fmt: []const u8, arguments: anytype) void {
var line: [128]u8 = undefined;
_ = runtime.system.write(std.fmt.bufPrint(&line, fmt, arguments) catch return);
}
/// Ask the device on `port` what it is, then spawn the matching driver from the
/// initial-ramdisk, handing it the device's HID as argv[1]. The driver is chosen
/// from what the device reports, not from the port number. Returns the identified
@@ -30,19 +23,19 @@ fn writeLine(comptime fmt: []const u8, arguments: anytype) void {
/// attaches, or null if nothing was spawned.
fn spawnIdentifiedDriver(controller: ps2.Controller, port: ps2.Port) ?ps2.DeviceType {
const device_type = controller.identifyDevice(port) orelse {
writeLine("/system/drivers/ps2-bus: identify timed out on port {s}\n", .{@tagName(port)});
std.log.info("identify timed out on port {s}", .{@tagName(port)});
return null;
};
const driver_name = device_type.driverName() orelse {
writeLine("/system/drivers/ps2-bus: unrecognized device on port {s}\n", .{@tagName(port)});
std.log.info("unrecognized device on port {s}", .{@tagName(port)});
return null;
};
const hid = device_type.hid() orelse "";
if (runtime.system.spawnWithArguments(driver_name, &.{hid}) != null) {
writeLine("/system/drivers/ps2-bus: port {s} is a {s}, spawned {s}\n", .{ @tagName(port), hid, driver_name });
std.log.info("port {s} is a {s}, spawned {s}", .{ @tagName(port), hid, driver_name });
return device_type;
}
writeLine("/system/drivers/ps2-bus: failed to spawn {s}\n", .{driver_name});
std.log.info("failed to spawn {s}", .{driver_name});
return null;
}
@@ -83,7 +76,7 @@ fn handleAttach(message: []const u8, got: ipc.Received, out: []u8) usize {
const device_type = maybe_type orelse continue;
if (@intFromEnum(device_type) != request.device_type) continue;
port_endpoints[port_index] = endpoint;
writeLine("/system/drivers/ps2-bus: {s} driver attached\n", .{@tagName(device_type)});
std.log.info("{s} driver attached", .{@tagName(device_type)});
return reply.write(out, .ok);
}
return reply.write(out, .no_such_device);
+3 -8
View File
@@ -23,11 +23,6 @@ const ipc = runtime.ipc;
const process = runtime.process;
const input_protocol = runtime.input_protocol;
fn writeLine(comptime fmt: []const u8, arguments: anytype) void {
var line: [128]u8 = undefined;
_ = runtime.system.write(std.fmt.bufPrint(&line, fmt, arguments) catch return);
}
// The modifier state a character lookup needs — derived from the report's
// modifier byte, plus the driver-tracked caps-lock toggle.
const ModifierSnapshot = struct {
@@ -71,7 +66,7 @@ pub fn main(init: runtime.process.Init) void {
return;
};
const device_id = std.fmt.parseInt(u64, argument, 10) catch {
writeLine("/system/drivers/usb-hid/keyboard: malformed device id '{s}'\n", .{argument});
std.log.info("malformed device id '{s}'", .{argument});
return;
};
const layout = xkb.byName(init.arguments.get(2) orelse "us") orelse xkb.us;
@@ -82,7 +77,7 @@ pub fn main(init: runtime.process.Init) void {
return;
}
var device = runtime.usb.open(device_id) orelse {
writeLine("/system/drivers/usb-hid/keyboard: could not open device {d}\n", .{device_id});
std.log.info("could not open device {d}", .{device_id});
return;
};
const endpoint = device.findEndpoint(runtime.usb.transfer_type_interrupt, true) orelse {
@@ -104,7 +99,7 @@ pub fn main(init: runtime.process.Init) void {
return;
};
_ = process.bindSignals(device.endpoint);
writeLine("/system/drivers/usb-hid/keyboard: ok (device {d}, interface {d}, layout {s})\n", .{ device_id, device.interface_number, layout.name });
std.log.info("ok (device {d}, interface {d}, layout {s})", .{ device_id, device.interface_number, layout.name });
var decoder = hid.KeyboardDecoder{};
var caps_lock = false;
+3 -8
View File
@@ -18,11 +18,6 @@ const ipc = runtime.ipc;
const process = runtime.process;
const input_protocol = runtime.input_protocol;
fn writeLine(comptime fmt: []const u8, arguments: anytype) void {
var line: [128]u8 = undefined;
_ = runtime.system.write(std.fmt.bufPrint(&line, fmt, arguments) catch return);
}
// The current pressed-button bitmask in input-protocol terms.
fn buttonMask(buttons: u8) u32 {
var mask: u32 = 0;
@@ -38,7 +33,7 @@ pub fn main(init: runtime.process.Init) void {
return;
};
const device_id = std.fmt.parseInt(u64, argument, 10) catch {
writeLine("/system/drivers/usb-hid/mouse: malformed device id '{s}'\n", .{argument});
std.log.info("malformed device id '{s}'", .{argument});
return;
};
@@ -47,7 +42,7 @@ pub fn main(init: runtime.process.Init) void {
return;
}
var device = runtime.usb.open(device_id) orelse {
writeLine("/system/drivers/usb-hid/mouse: could not open device {d}\n", .{device_id});
std.log.info("could not open device {d}", .{device_id});
return;
};
const endpoint = device.findEndpoint(runtime.usb.transfer_type_interrupt, true) orelse {
@@ -67,7 +62,7 @@ pub fn main(init: runtime.process.Init) void {
return;
};
_ = process.bindSignals(device.endpoint);
writeLine("/system/drivers/usb-hid/mouse: ok (device {d}, interface {d})\n", .{ device_id, device.interface_number });
std.log.info("ok (device {d}, interface {d})", .{ device_id, device.interface_number });
var previous_buttons: u8 = 0;
var receive: [64]u8 = undefined;
+4 -9
View File
@@ -18,11 +18,6 @@ const bot = @import("bulk-only-transport.zig");
const block_protocol = @import("block-protocol");
const dma = runtime.dma;
fn writeLine(comptime fmt: []const u8, arguments: anytype) void {
var line: [128]u8 = undefined;
_ = runtime.system.write(std.fmt.bufPrint(&line, fmt, arguments) catch return);
}
var device_id: u64 = 0;
var device: runtime.usb.Device = undefined;
var bulk_in: runtime.usb.Endpoint = undefined;
@@ -73,7 +68,7 @@ fn initialise(endpoint: runtime.ipc.Handle) bool {
return false;
}
device = runtime.usb.open(device_id) orelse {
writeLine("/system/drivers/usb-storage: could not open device {d}\n", .{device_id});
std.log.info("could not open device {d}", .{device_id});
return false;
};
bulk_in = device.findEndpoint(runtime.usb.transfer_type_bulk, true) orelse {
@@ -112,14 +107,14 @@ fn initialise(endpoint: runtime.ipc.Handle) bool {
const capacity = scsi.parseCapacity(capacity_bytes);
block_size = capacity.block_size;
block_count = @as(u64, capacity.last_lba) + 1;
writeLine("/system/drivers/usb-storage: ready ({d} blocks x {d} bytes)\n", .{ block_count, block_size });
std.log.info("ready ({d} blocks x {d} bytes)", .{ block_count, block_size });
// Self-check: read block 0 and log its trailing signature (0x55AA for a boot
// sector) — proof READ(10) works end to end over the bulk path.
const read0 = scsi.read10(0, 1);
if (block_size <= 4096 and transact(&read0, true, command_data.physical, block_size)) {
const sector: [*]const u8 = @ptrFromInt(command_data.virtual);
writeLine("/system/drivers/usb-storage: block 0 signature 0x{x:0>2}{x:0>2}\n", .{ sector[510], sector[511] });
std.log.info("block 0 signature 0x{x:0>2}{x:0>2}", .{ sector[510], sector[511] });
}
return true;
}
@@ -171,7 +166,7 @@ pub fn main(init: runtime.process.Init) void {
return;
};
device_id = std.fmt.parseInt(u64, argument, 10) catch {
writeLine("/system/drivers/usb-storage: malformed device id '{s}'\n", .{argument});
std.log.info("malformed device id '{s}'", .{argument});
return;
};
runtime.service.run(block_protocol.message_maximum, .{
+14 -21
View File
@@ -64,13 +64,6 @@ fn reportEndpointFor(device_token: u64) ?usize {
return null;
}
/// Format one whole log line and emit it in a single `debug_write`, so
/// concurrent instances (one per controller) can never interleave mid-line.
fn writeLine(comptime fmt: []const u8, arguments: anytype) void {
var line: [128]u8 = undefined;
_ = runtime.system.write(std.fmt.bufPrint(&line, fmt, arguments) catch return);
}
var controller_id: u64 = protocol.no_device;
/// Claim the assigned controller, find its register window, and hello the
@@ -79,7 +72,7 @@ var controller_id: u64 = protocol.no_device;
fn initialise(endpoint: runtime.ipc.Handle) bool {
service_endpoint = endpoint;
if (!device.claim(controller_id)) {
writeLine("/system/drivers/usb-xhci-bus: unable to claim controller device {d}\n", .{controller_id});
std.log.info("unable to claim controller device {d}", .{controller_id});
return false;
}
@@ -92,7 +85,7 @@ fn initialise(endpoint: runtime.ipc.Handle) bool {
const descriptor = for (buffer[0..@min(total, buffer.len)]) |d| {
if (d.id == controller_id) break d;
} else {
writeLine("/system/drivers/usb-xhci-bus: device {d} not in the device tree\n", .{controller_id});
std.log.info("device {d} not in the device tree", .{controller_id});
return false;
};
@@ -105,10 +98,10 @@ fn initialise(endpoint: runtime.ipc.Handle) bool {
break resource;
}
} else {
writeLine("/system/drivers/usb-xhci-bus: controller device {d} has no register BAR\n", .{controller_id});
std.log.info("controller device {d} has no register BAR", .{controller_id});
return false;
};
writeLine("/system/drivers/usb-xhci-bus: claimed controller device {d} (registers at 0x{x}, {d} bytes)\n", .{
std.log.info("claimed controller device {d} (registers at 0x{x}, {d} bytes)", .{
controller_id,
register_window.start,
register_window.len,
@@ -124,7 +117,7 @@ fn initialise(endpoint: runtime.ipc.Handle) bool {
_ = runtime.system.write("/system/drivers/usb-xhci-bus: controller reset/bring-up failed\n");
return false;
};
writeLine("/system/drivers/usb-xhci-bus: controller running ({d} slots, {d}-byte contexts)\n", .{
std.log.info("controller running ({d} slots, {d}-byte contexts)", .{
controller.?.max_slots,
controller.?.context_size,
});
@@ -198,7 +191,7 @@ fn scanPorts(manager: runtime.ipc.Handle) void {
_ = runtime.system.write("/system/drivers/usb-xhci-bus: controller not initialised\n");
return;
};
writeLine("/system/drivers/usb-xhci-bus: {d} root-hub ports\n", .{engine.max_ports});
std.log.info("{d} root-hub ports", .{engine.max_ports});
var port: u32 = 1;
var connected: u32 = 0;
@@ -207,17 +200,17 @@ fn scanPorts(manager: runtime.ipc.Handle) void {
if (port_status & 1 == 0) continue; // CCS: nothing connected
connected += 1;
const speed = (port_status >> 10) & 0xF; // the PORTSC port-speed class
writeLine("/system/drivers/usb-xhci-bus: port {d} connected — {s} (speed class {d})\n", .{ port, speedName(speed), speed });
std.log.info("port {d} connected — {s} (speed class {d})", .{ port, speedName(speed), speed });
const usb_device = engine.setupDevice(port, speed) orelse {
writeLine("/system/drivers/usb-xhci-bus: port {d} device setup failed\n", .{port});
std.log.info("port {d} device setup failed", .{port});
continue;
};
if (!engine.enumerate(usb_device)) {
writeLine("/system/drivers/usb-xhci-bus: port {d} enumeration failed\n", .{port});
std.log.info("port {d} enumeration failed", .{port});
continue;
}
writeLine("/system/drivers/usb-xhci-bus: port {d} device vendor 0x{x:0>4} product 0x{x:0>4}, {d} interface(s)\n", .{
std.log.info("port {d} device vendor 0x{x:0>4} product 0x{x:0>4}, {d} interface(s)", .{
port,
usb_device.device_descriptor.vendor_id,
usb_device.device_descriptor.product_id,
@@ -259,7 +252,7 @@ fn reportInterface(manager: runtime.ipc.Handle, port: u32, interface: library.In
descriptor.hid_len = hid_text.len;
@memcpy(descriptor.hid[0..hid_text.len], hid_text);
const registered = device.register(controller_id, &descriptor) orelse {
writeLine("/system/drivers/usb-xhci-bus: register refused for port {d} interface {d}\n", .{ port, interface.number });
std.log.info("register refused for port {d} interface {d}", .{ port, interface.number });
return null;
};
@@ -271,10 +264,10 @@ fn reportInterface(manager: runtime.ipc.Handle, port: u32, interface: library.In
};
var reply: [protocol.message_maximum]u8 = undefined;
_ = runtime.ipc.call(manager, std.mem.asBytes(&report), &reply) catch {
writeLine("/system/drivers/usb-xhci-bus: child report for port {d} interface {d} failed\n", .{ port, interface.number });
std.log.info("child report for port {d} interface {d} failed", .{ port, interface.number });
return null;
};
writeLine("/system/drivers/usb-xhci-bus: port {d} interface {d} class {d}/{d}/{d} registered as device {d}\n", .{
std.log.info("port {d} interface {d} class {d}/{d}/{d} registered as device {d}", .{
port,
interface.number,
interface.class,
@@ -407,7 +400,7 @@ pub fn main(init: runtime.process.Init) void {
return;
};
controller_id = std.fmt.parseInt(u64, argument, 10) catch {
writeLine("/system/drivers/usb-xhci-bus: malformed controller device id '{s}'\n", .{argument});
std.log.info("malformed controller device id '{s}'", .{argument});
return;
};
runtime.service.run(transfer.message_maximum, .{
+33 -40
View File
@@ -103,13 +103,6 @@ var surface: shm.Region = undefined;
var avail_shadow: u16 = 0;
var used_shadow: u16 = 0;
/// Format one whole log line and emit it in a single `write`, so this driver's output can
/// never interleave mid-line with the other drivers the manager runs concurrently.
fn log(comptime fmt: []const u8, arguments: anytype) void {
var line: [160]u8 = undefined;
_ = system.write(std.fmt.bufPrint(&line, fmt, arguments) catch return);
}
// --- common-config register access (little-endian MMIO at `common_base`) ---------------
fn cfgRead(comptime T: type, comptime field: []const u8) T {
@@ -154,7 +147,7 @@ fn mapBar(config: usize, descriptor: *const device.DeviceDescriptor, bar: u8) ?u
return v;
}
}
log("virtio-gpu: BAR {d} (physical 0x{x}) is not a mapped resource\n", .{ bar, base });
std.log.info("BAR {d} (physical 0x{x}) is not a mapped resource", .{ bar, base });
return null;
}
@@ -162,7 +155,7 @@ fn mapBar(config: usize, descriptor: *const device.DeviceDescriptor, bar: u8) ?u
/// notify structures (the only two V3 needs). Returns false if either is missing.
fn walkCapabilities(config: usize, descriptor: *const device.DeviceDescriptor) bool {
if (mmio.read(u16, config + 0x06) & 0x10 == 0) { // Status bit 4: capabilities list present
log("virtio-gpu: device has no PCI capability list\n", .{});
std.log.info("device has no PCI capability list", .{});
return false;
}
var cap: u8 = @as(u8, @truncate(mmio.read(u8, config + 0x34))) & 0xFC;
@@ -193,7 +186,7 @@ fn walkCapabilities(config: usize, descriptor: *const device.DeviceDescriptor) b
cap = next;
}
if (common_base == 0 or notify_base == 0) {
log("virtio-gpu: missing common-config or notify capability\n", .{});
std.log.info("missing common-config or notify capability", .{});
return false;
}
return true;
@@ -275,7 +268,7 @@ fn testPixel(index: u32) u32 {
fn initialise(endpoint: ipc.Handle) bool {
_ = endpoint;
if (!device.claim(device_id)) {
log("virtio-gpu: unable to claim device {d}\n", .{device_id});
std.log.info("unable to claim device {d}", .{device_id});
return false;
}
@@ -284,7 +277,7 @@ fn initialise(endpoint: ipc.Handle) bool {
const descriptor = for (descriptors[0..@min(total, descriptors.len)]) |*d| {
if (d.id == device_id) break d;
} else {
log("virtio-gpu: device {d} not in the device tree\n", .{device_id});
std.log.info("device {d} not in the device tree", .{device_id});
return false;
};
@@ -292,13 +285,13 @@ fn initialise(endpoint: ipc.Handle) bool {
// decode + bus mastering (the device DMAs the ring and backing out of RAM); pci-bus only
// preserves whatever the firmware left, and a secondary display is often left disabled.
const config = device.mmioMap(device_id, 0) orelse {
log("virtio-gpu: config-space map failed\n", .{});
std.log.info("config-space map failed", .{});
return false;
};
const vendor = mmio.read(u16, config + 0x00);
const dev = mmio.read(u16, config + 0x02);
if (vendor != virtio_vendor or dev != virtio_gpu_device) {
log("virtio-gpu: not a virtio-gpu (vendor 0x{x} device 0x{x})\n", .{ vendor, dev });
std.log.info("not a virtio-gpu (vendor 0x{x} device 0x{x})", .{ vendor, dev });
return false;
}
mmio.write(u16, config + 0x04, mmio.read(u16, config + 0x04) | 0x06); // MEM + bus master
@@ -317,7 +310,7 @@ fn initialise(endpoint: ipc.Handle) bool {
// High feature word: VERSION_1 (bit 32) is required for a modern device.
cfgWrite(u32, "device_feature_select", vp.feature_version_1_word);
if (cfgRead(u32, "device_feature") & vp.feature_version_1_bit == 0) {
log("virtio-gpu: device does not offer VERSION_1 (not a modern device)\n", .{});
std.log.info("device does not offer VERSION_1 (not a modern device)", .{});
return false;
}
// Accept exactly VERSION_1, plus EDID when the device offered it (never a feature it didn't).
@@ -327,7 +320,7 @@ fn initialise(endpoint: ipc.Handle) bool {
cfgWrite(u32, "driver_feature", vp.feature_version_1_bit);
orStatus(vp.status_features_ok);
if (cfgRead(u8, "device_status") & vp.status_features_ok == 0) {
log("virtio-gpu: device rejected the negotiated features\n", .{});
std.log.info("device rejected the negotiated features", .{});
return false;
}
@@ -335,15 +328,15 @@ fn initialise(endpoint: ipc.Handle) bool {
cfgWrite(u16, "queue_select", 0);
const device_qsize = cfgRead(u16, "queue_size");
if (device_qsize < queue_size) {
log("virtio-gpu: control queue too small ({d})\n", .{device_qsize});
std.log.info("control queue too small ({d})", .{device_qsize});
return false;
}
ring = dma.alloc(4096, dma.coherent) orelse {
log("virtio-gpu: virtqueue allocation failed\n", .{});
std.log.info("virtqueue allocation failed", .{});
return false;
};
command = dma.alloc(4096, dma.coherent) orelse {
log("virtio-gpu: command-buffer allocation failed\n", .{});
std.log.info("command-buffer allocation failed", .{});
return false;
};
mmio.write(u16, ring.virtual + avail_offset, 1); // VIRTQ_AVAIL_F_NO_INTERRUPT: we poll
@@ -371,7 +364,7 @@ fn initialise(endpoint: ipc.Handle) bool {
.height = max_height,
};
if (command_nodata(@sizeOf(vg.ResourceCreate2d)) != ok_nodata) {
log("virtio-gpu: resource_create_2d failed\n", .{});
std.log.info("resource_create_2d failed", .{});
return false;
}
}
@@ -379,11 +372,11 @@ fn initialise(endpoint: ipc.Handle) bool {
// Back the resource with a shared (shm) surface, so the compositor and the device work
// the same physical pages. The device needs the guest-physical base for attach_backing.
surface = shm.create(scanout_bytes) orelse {
log("virtio-gpu: scanout surface allocation failed\n", .{});
std.log.info("scanout surface allocation failed", .{});
return false;
};
const surface_physical = shm.physical(surface.handle) orelse {
log("virtio-gpu: could not resolve the scanout surface physical address\n", .{});
std.log.info("could not resolve the scanout surface physical address", .{});
return false;
};
{
@@ -396,15 +389,15 @@ fn initialise(endpoint: ipc.Handle) bool {
const entry: *vg.MemEntry = @ptrFromInt(command.virtual + request_offset + @sizeOf(vg.ResourceAttachBacking));
entry.* = .{ .addr = surface_physical, .length = @intCast(scanout_bytes) };
if (command_nodata(@sizeOf(vg.ResourceAttachBacking) + @sizeOf(vg.MemEntry)) != ok_nodata) {
log("virtio-gpu: resource_attach_backing failed\n", .{});
std.log.info("resource_attach_backing failed", .{});
return false;
}
}
if (!setScanoutRect()) {
log("virtio-gpu: set_scanout failed\n", .{});
std.log.info("set_scanout failed", .{});
return false;
}
log("virtio-gpu: scanout {d}x{d} online\n", .{ current_width, current_height });
std.log.info("scanout {d}x{d} online", .{ current_width, current_height });
// Hello the device manager so it counts us as up (and does not stop us at the hello
// deadline). A restarted instance re-hellos here and re-announces below — the compositor
@@ -422,17 +415,17 @@ fn initialise(endpoint: ipc.Handle) bool {
for (0..pixel_count) |i| pixels[i] = testPixel(@intCast(i));
if (!presentFull()) {
log("virtio-gpu: initial present failed\n", .{});
std.log.info("initial present failed", .{});
return false;
}
// The scanout surface is CPU-visible RAM: read the pattern back to prove the mapping,
// which together with the flush ack above is the automated stand-in for "it's on screen".
mmio.rmb();
if (pixels[0] != testPixel(0) or pixels[pixel_count / 2] != testPixel(@intCast(pixel_count / 2))) {
log("virtio-gpu: pixel read-back mismatch\n", .{});
std.log.info("pixel read-back mismatch", .{});
return false;
}
log("virtio-gpu: flush acked, pixel check ok\n", .{});
std.log.info("flush acked, pixel check ok", .{});
// Offer the shared surface to the compositor so it upgrades off the GOP floor (V4).
announce();
@@ -456,18 +449,18 @@ fn setScanoutRect() bool {
/// a device that doesn't offer EDID, or a missing/short block, is logged and ignored.
fn readEdid() void {
if (!edid_available) {
log("virtio-gpu: EDID not offered by device\n", .{});
std.log.info("EDID not offered by device", .{});
return;
}
const request = requestAt(vg.GetEdid);
request.* = .{ .hdr = .{ .type = @intFromEnum(vg.CmdType.get_edid) }, .scanout = 0 };
if (!submit(@sizeOf(vg.GetEdid), @sizeOf(vg.RespEdid))) {
log("virtio-gpu: EDID request not acked\n", .{});
std.log.info("EDID request not acked", .{});
return;
}
const response: *vg.RespEdid = @ptrFromInt(command.virtual + response_offset);
if (response.hdr.type != @intFromEnum(vg.CmdType.resp_ok_edid) or response.size < 64) {
log("virtio-gpu: EDID unavailable\n", .{});
std.log.info("EDID unavailable", .{});
return;
}
// The first detailed timing descriptor (EDID base-block offset 54) is the preferred mode:
@@ -483,7 +476,7 @@ fn readEdid() void {
const v_blank = @as(u64, e[60]) | (@as(u64, e[61] & 0x0F) << 8);
const total = (@as(u64, h_active) + h_blank) * (@as(u64, v_active) + v_blank);
if (total != 0) edid_refresh_hz = @intCast((clock_hz + total / 2) / total);
log("virtio-gpu: EDID preferred mode {d}x{d} @ {d} Hz\n", .{ h_active, v_active, edid_refresh_hz });
std.log.info("EDID preferred mode {d}x{d} @ {d} Hz", .{ h_active, v_active, edid_refresh_hz });
}
/// Present the whole surface: copy the guest backing into the host resource, then flush it to
@@ -529,20 +522,20 @@ fn helloManager() void {
if (ipc.lookup(.device_manager)) |h| break h;
system.sleep(20);
} else {
log("virtio-gpu: no device manager to hello\n", .{});
std.log.info("no device manager to hello", .{});
return;
};
const hello = dm.Hello{ .role = @intFromEnum(dm.Role.bus), .device_id = device_id };
var reply: [dm.reply_size]u8 = undefined;
const n = ipc.call(manager, std.mem.asBytes(&hello), &reply) catch {
log("virtio-gpu: hello call failed\n", .{});
std.log.info("hello call failed", .{});
return;
};
if (n < dm.reply_size or std.mem.bytesToValue(dm.HelloReply, reply[0..dm.reply_size]).status != 0) {
log("virtio-gpu: hello refused\n", .{});
std.log.info("hello refused", .{});
return;
}
log("virtio-gpu: hello acknowledged\n", .{});
std.log.info("hello acknowledged", .{});
}
/// Announce the scanout to the display service so it upgrades off the GOP framebuffer: hand it
@@ -556,7 +549,7 @@ fn announce() void {
if (ipc.lookup(.display)) |h| break h;
system.sleep(20);
} else {
log("virtio-gpu: no display service to announce to (scanout-only)\n", .{});
std.log.info("no display service to announce to (scanout-only)", .{});
return;
};
var request = dp.Request{
@@ -569,10 +562,10 @@ fn announce() void {
};
var reply: [dp.reply_size]u8 = undefined;
_ = ipc.callCap(display, std.mem.asBytes(&request), &reply, surface.handle) catch {
log("virtio-gpu: announce to display failed\n", .{});
std.log.info("announce to display failed", .{});
return;
};
log("virtio-gpu: announced scanout to display\n", .{});
std.log.info("announced scanout to display", .{});
}
/// A `sp.Reply{status}` written into `reply`.
@@ -621,7 +614,7 @@ pub fn main(init: runtime.process.Init) void {
return;
};
device_id = std.fmt.parseInt(u64, argument, 10) catch {
log("virtio-gpu: malformed device id '{s}'\n", .{argument});
std.log.info("malformed device id '{s}'", .{argument});
return;
};
runtime.service.run(256, .{