Author SHA1 Message Date
Daniel Samson 6e60daed6a Fix the drviers typo and make tests robust to source-path debug prefixes
The debug-message refactor prefixed each service/driver line with its
source path (system/drivers/hpet:, ...) for readability, but two things
left main red: a 'drviers' typo in hpet.zig and pci-bus.zig, and five
kernel tests (init, hpet, pci-scan, device-manager, vfs-client-death)
that starts-with-matched the old short markers, which no longer sit at
the front of the prefixed lines.

Fix the typo, and convert the fragile starts-with matchers to substring
matching via a bufferHas helper — 'hpet: ok' now matches inside
'system/drivers/hpet: ok' regardless of prefix. Future-proof against
further prefix changes and harmless for the tests that already passed.
Suite 58/58.
2026-07-13 06:23:21 +01:00
Daniel Samson dd044fb115 fix / debug 2026-07-13 05:41:57 +01:00
Daniel Samson 3ec14509a0 fix / debug 2026-07-13 05:41:05 +01:00
Daniel Samson d71a5f25d3 fix kernel: debug 2026-07-13 05:37:35 +01:00
Daniel Samson 2a0f17ae86 fix kernel: debug 2026-07-13 05:35:29 +01:00
Daniel Samson 9ef61a0844 fix kernel: debug prefix 2026-07-13 05:32:26 +01:00
Daniel Samson 688b9101e8 fix kernel: debug prefix 2026-07-13 05:31:36 +01:00
Daniel Samson 1d7ba814dc fix efi: debug prefix 2026-07-13 05:30:56 +01:00
Daniel Samson 8aba86b4ce fix vfs: debug prefix 2026-07-13 05:24:47 +01:00
Daniel Samson a0c83f4b3f fix input: debug prefix 2026-07-13 05:24:16 +01:00
Daniel Samson 1ea48ed5d6 fix init: debug prefix 2026-07-13 05:23:07 +01:00
Daniel Samson 77a3ccd33d fix hpet: debug prefix 2026-07-13 05:22:27 +01:00
Daniel Samson 07da27dc39 fix pci-bus: debug prefix 2026-07-13 05:21:47 +01:00
Daniel Samson d89657d0a4 fix device-manager: debug prefix 2026-07-13 05:21:08 +01:00
Daniel Samson 849b4b62d4 fix acpi: debug prefix 2026-07-13 05:20:31 +01:00
Daniel Samson 8589bf713b fix usb-xhci-bus debug prefix 2026-07-13 05:18:49 +01:00
14 changed files with 204 additions and 199 deletions
+6 -6
View File
@@ -29,7 +29,7 @@ pub fn main() uefi.Status {
// report the reason (boot services are still up) and park the machine so the // report the reason (boot services are still up) and park the machine so the
// message stays on screen. // message stays on screen.
boot() catch |err| { boot() catch |err| {
log("\r\ndanos: boot failed: "); log("\r\nEFI: boot failed: ");
logBytes(@errorName(err)); logBytes(@errorName(err));
log("\r\n"); log("\r\n");
while (true) asm volatile ("hlt"); while (true) asm volatile ("hlt");
@@ -65,14 +65,14 @@ fn boot() !noreturn {
// Best effort: a volume without /system/services/init still boots (kernel-only). // Best effort: a volume without /system/services/init still boots (kernel-only).
loadInit(bs, &boot_information) catch |err| { loadInit(bs, &boot_information) catch |err| {
log("danos: no /system/services/init ("); log("EFI: no /system/services/init (");
logBytes(@errorName(err)); logBytes(@errorName(err));
log(") - booting without user space\r\n"); log(") - booting without user space\r\n");
}; };
// Best effort: the initial_ramdisk (VFS server + drivers) is optional too. // Best effort: the initial_ramdisk (VFS server + drivers) is optional too.
loadInitialRamdisk(bs, &boot_information) catch |err| { loadInitialRamdisk(bs, &boot_information) catch |err| {
log("danos: no initial_ramdisk ("); log("EFI: no initial_ramdisk (");
logBytes(@errorName(err)); logBytes(@errorName(err));
log(")\r\n"); log(")\r\n");
}; };
@@ -84,7 +84,7 @@ fn boot() !noreturn {
// the map and exiting would invalidate the map key. // the map and exiting would invalidate the map key.
const cr3 = try buildBootstrapTables(bs, &boot_information); const cr3 = try buildBootstrapTables(bs, &boot_information);
log("danos: kernel loaded, exiting boot services\r\n"); log("EFI: kernel loaded, exiting boot services\r\n");
boot_information.memory_map = try exitBootServices(bs); boot_information.memory_map = try exitBootServices(bs);
// Switch onto our tables and jump to the kernel in one uninterruptible step. // Switch onto our tables and jump to the kernel in one uninterruptible step.
@@ -395,7 +395,7 @@ fn loadInit(bs: *uefi.tables.BootServices, boot_information: *BootInformation) !
const image = try loadFile(bs, init_file_name); const image = try loadFile(bs, init_file_name);
boot_information.init_base = @intFromPtr(image.ptr); boot_information.init_base = @intFromPtr(image.ptr);
boot_information.init_len = image.len; boot_information.init_len = image.len;
log("danos: /system/services/init loaded\r\n"); log("EFI: /system/services/init loaded\r\n");
} }
/// Ferry the initial_ramdisk (the VFS server + drivers) to the kernel, same as init. /// Ferry the initial_ramdisk (the VFS server + drivers) to the kernel, same as init.
@@ -403,7 +403,7 @@ fn loadInitialRamdisk(bs: *uefi.tables.BootServices, boot_information: *BootInfo
const image = try loadFile(bs, initial_ramdisk_file_name); const image = try loadFile(bs, initial_ramdisk_file_name);
boot_information.initial_ramdisk_base = @intFromPtr(image.ptr); boot_information.initial_ramdisk_base = @intFromPtr(image.ptr);
boot_information.initial_ramdisk_len = image.len; boot_information.initial_ramdisk_len = image.len;
log("danos: initial_ramdisk loaded\r\n"); log("EFI: initial_ramdisk loaded\r\n");
} }
/// Validate the ELF, copy every PT_LOAD segment to its physical address, and /// Validate the ELF, copy every PT_LOAD segment to its physical address, and
+11 -11
View File
@@ -93,21 +93,21 @@ fn findHpet(buffer: []device.DeviceDescriptor) ?Found {
pub fn main() void { pub fn main() void {
// Enumerate into a heap buffer (too big for the one-page user stack). // Enumerate into a heap buffer (too big for the one-page user stack).
const buffer = runtime.allocator().alloc(device.DeviceDescriptor, 32) catch { const buffer = runtime.allocator().alloc(device.DeviceDescriptor, 32) catch {
_ = runtime.system.write("hpet: out of memory\n"); _ = runtime.system.write("system/drivers/hpet: out of memory\n");
return; return;
}; };
const hpet = findHpet(buffer) orelse { const hpet = findHpet(buffer) orelse {
_ = runtime.system.write("hpet: no HPET with an IRQ\n"); _ = runtime.system.write("system/drivers/hpet: no HPET with an IRQ\n");
return; return;
}; };
if (!device.claim(hpet.device_id)) { if (!device.claim(hpet.device_id)) {
_ = runtime.system.write("hpet: claim failed\n"); _ = runtime.system.write("system/drivers/hpet: claim failed\n");
return; return;
} }
const base = device.mmioMap(hpet.device_id, hpet.mmio) orelse { const base = device.mmioMap(hpet.device_id, hpet.mmio) orelse {
_ = runtime.system.write("hpet: mmio_map failed\n"); _ = runtime.system.write("system/drivers/hpet: mmio_map failed\n");
return; return;
}; };
@@ -116,7 +116,7 @@ pub fn main() void {
const gsi = hpet.gsi; const gsi = hpet.gsi;
const endpoint = ipc.createIpcEndpoint() orelse { const endpoint = ipc.createIpcEndpoint() orelse {
_ = runtime.system.write("hpet: create_ipc_endpoint failed\n"); _ = runtime.system.write("system/drivers/hpet: create_ipc_endpoint failed\n");
return; return;
}; };
@@ -124,7 +124,7 @@ pub fn main() void {
// Counter period, so we can arm the comparator a fixed wall-clock distance out. // Counter period, so we can arm the comparator a fixed wall-clock distance out.
const femtos_per_tick = rd(base, register_general_cap) >> 32; const femtos_per_tick = rd(base, register_general_cap) >> 32;
if (femtos_per_tick == 0) { if (femtos_per_tick == 0) {
_ = runtime.system.write("hpet: bad HPET period\n"); _ = runtime.system.write("system/drivers/hpet: bad HPET period\n");
return; return;
} }
const ticks_per_ms = 1_000_000_000_000 / femtos_per_tick; const ticks_per_ms = 1_000_000_000_000 / femtos_per_tick;
@@ -147,10 +147,10 @@ pub fn main() void {
wr(base, register_general_configuration, rd(base, register_general_configuration) | configuration_enable); wr(base, register_general_configuration, rd(base, register_general_configuration) | configuration_enable);
if (!device.irqBind(hpet.device_id, hpet.irq, endpoint)) { if (!device.irqBind(hpet.device_id, hpet.irq, endpoint)) {
_ = runtime.system.write("hpet: irq_bind failed\n"); _ = runtime.system.write("system/drivers/hpet: irq_bind failed\n");
return; return;
} }
_ = runtime.system.write("hpet: bound, sleeping until the hardware speaks\n"); _ = runtime.system.write("system/drivers/hpet: bound, sleeping until the hardware speaks\n");
// --- the driver loop ----------------------------------------------------- // --- the driver loop -----------------------------------------------------
// Blocked in replyWait. No polling, no spinning: the next line of this function // Blocked in replyWait. No polling, no spinning: the next line of this function
@@ -178,14 +178,14 @@ pub fn main() void {
wr(base, register_timer0_configuration, rd(base, register_timer0_configuration) & ~tn_int_enb); wr(base, register_timer0_configuration, rd(base, register_timer0_configuration) & ~tn_int_enb);
} }
_ = runtime.system.write("hpet: irq\n"); _ = runtime.system.write("system/drivers/hpet: irq\n");
if (!device.irqAck(hpet.device_id, hpet.irq)) { if (!device.irqAck(hpet.device_id, hpet.irq)) {
_ = runtime.system.write("hpet: irq_ack failed\n"); _ = runtime.system.write("system/drivers/hpet: irq_ack failed\n");
return; return;
} }
} }
_ = runtime.system.write("hpet: ok\n"); _ = runtime.system.write("system/drivers/hpet: ok\n");
while (true) runtime.system.sleep(1000); while (true) runtime.system.sleep(1000);
} }
+16 -16
View File
@@ -6,7 +6,7 @@
//! M19.1 (this increment): claim the bridge, map its ECAM window (resource 0; //! M19.1 (this increment): claim the bridge, map its ECAM window (resource 0;
//! the bus range and the MMIO apertures follow it), walk every //! the bus range and the MMIO apertures follow it), walk every
//! bus/device/function config header, and log what the walk finds — ending //! bus/device/function config header, and log what the walk finds — ending
//! with "pci-bus: N functions found", which the `pci-scan` scenario compares //! with "/system/drivers/pci-bus: N functions found", which the `pci-scan` scenario compares
//! against the kernel's own enumeration. Registration and reports (M19.2), and //! against the kernel's own enumeration. Registration and reports (M19.2), and
//! the kernel walk's retirement (M19.3), build on this proven-equivalent scan. //! the kernel walk's retirement (M19.3), build on this proven-equivalent scan.
@@ -31,9 +31,9 @@ fn logFunction(bus: u64, dev: u64, function: u64, class_triple: u32) void {
const pif = pci_class.progIfName(cc.base, cc.subclass, cc.prog_if); const pif = pci_class.progIfName(cc.base, cc.subclass, cc.prog_if);
var line: [200]u8 = undefined; var line: [200]u8 = undefined;
const text = if (pif.len != 0) const text = if (pif.len != 0)
std.fmt.bufPrint(&line, "pci-bus: {d}:{d}.{d} class 0x{x:0>2} ({s}) subclass 0x{x:0>2} ({s}) progif 0x{x:0>2} ({s})\n", .{ bus, dev, function, cc.base, pci_class.className(cc.base), cc.subclass, pci_class.subclassName(cc.base, cc.subclass), cc.prog_if, pif }) catch return std.fmt.bufPrint(&line, "/system/drivers/pci-bus: {d}:{d}.{d} class 0x{x:0>2} ({s}) subclass 0x{x:0>2} ({s}) progif 0x{x:0>2} ({s})\n", .{ bus, dev, function, cc.base, pci_class.className(cc.base), cc.subclass, pci_class.subclassName(cc.base, cc.subclass), cc.prog_if, pif }) catch return
else else
std.fmt.bufPrint(&line, "pci-bus: {d}:{d}.{d} class 0x{x:0>2} ({s}) subclass 0x{x:0>2} ({s}) progif 0x{x:0>2}\n", .{ bus, dev, function, cc.base, pci_class.className(cc.base), cc.subclass, pci_class.subclassName(cc.base, cc.subclass), cc.prog_if }) catch return; std.fmt.bufPrint(&line, "/system/drivers/pci-bus: {d}:{d}.{d} class 0x{x:0>2} ({s}) subclass 0x{x:0>2} ({s}) progif 0x{x:0>2}\n", .{ bus, dev, function, cc.base, pci_class.className(cc.base), cc.subclass, pci_class.subclassName(cc.base, cc.subclass), cc.prog_if }) catch return;
_ = runtime.system.write(text); _ = runtime.system.write(text);
} }
@@ -74,37 +74,37 @@ fn configWrite16(bus: u64, dev: u64, function: u64, offset: u64, value: u16) voi
fn initialise(endpoint: runtime.ipc.Handle) bool { fn initialise(endpoint: runtime.ipc.Handle) bool {
_ = endpoint; _ = endpoint;
if (!device.claim(bridge_id)) { if (!device.claim(bridge_id)) {
writeLine("pci-bus: unable to claim bridge device {d}\n", .{bridge_id}); writeLine("/system/drivers/pci-bus: unable to claim bridge device {d}\n", .{bridge_id});
return false; return false;
} }
const buffer = runtime.allocator().alloc(device.DeviceDescriptor, 64) catch { const buffer = runtime.allocator().alloc(device.DeviceDescriptor, 64) catch {
_ = runtime.system.write("pci-bus: out of memory\n"); _ = runtime.system.write("/system/drivers/pci-bus: out of memory\n");
return false; return false;
}; };
const total = device.enumerate(buffer); const total = device.enumerate(buffer);
const descriptor = for (buffer[0..@min(total, buffer.len)]) |d| { const descriptor = for (buffer[0..@min(total, buffer.len)]) |d| {
if (d.id == bridge_id) break d; if (d.id == bridge_id) break d;
} else { } else {
writeLine("pci-bus: device {d} not in the device tree\n", .{bridge_id}); writeLine("/system/drivers/pci-bus: device {d} not in the device tree\n", .{bridge_id});
return false; return false;
}; };
// Resource 0 is the ECAM window (1 MiB of config space per bus); the bus // Resource 0 is the ECAM window (1 MiB of config space per bus); the bus
// range rides beside it. The MMIO apertures (M19.0) come after both. // range rides beside it. The MMIO apertures (M19.0) come after both.
if (descriptor.resource_count < 2 or descriptor.resources[0].kind != @intFromEnum(device.ResourceKind.memory)) { if (descriptor.resource_count < 2 or descriptor.resources[0].kind != @intFromEnum(device.ResourceKind.memory)) {
_ = runtime.system.write("pci-bus: bridge has no ECAM window\n"); _ = runtime.system.write("/system/drivers/pci-bus: bridge has no ECAM window\n");
return false; return false;
} }
const bus_range = for (descriptor.resources[0..@intCast(descriptor.resource_count)]) |resource| { const bus_range = for (descriptor.resources[0..@intCast(descriptor.resource_count)]) |resource| {
if (resource.kind == @intFromEnum(device.ResourceKind.bus_range)) break resource; if (resource.kind == @intFromEnum(device.ResourceKind.bus_range)) break resource;
} else { } else {
_ = runtime.system.write("pci-bus: bridge has no bus range\n"); _ = runtime.system.write("/system/drivers/pci-bus: bridge has no bus range\n");
return false; return false;
}; };
start_bus = bus_range.start; start_bus = bus_range.start;
bus_count = bus_range.len; bus_count = bus_range.len;
ecam_physical = descriptor.resources[0].start; ecam_physical = descriptor.resources[0].start;
ecam_base = device.mmioMap(bridge_id, 0) orelse { ecam_base = device.mmioMap(bridge_id, 0) orelse {
_ = runtime.system.write("pci-bus: ECAM mmio_map failed\n"); _ = runtime.system.write("/system/drivers/pci-bus: ECAM mmio_map failed\n");
return false; return false;
}; };
@@ -116,17 +116,17 @@ fn initialise(endpoint: runtime.ipc.Handle) bool {
if (manager == null) runtime.system.sleep(20); if (manager == null) runtime.system.sleep(20);
} }
const h = manager orelse { const h = manager orelse {
_ = runtime.system.write("pci-bus: no device manager to hello\n"); _ = runtime.system.write("/system/drivers/pci-bus: no device manager to hello\n");
return false; return false;
}; };
const hello = protocol.Hello{ .role = @intFromEnum(protocol.Role.bus), .device_id = bridge_id }; const hello = protocol.Hello{ .role = @intFromEnum(protocol.Role.bus), .device_id = bridge_id };
var reply: [protocol.message_maximum]u8 = undefined; var reply: [protocol.message_maximum]u8 = undefined;
const n = runtime.ipc.call(h, std.mem.asBytes(&hello), &reply) catch { const n = runtime.ipc.call(h, std.mem.asBytes(&hello), &reply) catch {
_ = runtime.system.write("pci-bus: hello call failed\n"); _ = runtime.system.write("/system/drivers/pci-bus: hello call failed\n");
return false; return false;
}; };
if (n < protocol.reply_size or std.mem.bytesToValue(protocol.HelloReply, reply[0..protocol.reply_size]).status != 0) { if (n < protocol.reply_size or std.mem.bytesToValue(protocol.HelloReply, reply[0..protocol.reply_size]).status != 0) {
_ = runtime.system.write("pci-bus: hello refused\n"); _ = runtime.system.write("/system/drivers/pci-bus: hello refused\n");
return false; return false;
} }
manager_handle = h; manager_handle = h;
@@ -159,7 +159,7 @@ fn scan() void {
} }
} }
} }
writeLine("pci-bus: {d} functions found\n", .{found}); writeLine("/system/drivers/pci-bus: {d} functions found\n", .{found});
} }
/// Register one function under the bridge and report it to the manager. The /// Register one function under the bridge and report it to the manager. The
@@ -229,7 +229,7 @@ fn registerAndReport(bus: u64, dev: u64, function: u64, class_triple: u32) void
} }
const registered = device.register(bridge_id, &descriptor) orelse { const registered = device.register(bridge_id, &descriptor) orelse {
writeLine("pci-bus: register refused for {d}:{d}.{d}\n", .{ bus, dev, function }); writeLine("/system/drivers/pci-bus: register refused for {d}:{d}.{d}\n", .{ bus, dev, function });
return; return;
}; };
const report = protocol.ChildAdded{ const report = protocol.ChildAdded{
@@ -240,7 +240,7 @@ fn registerAndReport(bus: u64, dev: u64, function: u64, class_triple: u32) void
}; };
var reply: [protocol.message_maximum]u8 = undefined; var reply: [protocol.message_maximum]u8 = undefined;
_ = runtime.ipc.call(manager_handle, std.mem.asBytes(&report), &reply) catch { _ = runtime.ipc.call(manager_handle, std.mem.asBytes(&report), &reply) catch {
writeLine("pci-bus: child report for {d}:{d}.{d} failed\n", .{ bus, dev, function }); writeLine("/system/drivers/pci-bus: child report for {d}:{d}.{d} failed\n", .{ bus, dev, function });
}; };
} }
@@ -255,7 +255,7 @@ fn onMessage(message: []const u8, reply: []u8, sender: u32, capability: ?runtime
pub fn main(init: runtime.process.Init) void { pub fn main(init: runtime.process.Init) void {
const argument = init.arguments.get(1) orelse return; // bare (ramdisk sweep): stay silent const argument = init.arguments.get(1) orelse return; // bare (ramdisk sweep): stay silent
bridge_id = std.fmt.parseInt(u64, argument, 10) catch { bridge_id = std.fmt.parseInt(u64, argument, 10) catch {
writeLine("pci-bus: malformed bridge device id '{s}'\n", .{argument}); writeLine("/system/drivers/pci-bus: malformed bridge device id '{s}'\n", .{argument});
return; return;
}; };
runtime.service.run(protocol.message_maximum, .{ runtime.service.run(protocol.message_maximum, .{
+11 -11
View File
@@ -72,17 +72,17 @@ fn modifierWord(modifiers: scancode.ModifierSnapshot) u32 {
pub fn main(init: runtime.process.Init) void { pub fn main(init: runtime.process.Init) void {
const hid = init.arguments.get(1).?; const hid = init.arguments.get(1).?;
if (hid.len == 0) { if (hid.len == 0) {
_ = runtime.system.write("system/drivers/ps2-bus/keyboard: no HID argument\n"); _ = runtime.system.write("/system/drivers/ps2-bus/keyboard: no HID argument\n");
return; return;
} }
writeLine("system/drivers/ps2-bus/keyboard: starting for hid {s}\n", .{hid}); writeLine("/system/drivers/ps2-bus/keyboard: starting for hid {s}\n", .{hid});
const buffer = runtime.allocator().alloc(device.DeviceDescriptor, 64) catch { const buffer = runtime.allocator().alloc(device.DeviceDescriptor, 64) catch {
_ = runtime.system.write("system/drivers/ps2-bus/keyboard: out of memory\n"); _ = runtime.system.write("/system/drivers/ps2-bus/keyboard: out of memory\n");
return; return;
}; };
if (device.findDeviceDescriptorByHid(buffer, hid) == null) { if (device.findDeviceDescriptorByHid(buffer, hid) == null) {
writeLine("system/drivers/ps2-bus/keyboard: no device for hid {s}\n", .{hid}); writeLine("/system/drivers/ps2-bus/keyboard: no device for hid {s}\n", .{hid});
return; return;
} }
@@ -90,38 +90,38 @@ pub fn main(init: runtime.process.Init) void {
// absent (as today) it defaults to us. // absent (as today) it defaults to us.
const layout_name = init.arguments.get(2) orelse "us"; const layout_name = init.arguments.get(2) orelse "us";
const layout = xkb.byName(layout_name) orelse xkb.us; const layout = xkb.byName(layout_name) orelse xkb.us;
writeLine("system/drivers/ps2-bus/keyboard: layout {s}\n", .{layout.name}); writeLine("/system/drivers/ps2-bus/keyboard: layout {s}\n", .{layout.name});
// Attach to the bus: hand it our endpoint, and it forwards every byte the // Attach to the bus: hand it our endpoint, and it forwards every byte the
// keyboard sends (it owns the controller; we own the decoding). // keyboard sends (it owns the controller; we own the decoding).
const bus = lookupBus() orelse { const bus = lookupBus() orelse {
_ = runtime.system.write("system/drivers/ps2-bus/keyboard: ps2-bus service unavailable\n"); _ = runtime.system.write("/system/drivers/ps2-bus/keyboard: ps2-bus service unavailable\n");
return; return;
}; };
const endpoint = ipc.createIpcEndpoint() orelse { const endpoint = ipc.createIpcEndpoint() orelse {
_ = runtime.system.write("system/drivers/ps2-bus/keyboard: no endpoint\n"); _ = runtime.system.write("/system/drivers/ps2-bus/keyboard: no endpoint\n");
return; return;
}; };
var attach = ps2.AttachRequest{ .device_type = @intFromEnum(ps2.DeviceType.keyboard) }; var attach = ps2.AttachRequest{ .device_type = @intFromEnum(ps2.DeviceType.keyboard) };
var attach_reply: [@sizeOf(ps2.AttachReply)]u8 = undefined; var attach_reply: [@sizeOf(ps2.AttachReply)]u8 = undefined;
const attached = ipc.callCap(bus, std.mem.asBytes(&attach), &attach_reply, endpoint) catch { const attached = ipc.callCap(bus, std.mem.asBytes(&attach), &attach_reply, endpoint) catch {
_ = runtime.system.write("system/drivers/ps2-bus/keyboard: attach call failed\n"); _ = runtime.system.write("/system/drivers/ps2-bus/keyboard: attach call failed\n");
return; return;
}; };
if (attached.len < @sizeOf(ps2.AttachReply) or if (attached.len < @sizeOf(ps2.AttachReply) or
std.mem.bytesToValue(ps2.AttachReply, attach_reply[0..@sizeOf(ps2.AttachReply)]).status != @intFromEnum(ps2.AttachStatus.ok)) std.mem.bytesToValue(ps2.AttachReply, attach_reply[0..@sizeOf(ps2.AttachReply)]).status != @intFromEnum(ps2.AttachStatus.ok))
{ {
_ = runtime.system.write("system/drivers/ps2-bus/keyboard: attach refused\n"); _ = runtime.system.write("/system/drivers/ps2-bus/keyboard: attach refused\n");
return; return;
} }
// Broadcast keyboard events through the input service so programs can listen // Broadcast keyboard events through the input service so programs can listen
// for them (docs/input.md). // for them (docs/input.md).
var source = runtime.input.connectSource() orelse { var source = runtime.input.connectSource() orelse {
_ = runtime.system.write("system/drivers/ps2-bus/keyboard: input service unavailable\n"); _ = runtime.system.write("/system/drivers/ps2-bus/keyboard: input service unavailable\n");
return; return;
}; };
_ = runtime.system.write("system/drivers/ps2-bus/keyboard: ok\n"); _ = runtime.system.write("/system/drivers/ps2-bus/keyboard: ok\n");
var decoder = scancode.Decoder{}; var decoder = scancode.Decoder{};
var state = scancode.KeyboardState{}; var state = scancode.KeyboardState{};
+10 -10
View File
@@ -51,50 +51,50 @@ pub fn main(init: runtime.process.Init) void {
const hid = init.arguments.get(1).?; const hid = init.arguments.get(1).?;
if (hid.len == 0) { if (hid.len == 0) {
_ = runtime.system.write("system/drivers/ps2-bus/mouse: no HID argument\n"); _ = runtime.system.write("/system/drivers/ps2-bus/mouse: no HID argument\n");
return; return;
} }
writeLine("system/drivers/ps2-bus/mouse: starting for hid {s}\n", .{hid}); writeLine("/system/drivers/ps2-bus/mouse: starting for hid {s}\n", .{hid});
const buffer = runtime.allocator().alloc(device.DeviceDescriptor, 64) catch { const buffer = runtime.allocator().alloc(device.DeviceDescriptor, 64) catch {
_ = runtime.system.write("system/drivers/ps2-bus/mouse: out of memory\n"); _ = runtime.system.write("/system/drivers/ps2-bus/mouse: out of memory\n");
return; return;
}; };
if (device.findDeviceDescriptorByHid(buffer, hid) == null) { if (device.findDeviceDescriptorByHid(buffer, hid) == null) {
writeLine("system/drivers/ps2-bus/mouse: no device for hid {s}\n", .{hid}); writeLine("/system/drivers/ps2-bus/mouse: no device for hid {s}\n", .{hid});
return; return;
} }
// Attach to the bus: hand it our endpoint, and it forwards every byte the // Attach to the bus: hand it our endpoint, and it forwards every byte the
// mouse sends (it owns the controller; we own the decoding). // mouse sends (it owns the controller; we own the decoding).
const bus = lookupBus() orelse { const bus = lookupBus() orelse {
_ = runtime.system.write("system/drivers/ps2-bus/mouse: ps2-bus service unavailable\n"); _ = runtime.system.write("/system/drivers/ps2-bus/mouse: ps2-bus service unavailable\n");
return; return;
}; };
const endpoint = ipc.createIpcEndpoint() orelse { const endpoint = ipc.createIpcEndpoint() orelse {
_ = runtime.system.write("system/drivers/ps2-bus/mouse: no endpoint\n"); _ = runtime.system.write("/system/drivers/ps2-bus/mouse: no endpoint\n");
return; return;
}; };
var attach = ps2.AttachRequest{ .device_type = @intFromEnum(ps2.DeviceType.mouse) }; var attach = ps2.AttachRequest{ .device_type = @intFromEnum(ps2.DeviceType.mouse) };
var attach_reply: [@sizeOf(ps2.AttachReply)]u8 = undefined; var attach_reply: [@sizeOf(ps2.AttachReply)]u8 = undefined;
const attached = ipc.callCap(bus, std.mem.asBytes(&attach), &attach_reply, endpoint) catch { const attached = ipc.callCap(bus, std.mem.asBytes(&attach), &attach_reply, endpoint) catch {
_ = runtime.system.write("system/drivers/ps2-bus/mouse: attach call failed\n"); _ = runtime.system.write("/system/drivers/ps2-bus/mouse: attach call failed\n");
return; return;
}; };
if (attached.len < @sizeOf(ps2.AttachReply) or if (attached.len < @sizeOf(ps2.AttachReply) or
std.mem.bytesToValue(ps2.AttachReply, attach_reply[0..@sizeOf(ps2.AttachReply)]).status != @intFromEnum(ps2.AttachStatus.ok)) std.mem.bytesToValue(ps2.AttachReply, attach_reply[0..@sizeOf(ps2.AttachReply)]).status != @intFromEnum(ps2.AttachStatus.ok))
{ {
_ = runtime.system.write("system/drivers/ps2-bus/mouse: attach refused\n"); _ = runtime.system.write("/system/drivers/ps2-bus/mouse: attach refused\n");
return; return;
} }
// Broadcast mouse events through the input service so programs can listen // Broadcast mouse events through the input service so programs can listen
// for them (docs/input.md). // for them (docs/input.md).
var source = runtime.input.connectSource() orelse { var source = runtime.input.connectSource() orelse {
_ = runtime.system.write("system/drivers/ps2-bus/mouse: input service unavailable\n"); _ = runtime.system.write("/system/drivers/ps2-bus/mouse: input service unavailable\n");
return; return;
}; };
_ = runtime.system.write("system/drivers/ps2-bus/mouse: ok\n"); _ = runtime.system.write("/system/drivers/ps2-bus/mouse: ok\n");
var assembler = mouse_packet.Assembler{}; var assembler = mouse_packet.Assembler{};
var buttons: u32 = 0; var buttons: u32 = 0;
+32 -32
View File
@@ -30,19 +30,19 @@ fn writeLine(comptime fmt: []const u8, arguments: anytype) void {
/// attaches, or null if nothing was spawned. /// attaches, or null if nothing was spawned.
fn spawnIdentifiedDriver(controller: ps2.Controller, port: ps2.Port) ?ps2.DeviceType { fn spawnIdentifiedDriver(controller: ps2.Controller, port: ps2.Port) ?ps2.DeviceType {
const device_type = controller.identifyDevice(port) orelse { const device_type = controller.identifyDevice(port) orelse {
writeLine("system/drivers/ps2-bus: identify timed out on port {s}\n", .{@tagName(port)}); writeLine("/system/drivers/ps2-bus: identify timed out on port {s}\n", .{@tagName(port)});
return null; return null;
}; };
const driver_name = device_type.driverName() orelse { const driver_name = device_type.driverName() orelse {
writeLine("system/drivers/ps2-bus: unrecognized device on port {s}\n", .{@tagName(port)}); writeLine("/system/drivers/ps2-bus: unrecognized device on port {s}\n", .{@tagName(port)});
return null; return null;
}; };
const hid = device_type.hid() orelse ""; const hid = device_type.hid() orelse "";
if (runtime.system.spawnWithArguments(driver_name, &.{hid}) != null) { 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 }); writeLine("/system/drivers/ps2-bus: port {s} is a {s}, spawned {s}\n", .{ @tagName(port), hid, driver_name });
return device_type; return device_type;
} }
writeLine("system/drivers/ps2-bus: failed to spawn {s}\n", .{driver_name}); writeLine("/system/drivers/ps2-bus: failed to spawn {s}\n", .{driver_name});
return null; return null;
} }
@@ -83,7 +83,7 @@ fn handleAttach(message: []const u8, got: ipc.Received, out: []u8) usize {
const device_type = maybe_type orelse continue; const device_type = maybe_type orelse continue;
if (@intFromEnum(device_type) != request.device_type) continue; if (@intFromEnum(device_type) != request.device_type) continue;
port_endpoints[port_index] = endpoint; port_endpoints[port_index] = endpoint;
writeLine("system/drivers/ps2-bus: {s} driver attached\n", .{@tagName(device_type)}); writeLine("/system/drivers/ps2-bus: {s} driver attached\n", .{@tagName(device_type)});
return reply.write(out, .ok); return reply.write(out, .ok);
} }
return reply.write(out, .no_such_device); return reply.write(out, .no_such_device);
@@ -91,7 +91,7 @@ fn handleAttach(message: []const u8, got: ipc.Received, out: []u8) usize {
pub fn main() void { pub fn main() void {
const buffer = runtime.allocator().alloc(device.DeviceDescriptor, 64) catch { const buffer = runtime.allocator().alloc(device.DeviceDescriptor, 64) catch {
_ = runtime.system.write("system/drivers/ps2-bus: out of memory\n"); _ = runtime.system.write("/system/drivers/ps2-bus: out of memory\n");
return; return;
}; };
@@ -103,16 +103,16 @@ pub fn main() void {
// is on which port is decided later by identify, not by this HID. // is on which port is decided later by identify, not by this HID.
const maybe_controller_device_descriptor = device.findDeviceDescriptorByHid(buffer, acpi_ids.HardwareId.ps2_keyboard.hid()); const maybe_controller_device_descriptor = device.findDeviceDescriptorByHid(buffer, acpi_ids.HardwareId.ps2_keyboard.hid());
if (maybe_controller_device_descriptor) |controller_device_descriptor| { if (maybe_controller_device_descriptor) |controller_device_descriptor| {
_ = runtime.system.write("system/drivers/ps2-bus: found PS/2 controller\n"); _ = runtime.system.write("/system/drivers/ps2-bus: found PS/2 controller\n");
_ = runtime.system.write("system/drivers/ps2-bus: initializing controller\n"); _ = runtime.system.write("/system/drivers/ps2-bus: initializing controller\n");
if (!device.claim(controller_device_descriptor.id)) { if (!device.claim(controller_device_descriptor.id)) {
_ = runtime.system.write("system/drivers/ps2-bus: unable to claim controller \n"); _ = runtime.system.write("/system/drivers/ps2-bus: unable to claim controller \n");
return; return;
} }
const controller = ps2.Controller.init(controller_device_descriptor) orelse { const controller = ps2.Controller.init(controller_device_descriptor) orelse {
_ = runtime.system.write("system/drivers/ps2-bus: controller is missing its IO ports\n"); _ = runtime.system.write("/system/drivers/ps2-bus: controller is missing its IO ports\n");
return; return;
}; };
maybe_controller = controller; maybe_controller = controller;
@@ -123,7 +123,7 @@ pub fn main() void {
controller.flushOutputBuffer(); controller.flushOutputBuffer();
const current = controller.readConfigurationByte() orelse { const current = controller.readConfigurationByte() orelse {
_ = runtime.system.write("system/drivers/ps2-bus: controller configuration timed out\n"); _ = runtime.system.write("/system/drivers/ps2-bus: controller configuration timed out\n");
return; return;
}; };
@@ -132,49 +132,49 @@ pub fn main() void {
ps2.configuration_first_port_translation); ps2.configuration_first_port_translation);
if (controller.writeConfigurationByte(update) == null) { if (controller.writeConfigurationByte(update) == null) {
_ = runtime.system.write("system/drivers/ps2-bus: controller configuration timed out\n"); _ = runtime.system.write("/system/drivers/ps2-bus: controller configuration timed out\n");
return; return;
} }
if (controller.performSelfTest()) |reply| { if (controller.performSelfTest()) |reply| {
if (reply != ps2.response_controller_test_passed) { if (reply != ps2.response_controller_test_passed) {
_ = runtime.system.write("system/drivers/ps2-bus: perform controller self test failed\n"); _ = runtime.system.write("/system/drivers/ps2-bus: perform controller self test failed\n");
return; return;
} }
} else { } else {
_ = runtime.system.write("system/drivers/ps2-bus: controller self test timed out\n"); _ = runtime.system.write("/system/drivers/ps2-bus: controller self test timed out\n");
return; return;
} }
has_two_channels = controller.hasTwoChannels() orelse { has_two_channels = controller.hasTwoChannels() orelse {
_ = runtime.system.write("system/drivers/ps2-bus: controller channels timed out\n"); _ = runtime.system.write("/system/drivers/ps2-bus: controller channels timed out\n");
return; return;
}; };
if (has_two_channels) { if (has_two_channels) {
_ = runtime.system.write("system/drivers/ps2-bus: has two channels\n"); _ = runtime.system.write("/system/drivers/ps2-bus: has two channels\n");
// keep the bus quiet until we have tested the ports and are ready to use them // keep the bus quiet until we have tested the ports and are ready to use them
controller.disablePort(.two); controller.disablePort(.two);
} else { } else {
_ = runtime.system.write("system/drivers/ps2-bus: has one channel\n"); _ = runtime.system.write("/system/drivers/ps2-bus: has one channel\n");
} }
// interface tests: always test port 1, test port 2 only if it exists // interface tests: always test port 1, test port 2 only if it exists
const port_one_works = (controller.testPort(.one) orelse { const port_one_works = (controller.testPort(.one) orelse {
_ = runtime.system.write("system/drivers/ps2-bus: port 1 test timed out\n"); _ = runtime.system.write("/system/drivers/ps2-bus: port 1 test timed out\n");
return; return;
}) == ps2.response_port_test_passed; }) == ps2.response_port_test_passed;
var port_two_works = false; var port_two_works = false;
if (has_two_channels) { if (has_two_channels) {
port_two_works = (controller.testPort(.two) orelse { port_two_works = (controller.testPort(.two) orelse {
_ = runtime.system.write("system/drivers/ps2-bus: port 2 test timed out\n"); _ = runtime.system.write("/system/drivers/ps2-bus: port 2 test timed out\n");
return; return;
}) == ps2.response_port_test_passed; }) == ps2.response_port_test_passed;
} }
if (!port_one_works and !port_two_works) { if (!port_one_works and !port_two_works) {
_ = runtime.system.write("system/drivers/ps2-bus: no usable ports\n"); _ = runtime.system.write("/system/drivers/ps2-bus: no usable ports\n");
return; return;
} }
@@ -188,16 +188,16 @@ pub fn main() void {
// abort bring-up of the other one // abort bring-up of the other one
if (port_one_works) { if (port_one_works) {
if (controller.resetDevice(.one)) |passed| { if (controller.resetDevice(.one)) |passed| {
if (!passed) _ = runtime.system.write("system/drivers/ps2-bus: port 1 device reset failed\n"); if (!passed) _ = runtime.system.write("/system/drivers/ps2-bus: port 1 device reset failed\n");
} else { } else {
_ = runtime.system.write("system/drivers/ps2-bus: port 1 device reset timed out\n"); _ = runtime.system.write("/system/drivers/ps2-bus: port 1 device reset timed out\n");
} }
} }
if (port_two_works) { if (port_two_works) {
if (controller.resetDevice(.two)) |passed| { if (controller.resetDevice(.two)) |passed| {
if (!passed) _ = runtime.system.write("system/drivers/ps2-bus: port 2 device reset failed\n"); if (!passed) _ = runtime.system.write("/system/drivers/ps2-bus: port 2 device reset failed\n");
} else { } else {
_ = runtime.system.write("system/drivers/ps2-bus: port 2 device reset timed out\n"); _ = runtime.system.write("/system/drivers/ps2-bus: port 2 device reset timed out\n");
} }
} }
@@ -207,13 +207,13 @@ pub fn main() void {
if (port_one_works) port_device_types[@intFromEnum(ps2.Port.one)] = spawnIdentifiedDriver(controller, .one); if (port_one_works) port_device_types[@intFromEnum(ps2.Port.one)] = spawnIdentifiedDriver(controller, .one);
if (port_two_works) port_device_types[@intFromEnum(ps2.Port.two)] = spawnIdentifiedDriver(controller, .two); if (port_two_works) port_device_types[@intFromEnum(ps2.Port.two)] = spawnIdentifiedDriver(controller, .two);
} else { } else {
_ = runtime.system.write("system/drivers/ps2-bus: no PS/2 controller found\n"); _ = runtime.system.write("/system/drivers/ps2-bus: no PS/2 controller found\n");
return; return;
} }
const controller = maybe_controller.?; const controller = maybe_controller.?;
const interrupt_index = maybe_interrupt_index orelse { const interrupt_index = maybe_interrupt_index orelse {
_ = runtime.system.write("system/drivers/ps2-bus: controller is missing its IRQ\n"); _ = runtime.system.write("/system/drivers/ps2-bus: controller is missing its IRQ\n");
return; return;
}; };
@@ -221,11 +221,11 @@ pub fn main() void {
// well-known id so the children can find it, the way input subscribers find // well-known id so the children can find it, the way input subscribers find
// the input service. // the input service.
const endpoint = ipc.createIpcEndpoint() orelse { const endpoint = ipc.createIpcEndpoint() orelse {
_ = runtime.system.write("system/drivers/ps2-bus: no endpoint\n"); _ = runtime.system.write("/system/drivers/ps2-bus: no endpoint\n");
return; return;
}; };
if (!ipc.register(.ps2_bus, endpoint)) { if (!ipc.register(.ps2_bus, endpoint)) {
_ = runtime.system.write("system/drivers/ps2-bus: register failed\n"); _ = runtime.system.write("/system/drivers/ps2-bus: register failed\n");
return; return;
} }
@@ -234,7 +234,7 @@ pub fn main() void {
// let the controller raise them — an interrupt with nobody bound is lost. // let the controller raise them — an interrupt with nobody bound is lost.
controller.drainOutputBuffer(); controller.drainOutputBuffer();
if (!device.irqBind(controller.device_id, interrupt_index, endpoint)) { if (!device.irqBind(controller.device_id, interrupt_index, endpoint)) {
_ = runtime.system.write("system/drivers/ps2-bus: irq_bind failed\n"); _ = runtime.system.write("/system/drivers/ps2-bus: irq_bind failed\n");
return; return;
} }
@@ -253,21 +253,21 @@ pub fn main() void {
.gsi = descriptor.resources[auxiliary_index].start, .gsi = descriptor.resources[auxiliary_index].start,
}; };
} else { } else {
_ = runtime.system.write("system/drivers/ps2-bus: auxiliary irq_bind failed\n"); _ = runtime.system.write("/system/drivers/ps2-bus: auxiliary irq_bind failed\n");
} }
} }
} }
} }
var configuration = controller.readConfigurationByte() orelse { var configuration = controller.readConfigurationByte() orelse {
_ = runtime.system.write("system/drivers/ps2-bus: controller configuration timed out\n"); _ = runtime.system.write("/system/drivers/ps2-bus: controller configuration timed out\n");
return; return;
}; };
if (port_device_types[@intFromEnum(ps2.Port.one)] != null) configuration |= ps2.Port.one.interruptBit(); if (port_device_types[@intFromEnum(ps2.Port.one)] != null) configuration |= ps2.Port.one.interruptBit();
if (maybe_auxiliary_interrupt != null) configuration |= ps2.Port.two.interruptBit(); if (maybe_auxiliary_interrupt != null) configuration |= ps2.Port.two.interruptBit();
_ = controller.writeConfigurationByte(configuration); _ = controller.writeConfigurationByte(configuration);
_ = runtime.system.write("system/drivers/ps2-bus: ok\n"); _ = runtime.system.write("/system/drivers/ps2-bus: ok\n");
// The forwarding loop: an IRQ1 notification drains the output buffer, routing // The forwarding loop: an IRQ1 notification drains the output buffer, routing
// each byte to the attached driver of the port it came from; a client message // each byte to the attached driver of the port it came from; a client message
+16 -16
View File
@@ -33,20 +33,20 @@ var controller_id: u64 = protocol.no_device;
fn initialise(endpoint: runtime.ipc.Handle) bool { fn initialise(endpoint: runtime.ipc.Handle) bool {
_ = endpoint; _ = endpoint;
if (!device.claim(controller_id)) { if (!device.claim(controller_id)) {
writeLine("usb-xhci-bus: unable to claim controller device {d}\n", .{controller_id}); writeLine("/system/drivers/usb-xhci-bus: unable to claim controller device {d}\n", .{controller_id});
return false; return false;
} }
// Fetch our own descriptor back for the controller's resources. // Fetch our own descriptor back for the controller's resources.
const buffer = runtime.allocator().alloc(device.DeviceDescriptor, 64) catch { const buffer = runtime.allocator().alloc(device.DeviceDescriptor, 64) catch {
_ = runtime.system.write("usb-xhci-bus: out of memory\n"); _ = runtime.system.write("/system/drivers/usb-xhci-bus: out of memory\n");
return false; return false;
}; };
const total = device.enumerate(buffer); const total = device.enumerate(buffer);
const descriptor = for (buffer[0..@min(total, buffer.len)]) |d| { const descriptor = for (buffer[0..@min(total, buffer.len)]) |d| {
if (d.id == controller_id) break d; if (d.id == controller_id) break d;
} else { } else {
writeLine("usb-xhci-bus: device {d} not in the device tree\n", .{controller_id}); writeLine("/system/drivers/usb-xhci-bus: device {d} not in the device tree\n", .{controller_id});
return false; return false;
}; };
@@ -59,16 +59,16 @@ fn initialise(endpoint: runtime.ipc.Handle) bool {
break resource; break resource;
} }
} else { } else {
writeLine("usb-xhci-bus: controller device {d} has no register BAR\n", .{controller_id}); writeLine("/system/drivers/usb-xhci-bus: controller device {d} has no register BAR\n", .{controller_id});
return false; return false;
}; };
writeLine("usb-xhci-bus: claimed controller device {d} (registers at 0x{x}, {d} bytes)\n", .{ writeLine("/system/drivers/usb-xhci-bus: claimed controller device {d} (registers at 0x{x}, {d} bytes)\n", .{
controller_id, controller_id,
register_window.start, register_window.start,
register_window.len, register_window.len,
}); });
register_base = device.mmioMap(controller_id, register_index) orelse { register_base = device.mmioMap(controller_id, register_index) orelse {
_ = runtime.system.write("usb-xhci-bus: mmio_map failed\n"); _ = runtime.system.write("/system/drivers/usb-xhci-bus: mmio_map failed\n");
return false; return false;
}; };
@@ -81,20 +81,20 @@ fn initialise(endpoint: runtime.ipc.Handle) bool {
if (manager == null) runtime.system.sleep(20); if (manager == null) runtime.system.sleep(20);
} }
const h = manager orelse { const h = manager orelse {
_ = runtime.system.write("usb-xhci-bus: no device manager to hello\n"); _ = runtime.system.write("/system/drivers/usb-xhci-bus: no device manager to hello\n");
return false; return false;
}; };
const hello = protocol.Hello{ .role = @intFromEnum(protocol.Role.bus), .device_id = controller_id }; const hello = protocol.Hello{ .role = @intFromEnum(protocol.Role.bus), .device_id = controller_id };
var reply: [protocol.message_maximum]u8 = undefined; var reply: [protocol.message_maximum]u8 = undefined;
const n = runtime.ipc.call(h, std.mem.asBytes(&hello), &reply) catch { const n = runtime.ipc.call(h, std.mem.asBytes(&hello), &reply) catch {
_ = runtime.system.write("usb-xhci-bus: hello call failed\n"); _ = runtime.system.write("/system/drivers/usb-xhci-bus: hello call failed\n");
return false; return false;
}; };
if (n < protocol.reply_size or std.mem.bytesToValue(protocol.HelloReply, reply[0..protocol.reply_size]).status != 0) { if (n < protocol.reply_size or std.mem.bytesToValue(protocol.HelloReply, reply[0..protocol.reply_size]).status != 0) {
_ = runtime.system.write("usb-xhci-bus: hello refused\n"); _ = runtime.system.write("/system/drivers/usb-xhci-bus: hello refused\n");
return false; return false;
} }
_ = runtime.system.write("usb-xhci-bus: hello acknowledged\n"); _ = runtime.system.write("/system/drivers/usb-xhci-bus: hello acknowledged\n");
scanPorts(h); scanPorts(h);
return true; return true;
@@ -135,7 +135,7 @@ fn scanPorts(manager: runtime.ipc.Handle) void {
const capability_length = readRegister(0) & 0xFF; const capability_length = readRegister(0) & 0xFF;
const structural = readRegister(0x04); const structural = readRegister(0x04);
const maximum_ports: u32 = structural >> 24; const maximum_ports: u32 = structural >> 24;
writeLine("usb-xhci-bus: {d} root-hub ports\n", .{maximum_ports}); writeLine("/system/drivers/usb-xhci-bus: {d} root-hub ports\n", .{maximum_ports});
// PORTSC registers: operational base + 0x400 + 0x10 per port (1-based). // PORTSC registers: operational base + 0x400 + 0x10 per port (1-based).
var port: u32 = 1; var port: u32 = 1;
@@ -145,7 +145,7 @@ fn scanPorts(manager: runtime.ipc.Handle) void {
if (port_status & 1 == 0) continue; // CCS: nothing connected if (port_status & 1 == 0) continue; // CCS: nothing connected
connected += 1; connected += 1;
const speed = (port_status >> 10) & 0xF; // the PORTSC port-speed class const speed = (port_status >> 10) & 0xF; // the PORTSC port-speed class
writeLine("usb-xhci-bus: port {d} connected — {s} (speed class {d})\n", .{ port, speedName(speed), speed }); writeLine("/system/drivers/usb-xhci-bus: port {d} connected — {s} (speed class {d})\n", .{ port, speedName(speed), speed });
const report = protocol.ChildAdded{ const report = protocol.ChildAdded{
.parent = controller_id, .parent = controller_id,
@@ -154,11 +154,11 @@ fn scanPorts(manager: runtime.ipc.Handle) void {
}; };
var reply: [protocol.message_maximum]u8 = undefined; var reply: [protocol.message_maximum]u8 = undefined;
_ = runtime.ipc.call(manager, std.mem.asBytes(&report), &reply) catch { _ = runtime.ipc.call(manager, std.mem.asBytes(&report), &reply) catch {
writeLine("usb-xhci-bus: child report for port {d} failed\n", .{port}); writeLine("/system/drivers/usb-xhci-bus: child report for port {d} failed\n", .{port});
continue; continue;
}; };
} }
if (connected == 0) _ = runtime.system.write("usb-xhci-bus: no devices connected\n"); if (connected == 0) _ = runtime.system.write("/system/drivers/usb-xhci-bus: no devices connected\n");
} }
/// No bus protocol to serve yet — transfer requests arrive with the USB track. /// No bus protocol to serve yet — transfer requests arrive with the USB track.
@@ -172,11 +172,11 @@ fn onMessage(message: []const u8, reply: []u8, sender: u32, capability: ?runtime
pub fn main(init: runtime.process.Init) void { pub fn main(init: runtime.process.Init) void {
const argument = init.arguments.get(1) orelse { const argument = init.arguments.get(1) orelse {
_ = runtime.system.write("usb-xhci-bus: missing controller device id (argv[1])\n"); _ = runtime.system.write("/system/drivers/usb-xhci-bus: missing controller device id (argv[1])\n");
return; return;
}; };
controller_id = std.fmt.parseInt(u64, argument, 10) catch { controller_id = std.fmt.parseInt(u64, argument, 10) catch {
writeLine("usb-xhci-bus: malformed controller device id '{s}'\n", .{argument}); writeLine("/system/drivers/usb-xhci-bus: malformed controller device id '{s}'\n", .{argument});
return; return;
}; };
runtime.service.run(protocol.message_maximum, .{ runtime.service.run(protocol.message_maximum, .{
+26 -26
View File
@@ -77,12 +77,12 @@ fn kmain(boot_information: *const BootInformation) noreturn {
architecture.setFaultHandler(onException); architecture.setFaultHandler(onException);
architecture.init(); architecture.init();
status("danos: initialising kernel...\n"); status("/system/kernel: initialising kernel...\n");
log.write(if (console.present()) log.write(if (console.present())
"danos: framebuffer console online (bootstrap; graphics driver later)\n" "/system/kernel: framebuffer console online (bootstrap; graphics driver later)\n"
else else
"danos: no framebuffer (headless) -> logging to serial/debugcon only\n"); "/system/kernel: no framebuffer (headless) -> logging to serial/debugcon only\n");
log.write("danos: cpu tables online (GDT, IDT, TSS)\n"); log.write("/system/kernel: cpu tables online (GDT, IDT, TSS)\n");
log.print(" resolution : {d}x{d}\n", .{ fb.width, fb.height }); log.print(" resolution : {d}x{d}\n", .{ fb.width, fb.height });
log.print(" pitch : {d} bytes\n", .{fb.pitch}); log.print(" pitch : {d} bytes\n", .{fb.pitch});
log.print(" format : {s}\n", .{@tagName(fb.format)}); log.print(" format : {s}\n", .{@tagName(fb.format)});
@@ -105,7 +105,7 @@ fn kmain(boot_information: *const BootInformation) noreturn {
const total_bytes = total_pages * abi.page_size; const total_bytes = total_pages * abi.page_size;
const gib = 1 << 30; const gib = 1 << 30;
log.write("\ndanos: physical memory\n"); log.write("\n/system/kernel: physical memory\n");
log.print(" total RAM : {d}.{d:0>2} GiB ({d} MiB) - RAM the firmware reported\n", .{ total_bytes / gib, (total_bytes % gib) * 100 / gib, mib(total_pages) }); log.print(" total RAM : {d}.{d:0>2} GiB ({d} MiB) - RAM the firmware reported\n", .{ total_bytes / gib, (total_bytes % gib) * 100 / gib, mib(total_pages) });
log.print(" usable : {d} MiB - free RAM (incl. reclaimed boot-services memory)\n", .{mib(usable_pages)}); log.print(" usable : {d} MiB - free RAM (incl. reclaimed boot-services memory)\n", .{mib(usable_pages)});
log.print(" reserved : {d} MiB - kernel image, boot stack, ACPI, runtime services\n", .{mib(reserved_pages)}); log.print(" reserved : {d} MiB - kernel image, boot stack, ACPI, runtime services\n", .{mib(reserved_pages)});
@@ -119,7 +119,7 @@ fn kmain(boot_information: *const BootInformation) noreturn {
// until SMP bring-up; 0 means none was available (we stay uniprocessor). // until SMP bring-up; 0 means none was available (we stay uniprocessor).
ap_trampoline_page = pmm.allocBelow(0x100000) orelse 0; ap_trampoline_page = pmm.allocBelow(0x100000) orelse 0;
const s1 = pmm.stats(); const s1 = pmm.stats();
log.print("\ndanos: frame allocator online\n", .{}); log.print("\n/system/kernel: frame allocator online\n", .{});
log.print(" free frames: {d} ({d} MiB)\n", .{ s1.free_frames, mib(s1.free_frames) }); log.print(" free frames: {d} ({d} MiB)\n", .{ s1.free_frames, mib(s1.free_frames) });
const f0 = pmm.alloc(); const f0 = pmm.alloc();
const f1 = pmm.alloc(); const f1 = pmm.alloc();
@@ -133,14 +133,14 @@ fn kmain(boot_information: *const BootInformation) noreturn {
// Switch off the firmware's page tables onto our own (with real permissions). // Switch off the firmware's page tables onto our own (with real permissions).
architecture.enablePaging(pmm.alloc, pmm.free, boot_information); architecture.enablePaging(pmm.alloc, pmm.free, boot_information);
log.checkpoint(cp_paging); log.checkpoint(cp_paging);
log.print("\ndanos: paging enabled\n", .{}); log.print("\n/system/kernel: paging enabled\n", .{});
log.print(" page tables: root = 0x{x:0>16}\n", .{architecture.activePageTable()}); log.print(" page tables: root = 0x{x:0>16}\n", .{architecture.activePageTable()});
log.print(" kernel segs: {d} (mapped with W^X permissions)\n", .{boot_information.kernel_segment_count}); log.print(" kernel segs: {d} (mapped with W^X permissions)\n", .{boot_information.kernel_segment_count});
// Bring up the kernel heap (dynamic allocation), built on the VMM. // Bring up the kernel heap (dynamic allocation), built on the VMM.
heap.init(); heap.init();
log.checkpoint(cp_heap); log.checkpoint(cp_heap);
log.write("\ndanos: kernel heap online\n"); log.write("\n/system/kernel: kernel heap online\n");
// Measure the amount of resources the kernel is actually using // Measure the amount of resources the kernel is actually using
const s2 = pmm.stats(); const s2 = pmm.stats();
log.print(" Kernel footprint: {d} KiB\n", .{kib(s1.free_frames - s2.free_frames)}); log.print(" Kernel footprint: {d} KiB\n", .{kib(s1.free_frames - s2.free_frames)});
@@ -156,7 +156,7 @@ fn kmain(boot_information: *const BootInformation) noreturn {
}; };
if (platform.discover(boot_information, heap.allocator(), hal)) |devtree| { if (platform.discover(boot_information, heap.allocator(), hal)) |devtree| {
var device_tree = devtree; var device_tree = devtree;
log.write("\ndanos: device discovery online\n"); log.write("\n/system/kernel: device discovery online\n");
device_tree.dump(log.write); device_tree.dump(log.write);
// Snapshot the device tree for user-space drivers (device_enumerate/claim/ // Snapshot the device tree for user-space drivers (device_enumerate/claim/
@@ -164,7 +164,7 @@ fn kmain(boot_information: *const BootInformation) noreturn {
devices_broker.init(&device_tree); devices_broker.init(&device_tree);
if (devices_broker.dropped > 0) { if (devices_broker.dropped > 0) {
// Otherwise entirely silent: drivers would just never see that hardware. // Otherwise entirely silent: drivers would just never see that hardware.
log.print("danos: WARNING {d} device(s) dropped — table full\n", .{devices_broker.dropped}); log.print("/system/kernel: WARNING {d} device(s) dropped — table full\n", .{devices_broker.dropped});
} }
// Install the device-IRQ trampolines, so a driver's irq_bind has vectors to // Install the device-IRQ trampolines, so a driver's irq_bind has vectors to
@@ -173,7 +173,7 @@ fn kmain(boot_information: *const BootInformation) noreturn {
// Power register map extracted from the FADT + AML, for confidence it parsed. // Power register map extracted from the FADT + AML, for confidence it parsed.
const pw = platform.powerInformation(); const pw = platform.powerInformation();
log.write("danos: power\n"); log.write("/system/kernel: power\n");
log.print(" pm1a_cnt : {s} 0x{x} (width {d})\n", .{ if (pw.pm1a_cnt.mmio) "mmio" else "io", pw.pm1a_cnt.address, pw.pm1a_cnt.width }); log.print(" pm1a_cnt : {s} 0x{x} (width {d})\n", .{ if (pw.pm1a_cnt.mmio) "mmio" else "io", pw.pm1a_cnt.address, pw.pm1a_cnt.width });
if (pw.s5) |s| { if (pw.s5) |s| {
log.print(" S5 slp_typ : a={d} b={d}\n", .{ s.slp_typ_a, s.slp_typ_b }); log.print(" S5 slp_typ : a={d} b={d}\n", .{ s.slp_typ_a, s.slp_typ_b });
@@ -221,7 +221,7 @@ fn kmain(boot_information: *const BootInformation) noreturn {
}); });
if (pinfo.spcr_uart) |u| architecture.serialReconfigure(u.mmio, u.address); if (pinfo.spcr_uart) |u| architecture.serialReconfigure(u.mmio, u.address);
log.write("danos: platform\n"); log.write("/system/kernel: platform\n");
log.print(" 8259 PIC : {s}\n", .{if (pinfo.pic_present) "present" else "absent"}); log.print(" 8259 PIC : {s}\n", .{if (pinfo.pic_present) "present" else "absent"});
log.print(" lapic base : 0x{x}\n", .{pinfo.lapic_base}); log.print(" lapic base : 0x{x}\n", .{pinfo.lapic_base});
log.print(" hpet base : 0x{x}\n", .{hpet_base}); log.print(" hpet base : 0x{x}\n", .{hpet_base});
@@ -237,7 +237,7 @@ fn kmain(boot_information: *const BootInformation) noreturn {
if (platform.cpusDropped() > 0) if (platform.cpusDropped() > 0)
log.print(" cpus : WARNING {d} core(s) beyond pool cap dropped\n", .{platform.cpusDropped()}); log.print(" cpus : WARNING {d} core(s) beyond pool cap dropped\n", .{platform.cpusDropped()});
} else |err| { } else |err| {
log.print("\ndanos: device discovery failed: {s}\n", .{@errorName(err)}); log.print("\n/system/kernel: device discovery failed: {s}\n", .{@errorName(err)});
} }
log.checkpoint(cp_discovery); log.checkpoint(cp_discovery);
@@ -248,14 +248,14 @@ fn kmain(boot_information: *const BootInformation) noreturn {
// Register the current context as the first task before enabling preemption. // Register the current context as the first task before enabling preemption.
scheduler.init(4); scheduler.init(4);
log.checkpoint(cp_scheduler); log.checkpoint(cp_scheduler);
log.write("\ndanos: scheduler online\n"); log.write("\n/system/kernel: scheduler online\n");
// Start the timer and unmask interrupts — the kernel now has a heartbeat, and // Start the timer and unmask interrupts — the kernel now has a heartbeat, and
// the timer preempts among tasks. // the timer preempts among tasks.
architecture.startTimer(); architecture.startTimer();
architecture.enableInterrupts(); architecture.enableInterrupts();
log.checkpoint(cp_timer); log.checkpoint(cp_timer);
log.print("danos: timer online ({d} Hz tick; timer clock {d} MHz, clock {d} MHz; calibrated via {s})\n", .{ architecture.timer_hz, architecture.timerClockHz() / 1_000_000, architecture.clockHz() / 1_000_000, architecture.timerCalibrationSource() }); log.print("/system/kernel: timer online ({d} Hz tick; timer clock {d} MHz, clock {d} MHz; calibrated via {s})\n", .{ architecture.timer_hz, architecture.timerClockHz() / 1_000_000, architecture.clockHz() / 1_000_000, architecture.timerCalibrationSource() });
// Wake the other cores (application processors). A no-op on a single-core // Wake the other cores (application processors). A no-op on a single-core
// machine; on SMP each AP climbs to long mode and reports in (docs/smp.md). // machine; on SMP each AP climbs to long mode and reports in (docs/smp.md).
@@ -269,7 +269,7 @@ fn kmain(boot_information: *const BootInformation) noreturn {
} }
log.checkpoint(cp_running); log.checkpoint(cp_running);
status("kernel initialised.\n"); status("/system/kernel: initialised.\n");
// Publish the initial-ramdisk so user space can `system_spawn` its bundled // Publish the initial-ramdisk so user space can `system_spawn` its bundled
// binaries by name. The kernel no longer launches them itself: init is the // binaries by name. The kernel no longer launches them itself: init is the
@@ -282,10 +282,10 @@ fn kmain(boot_information: *const BootInformation) noreturn {
// manager then discovers the hardware and spawns each driver. init runs on its own // manager then discovers the hardware and spawns each driver. init runs on its own
// address space, preemptively — this boot context becomes the BSP's idle loop. // address space, preemptively — this boot context becomes the BSP's idle loop.
if (boot_information.init_len != 0) { if (boot_information.init_len != 0) {
status("starting /system/services/init...\n"); status("/system/kernel: starting /system/services/init...\n");
const image = @as([*]const u8, @ptrFromInt(boot_handoff.physicalToVirtual(boot_information.init_base)))[0..boot_information.init_len]; const image = @as([*]const u8, @ptrFromInt(boot_handoff.physicalToVirtual(boot_information.init_base)))[0..boot_information.init_len];
process.spawnProcess(image, 4, &.{"/system/services/init"}) catch |err| { process.spawnProcess(image, 4, &.{"/system/services/init"}) catch |err| {
statusPrint("/system/services/init failed to load: {s}\n", .{@errorName(err)}); statusPrint("/system/kernel: /system/services/init failed to load: {s}\n", .{@errorName(err)});
}; };
} else { } else {
status("no /system/services/init on the boot volume.\n"); status("no /system/services/init on the boot volume.\n");
@@ -294,7 +294,7 @@ fn kmain(boot_information: *const BootInformation) noreturn {
// Become the idle task: drop below every real task and halt until an // Become the idle task: drop below every real task and halt until an
// interrupt. The timer keeps preempting into init and any other work. // interrupt. The timer keeps preempting into init and any other work.
scheduler.setPriority(0); scheduler.setPriority(0);
status("\nkernel idle; user space is running.\n"); status("\n/system/kernel: kernel idle; user space is running.\n");
architecture.halt(); architecture.halt();
} }
@@ -321,7 +321,7 @@ fn bringUpSecondaries() void {
// vector addresses it). It's kept for the system's life — armed only during a // vector addresses it). It's kept for the system's life — armed only during a
// wake, inert (zeroed, non-executable) otherwise — so cores can be re-woken later. // wake, inert (zeroed, non-executable) otherwise — so cores can be re-woken later.
if (ap_trampoline_page == 0) { if (ap_trampoline_page == 0) {
log.write("danos: smp: no low page for the AP trampoline; staying uniprocessor\n"); log.write("/system/kernel: smp: no low page for the AP trampoline; staying uniprocessor\n");
return; return;
} }
architecture.setTrampolinePage(ap_trampoline_page); architecture.setTrampolinePage(ap_trampoline_page);
@@ -333,7 +333,7 @@ fn bringUpSecondaries() void {
if (std.mem.eql(u8, tc, "smp-retry")) architecture.testFailNextWakes(1); if (std.mem.eql(u8, tc, "smp-retry")) architecture.testFailNextWakes(1);
} }
log.print("\ndanos: bringing up {d} application processor(s)\n", .{cores.len - 1}); log.print("\n/system/kernel: bringing up {d} application processor(s)\n", .{cores.len - 1});
const maximum_wake_attempts = 3; // a core that misses the first INIT-SIPI-SIPI gets retried const maximum_wake_attempts = 3; // a core that misses the first INIT-SIPI-SIPI gets retried
for (cores[1..], 1..) |core, index| { for (cores[1..], 1..) |core, index| {
const stack = heap.allocator().alloc(u8, parameters.kernel_stack_size) catch { const stack = heap.allocator().alloc(u8, parameters.kernel_stack_size) catch {
@@ -344,7 +344,7 @@ fn bringUpSecondaries() void {
// This core's dedicated fault stack — allocated only now that the core is // This core's dedicated fault stack — allocated only now that the core is
// real, rather than reserved statically for every possible core. // real, rather than reserved statically for every possible core.
const fault_stack = heap.allocator().alloc(u8, architecture.fault_stack_size) catch { const fault_stack = heap.allocator().alloc(u8, architecture.fault_stack_size) catch {
log.print(" cpu apic_id {d}: no fault stack; skipped\n", .{core.apic_id}); log.print("/system/kernel: cpu apic_id {d}: no fault stack; skipped\n", .{core.apic_id});
continue; continue;
}; };
architecture.setFaultStack(index, (@intFromPtr(fault_stack.ptr) + fault_stack.len) & ~@as(usize, 15)); architecture.setFaultStack(index, (@intFromPtr(fault_stack.ptr) + fault_stack.len) & ~@as(usize, 15));
@@ -353,14 +353,14 @@ fn bringUpSecondaries() void {
while (attempt <= maximum_wake_attempts) : (attempt += 1) { while (attempt <= maximum_wake_attempts) : (attempt += 1) {
if (architecture.startSecondary(core.apic_id, stack_top, @intFromPtr(pc), index)) { if (architecture.startSecondary(core.apic_id, stack_top, @intFromPtr(pc), index)) {
pc.online = true; pc.online = true;
log.print(" cpu apic_id {d}: online (attempt {d})\n", .{ core.apic_id, attempt }); log.print("/system/kernel: cpu apic_id {d}: online (attempt {d})\n", .{ core.apic_id, attempt });
break; break;
} }
if (attempt == maximum_wake_attempts) if (attempt == maximum_wake_attempts)
log.print(" cpu apic_id {d}: no response after {d} attempts (parked)\n", .{ core.apic_id, maximum_wake_attempts }); log.print("/system/kernel: cpu apic_id {d}: no response after {d} attempts (parked)\n", .{ core.apic_id, maximum_wake_attempts });
} }
} }
log.print("danos: {d}/{d} cores online\n", .{ scheduler.onlineCount(), cores.len }); log.print("/system/kernel: {d}/{d} cores online\n", .{ scheduler.onlineCount(), cores.len });
} }
/// A user-facing status line: to the diagnostic `log` *and* the on-screen console /// A user-facing status line: to the diagnostic `log` *and* the on-screen console
@@ -427,7 +427,7 @@ fn exitReasonForVector(vector: u64) abi.ExitReason {
fn onException(state: *const architecture.CpuState) noreturn { fn onException(state: *const architecture.CpuState) noreturn {
if (architecture.fromUser(state) and scheduler.currentIsUserProcess() and recoverableFault(state.vector)) { if (architecture.fromUser(state) and scheduler.currentIsUserProcess() and recoverableFault(state.vector)) {
statusPrint("\ndanos: process {d} ({s}) killed by {s} (vector {d}) on core {d}\n", .{ scheduler.currentId(), scheduler.current().name(), architecture.exceptionName(state.vector), state.vector, scheduler.currentCpuIndex() }); statusPrint("\n/system/kernel: process {d} ({s}) killed by {s} (vector {d}) on core {d}\n", .{ scheduler.currentId(), scheduler.current().name(), architecture.exceptionName(state.vector), state.vector, scheduler.currentCpuIndex() });
statusPrint(" error code : 0x{x}\n", .{state.error_code}); statusPrint(" error code : 0x{x}\n", .{state.error_code});
statusPrint(" IP : 0x{x:0>16}\n", .{architecture.instructionPointer(state)}); statusPrint(" IP : 0x{x:0>16}\n", .{architecture.instructionPointer(state)});
if (architecture.faultAddress(state)) |address| statusPrint(" fault addr : 0x{x:0>16}\n", .{address}); if (architecture.faultAddress(state)) |address| statusPrint(" fault addr : 0x{x:0>16}\n", .{address});
+32 -27
View File
@@ -207,6 +207,13 @@ fn eql(a: []const u8, b: []const u8) bool {
return std.mem.eql(u8, a, b); return std.mem.eql(u8, a, b);
} }
/// Whether the captured last-write buffer *contains* `needle`. Markers are
/// matched as substrings, not prefixes, so a service's source-path debug prefix
/// (`system/drivers/hpet: ok`) still satisfies a marker like `hpet: ok`.
fn bufferHas(needle: []const u8) bool {
return std.mem.indexOf(u8, process.write_buffer[0..process.write_len], needle) != null;
}
/// Non-destructive checks of the memory map and frame allocator. /// Non-destructive checks of the memory map and frame allocator.
fn smoke(boot_information: *const BootInformation) void { fn smoke(boot_information: *const BootInformation) void {
log("DANOS-TEST-BEGIN: smoke\n", .{}); log("DANOS-TEST-BEGIN: smoke\n", .{});
@@ -1376,7 +1383,7 @@ fn initTest(boot_information: *const BootInformation) void {
scheduler.setPriority(4); scheduler.setPriority(4);
const prefix = "init: heartbeat"; const prefix = "init: heartbeat";
const beat_ok = process.write_len >= prefix.len and eql(process.write_buffer[0..prefix.len], prefix); const beat_ok = bufferHas(prefix);
check("init produced repeated heartbeats (>=2)", process.write_count >= 2); check("init produced repeated heartbeats (>=2)", process.write_count >= 2);
check("heartbeat text arrived intact", beat_ok); check("heartbeat text arrived intact", beat_ok);
check("heartbeats came from user mode (CPL 3)", process.write_from_user); check("heartbeats came from user mode (CPL 3)", process.write_from_user);
@@ -1638,11 +1645,11 @@ fn vfsClientDeathTest(boot_information: *const BootInformation) void {
scheduler.setPriority(1); scheduler.setPriority(1);
var deadline = architecture.millis() + 10000; var deadline = architecture.millis() + 10000;
while (architecture.millis() < deadline) { while (architecture.millis() < deadline) {
if (process.write_len >= parked.len and eql(process.write_buffer[0..parked.len], parked)) break; if (bufferHas(parked)) break;
scheduler.yield(); scheduler.yield();
} }
scheduler.setPriority(4); scheduler.setPriority(4);
check("client parked holding an open handle", process.write_len >= parked.len and eql(process.write_buffer[0..parked.len], parked)); check("client parked holding an open handle", bufferHas(parked));
check("the kill is accepted", process.killProcess(me, client) == 0); check("the kill is accepted", process.killProcess(me, client) == 0);
var badge: u64 = 0; var badge: u64 = 0;
@@ -1655,11 +1662,11 @@ fn vfsClientDeathTest(boot_information: *const BootInformation) void {
scheduler.setPriority(1); scheduler.setPriority(1);
deadline = architecture.millis() + 10000; deadline = architecture.millis() + 10000;
while (architecture.millis() < deadline) { while (architecture.millis() < deadline) {
if (process.write_len >= released.len and eql(process.write_buffer[0..released.len], released)) break; if (bufferHas(released)) break;
scheduler.yield(); scheduler.yield();
} }
scheduler.setPriority(4); scheduler.setPriority(4);
check("the VFS released the dead client's handle", process.write_len >= released.len and eql(process.write_buffer[0..released.len], released)); check("the VFS released the dead client's handle", bufferHas(released));
result(); result();
} }
@@ -1701,8 +1708,8 @@ fn signalsTest(boot_information: *const BootInformation) void {
var saw_pass = false; var saw_pass = false;
var saw_fail = false; var saw_fail = false;
while (architecture.millis() < deadline and !saw_pass and !saw_fail) { while (architecture.millis() < deadline and !saw_pass and !saw_fail) {
if (process.write_len >= pass_marker.len and eql(process.write_buffer[0..pass_marker.len], pass_marker)) saw_pass = true; if (bufferHas(pass_marker)) saw_pass = true;
if (process.write_len >= fail_marker.len and eql(process.write_buffer[0..fail_marker.len], fail_marker)) saw_fail = true; if (bufferHas(fail_marker)) saw_fail = true;
scheduler.yield(); scheduler.yield();
} }
scheduler.setPriority(4); scheduler.setPriority(4);
@@ -1864,13 +1871,11 @@ fn pciScanTest(boot_information: *const BootInformation) void {
scheduler.setPriority(1); scheduler.setPriority(1);
var deadline = architecture.millis() + 15000; var deadline = architecture.millis() + 15000;
while (architecture.millis() < deadline and reported == 0) { while (architecture.millis() < deadline and reported == 0) {
if (process.write_len > count_prefix.len + count_suffix.len and eql(process.write_buffer[0..count_prefix.len], count_prefix)) {
const line = process.write_buffer[0..process.write_len]; const line = process.write_buffer[0..process.write_len];
const digits_end = std.mem.indexOf(u8, line, count_suffix) orelse { if (std.mem.indexOf(u8, line, count_prefix)) |start| {
scheduler.yield(); if (std.mem.indexOf(u8, line, count_suffix)) |digits_end| {
continue; reported = std.fmt.parseInt(u32, line[start + count_prefix.len .. digits_end], 10) catch 0;
}; }
reported = std.fmt.parseInt(u32, line[count_prefix.len..digits_end], 10) catch 0;
} }
scheduler.yield(); scheduler.yield();
} }
@@ -1894,7 +1899,7 @@ fn pciScanTest(boot_information: *const BootInformation) void {
deadline = architecture.millis() + 15000; deadline = architecture.millis() + 15000;
var restarted = false; var restarted = false;
while (architecture.millis() < deadline and !restarted) { while (architecture.millis() < deadline and !restarted) {
if (process.write_len >= restart_marker.len and eql(process.write_buffer[0..restart_marker.len], restart_marker)) restarted = true; if (bufferHas(restart_marker)) restarted = true;
scheduler.yield(); scheduler.yield();
} }
scheduler.setPriority(4); scheduler.setPriority(4);
@@ -1906,7 +1911,7 @@ fn pciScanTest(boot_information: *const BootInformation) void {
deadline = architecture.millis() + 15000; deadline = architecture.millis() + 15000;
var seen = false; var seen = false;
while (architecture.millis() < deadline and !seen) { while (architecture.millis() < deadline and !seen) {
if (process.write_len >= marker.len and eql(process.write_buffer[0..marker.len], marker)) seen = true; if (bufferHas(marker)) seen = true;
scheduler.yield(); scheduler.yield();
} }
scheduler.setPriority(4); scheduler.setPriority(4);
@@ -2035,12 +2040,12 @@ fn supervisionTest(boot_information: *const BootInformation) void {
scheduler.setPriority(1); scheduler.setPriority(1);
const deadline = architecture.millis() + 10000; const deadline = architecture.millis() + 10000;
while (architecture.millis() < deadline) { while (architecture.millis() < deadline) {
if (process.write_len >= marker.len and eql(process.write_buffer[0..marker.len], marker)) break; if (bufferHas(marker)) break;
scheduler.yield(); scheduler.yield();
} }
scheduler.setPriority(4); scheduler.setPriority(4);
const ok = process.write_len >= marker.len and eql(process.write_buffer[0..marker.len], marker); const ok = bufferHas(marker);
if (!ok and process.write_len > 0) log("DANOS-SUPERVISION: got \"{s}\"\n", .{process.write_buffer[0..process.write_len]}); if (!ok and process.write_len > 0) log("DANOS-SUPERVISION: got \"{s}\"\n", .{process.write_buffer[0..process.write_len]});
check("the supervisor completed every step (spawn/list/kill/notify)", ok); check("the supervisor completed every step (spawn/list/kill/notify)", ok);
check("it ran in user mode (CPL 3)", process.write_from_user); check("it ran in user mode (CPL 3)", process.write_from_user);
@@ -2120,12 +2125,12 @@ fn vfsTest(boot_information: *const BootInformation) void {
scheduler.setPriority(1); scheduler.setPriority(1);
const deadline = architecture.millis() + 10000; const deadline = architecture.millis() + 10000;
while (architecture.millis() < deadline) { while (architecture.millis() < deadline) {
if (process.write_len >= prefix.len and eql(process.write_buffer[0..prefix.len], prefix) and process.write_count >= 2) break; if (bufferHas(prefix) and process.write_count >= 2) break;
scheduler.yield(); scheduler.yield();
} }
scheduler.setPriority(4); scheduler.setPriority(4);
const ok = process.write_len >= prefix.len and eql(process.write_buffer[0..prefix.len], prefix); const ok = bufferHas(prefix);
check("client completed the VFS round trip (open/write/read matched)", ok); check("client completed the VFS round trip (open/write/read matched)", ok);
check("the round trip ran repeatedly (server stays up)", process.write_count >= 2); check("the round trip ran repeatedly (server stays up)", process.write_count >= 2);
check("client syscalls came from user mode (CPL 3)", process.write_from_user); check("client syscalls came from user mode (CPL 3)", process.write_from_user);
@@ -2165,12 +2170,12 @@ fn inputTest(boot_information: *const BootInformation) void {
scheduler.setPriority(1); scheduler.setPriority(1);
const deadline = architecture.millis() + 12000; const deadline = architecture.millis() + 12000;
while (architecture.millis() < deadline) { while (architecture.millis() < deadline) {
if (process.write_len >= prefix.len and eql(process.write_buffer[0..prefix.len], prefix) and process.write_count >= 2) break; if (bufferHas(prefix) and process.write_count >= 2) break;
scheduler.yield(); scheduler.yield();
} }
scheduler.setPriority(4); scheduler.setPriority(4);
const ok = process.write_len >= prefix.len and eql(process.write_buffer[0..prefix.len], prefix); const ok = bufferHas(prefix);
check("a subscriber received a broadcast key event over IPC (source -> service -> subscriber)", ok); check("a subscriber received a broadcast key event over IPC (source -> service -> subscriber)", ok);
check("events kept flowing (service + async send stay up)", process.write_count >= 2); check("events kept flowing (service + async send stay up)", process.write_count >= 2);
check("client syscalls came from user mode (CPL 3)", process.write_from_user); check("client syscalls came from user mode (CPL 3)", process.write_from_user);
@@ -2262,12 +2267,12 @@ fn hpetTest(boot_information: *const BootInformation) void {
scheduler.setPriority(1); scheduler.setPriority(1);
const deadline = architecture.millis() + 10000; const deadline = architecture.millis() + 10000;
while (architecture.millis() < deadline) { while (architecture.millis() < deadline) {
if (process.write_len >= prefix.len and eql(process.write_buffer[0..prefix.len], prefix) and process.write_count >= 2) break; if (bufferHas(prefix) and process.write_count >= 2) break;
scheduler.yield(); scheduler.yield();
} }
scheduler.setPriority(4); scheduler.setPriority(4);
const ok = process.write_len >= prefix.len and eql(process.write_buffer[0..prefix.len], prefix); const ok = bufferHas(prefix);
check("user driver mapped HPET MMIO and was woken by its interrupt", ok); check("user driver mapped HPET MMIO and was woken by its interrupt", ok);
check("driver syscalls came from user mode (CPL 3)", process.write_from_user); check("driver syscalls came from user mode (CPL 3)", process.write_from_user);
check("kernel routed and re-armed the HPET's line at the I/O APIC", hpetRouteOk()); check("kernel routed and re-armed the HPET's line at the I/O APIC", hpetRouteOk());
@@ -2368,12 +2373,12 @@ fn busTest(boot_information: *const BootInformation) void {
scheduler.setPriority(1); scheduler.setPriority(1);
const deadline = architecture.millis() + 10000; const deadline = architecture.millis() + 10000;
while (architecture.millis() < deadline) { while (architecture.millis() < deadline) {
if (process.write_len >= prefix.len and eql(process.write_buffer[0..prefix.len], prefix)) break; if (bufferHas(prefix)) break;
scheduler.yield(); scheduler.yield();
} }
scheduler.setPriority(4); scheduler.setPriority(4);
const ok = process.write_len >= prefix.len and eql(process.write_buffer[0..prefix.len], prefix); const ok = bufferHas(prefix);
check("bus driver published children and the kernel refused an out-of-window one", ok); check("bus driver published children and the kernel refused an out-of-window one", ok);
check("driver syscalls came from user mode (CPL 3)", process.write_from_user); check("driver syscalls came from user mode (CPL 3)", process.write_from_user);
check("every registered child is contained in its parent", childrenContained()); check("every registered child is contained in its parent", childrenContained());
@@ -2417,12 +2422,12 @@ fn deviceManagerTest(boot_information: *const BootInformation) void {
scheduler.setPriority(1); scheduler.setPriority(1);
const deadline = architecture.millis() + 10000; const deadline = architecture.millis() + 10000;
while (architecture.millis() < deadline) { while (architecture.millis() < deadline) {
if (process.write_len >= prefix.len and eql(process.write_buffer[0..prefix.len], prefix)) break; if (bufferHas(prefix)) break;
scheduler.yield(); scheduler.yield();
} }
scheduler.setPriority(4); scheduler.setPriority(4);
const ok = process.write_len >= prefix.len and eql(process.write_buffer[0..prefix.len], prefix); const ok = bufferHas(prefix);
check("device manager matched the timer and system_spawn'd hpet, which came up", ok); check("device manager matched the timer and system_spawn'd hpet, which came up", ok);
check("its syscalls came from user mode (CPL 3)", process.write_from_user); check("its syscalls came from user mode (CPL 3)", process.write_from_user);
result(); result();
+10 -10
View File
@@ -72,16 +72,16 @@ pub fn main(init: runtime.process.Init) void {
const expected: ?usize = if (init.arguments.get(1)) |a| (std.fmt.parseInt(usize, a, 10) catch null) else null; const expected: ?usize = if (init.arguments.get(1)) |a| (std.fmt.parseInt(usize, a, 10) catch null) else null;
const buffer = runtime.allocator().alloc(device.DeviceDescriptor, 64) catch { const buffer = runtime.allocator().alloc(device.DeviceDescriptor, 64) catch {
_ = runtime.system.write("acpi: out of memory\n"); _ = runtime.system.write("/system/services/acpi: out of memory\n");
return; return;
}; };
const node = findTablesNode(buffer) orelse { const node = findTablesNode(buffer) orelse {
_ = runtime.system.write("acpi: no acpi-tables node to claim\n"); _ = runtime.system.write("/system/services/acpi: no acpi-tables node to claim\n");
return; return;
}; };
node_id = node.id; node_id = node.id;
if (!device.claim(node_id)) { if (!device.claim(node_id)) {
_ = runtime.system.write("acpi: unable to claim acpi-tables\n"); _ = runtime.system.write("/system/services/acpi: unable to claim acpi-tables\n");
return; return;
} }
@@ -103,17 +103,17 @@ pub fn main(init: runtime.process.Init) void {
if (block_count == blocks.len) break; if (block_count == blocks.len) break;
} }
if (block_count == 0) { if (block_count == 0) {
_ = runtime.system.write("acpi: no AML blobs on the node\n"); _ = runtime.system.write("/system/services/acpi: no AML blobs on the node\n");
return; return;
} }
const result = aml.parse(runtime.allocator(), blocks[0..block_count]) catch { const result = aml.parse(runtime.allocator(), blocks[0..block_count]) catch {
_ = runtime.system.write("acpi: AML parse failed\n"); _ = runtime.system.write("/system/services/acpi: AML parse failed\n");
return; return;
}; };
var namespace = result.namespace; var namespace = result.namespace;
const devices = aml.deviceCount(&namespace); const devices = aml.deviceCount(&namespace);
writeLine("acpi: parsed {d} AML blob(s), {d} namespace devices\n", .{ block_count, devices }); writeLine("/system/services/acpi: parsed {d} AML blob(s), {d} namespace devices\n", .{ block_count, devices });
if (expected) |want| { if (expected) |want| {
if (devices == want) { if (devices == want) {
_ = runtime.system.write("acpi-parse: ok\n"); _ = runtime.system.write("acpi-parse: ok\n");
@@ -150,9 +150,9 @@ pub fn main(init: runtime.process.Init) void {
const hid = entry.hid[0..entry.hid_len]; const hid = entry.hid[0..entry.hid_len];
const desc = acpi_ids.description(hid); const desc = acpi_ids.description(hid);
if (desc.len != 0) if (desc.len != 0)
writeLine("acpi: reported {s} (device {d}, {d} resources) — {s}\n", .{ hid, entry.device_id, entry.resource_count, desc }) writeLine("/system/services/acpi: reported {s} (device {d}, {d} resources) — {s}\n", .{ hid, entry.device_id, entry.resource_count, desc })
else else
writeLine("acpi: reported {s} (device {d}, {d} resources)\n", .{ hid, entry.device_id, entry.resource_count }); writeLine("/system/services/acpi: reported {s} (device {d}, {d} resources)\n", .{ hid, entry.device_id, entry.resource_count });
if (manager) |h| { if (manager) |h| {
var report = protocol.ChildAdded{ var report = protocol.ChildAdded{
.parent = node_id, .parent = node_id,
@@ -165,7 +165,7 @@ pub fn main(init: runtime.process.Init) void {
_ = runtime.ipc.call(h, std.mem.asBytes(&report), &reply) catch {}; _ = runtime.ipc.call(h, std.mem.asBytes(&report), &reply) catch {};
} }
} }
writeLine("acpi: reported {d} device(s) to the manager\n", .{registered_count}); writeLine("/system/services/acpi: reported {d} device(s) to the manager\n", .{registered_count});
// Stay resident: the claim holds, and the service is here to grow into the // Stay resident: the claim holds, and the service is here to grow into the
// supervised discoverer (M20.3, then the M21 event side on the SCI). // supervised discoverer (M20.3, then the M21 event side on the SCI).
@@ -207,7 +207,7 @@ fn registerDevice(node: *aml.Node, hid: [8]u8, interpreter: *aml.Interpreter) vo
applyCrs(&descriptor, node, interpreter); applyCrs(&descriptor, node, interpreter);
const id = device.register(node_id, &descriptor) orelse { const id = device.register(node_id, &descriptor) orelse {
writeLine("acpi: register refused for {s}\n", .{hid[0..@intCast(hid_len)]}); writeLine("/system/services/acpi: register refused for {s}\n", .{hid[0..@intCast(hid_len)]});
return; return;
}; };
registered[registered_count] = .{ .hid = hid, .hid_len = @intCast(hid_len), .device_id = id, .resource_count = descriptor.resource_count }; registered[registered_count] = .{ .hid = hid, .hid_len = @intCast(hid_len), .device_id = id, .resource_count = descriptor.resource_count };
@@ -191,7 +191,7 @@ fn addChild(parent: u64, bus_address: u64, identity: u64, device_id: u64, report
fn pruneChildrenOf(reporter: u32) void { fn pruneChildrenOf(reporter: u32) void {
for (&children) |*child| { for (&children) |*child| {
if (child.used and child.reporter == reporter) { if (child.used and child.reporter == reporter) {
writeLine("device-manager: child removed (device {d} port {d})\n", .{ child.parent, child.bus_address }); writeLine("/system/services/device-manager: child removed (device {d} port {d})\n", .{ child.parent, child.bus_address });
child.used = false; child.used = false;
const event = protocol.ChildRemoved{ .parent = child.parent, .bus_address = child.bus_address }; const event = protocol.ChildRemoved{ .parent = child.parent, .bus_address = child.bus_address };
publishEvent(std.mem.asBytes(&event)); publishEvent(std.mem.asBytes(&event));
@@ -238,7 +238,7 @@ fn addDriver(name: []const u8, device_id: u64, speaks_protocol: bool) void {
spawnDriver(driver); spawnDriver(driver);
return; return;
} }
writeLine("device-manager: driver table full; cannot supervise {s}\n", .{name}); writeLine("/system/services/device-manager: driver table full; cannot supervise {s}\n", .{name});
} }
/// (Re)spawn a driver instance: supervised on the manager's own endpoint, the /// (Re)spawn a driver instance: supervised on the manager's own endpoint, the
@@ -253,7 +253,7 @@ fn spawnDriver(driver: *Driver) void {
argument_count = 1; argument_count = 1;
} }
const child = system.spawnSupervised(driver.name(), arguments[0..argument_count], manager_endpoint) orelse { const child = system.spawnSupervised(driver.name(), arguments[0..argument_count], manager_endpoint) orelse {
writeLine("device-manager: failed to spawn {s}\n", .{driver.name()}); writeLine("/system/services/device-manager: failed to spawn {s}\n", .{driver.name()});
driver.state = .failed; driver.state = .failed;
return; return;
}; };
@@ -267,9 +267,9 @@ fn spawnDriver(driver: *Driver) void {
driver.state = .running; driver.state = .running;
} }
if (driver.device_id != protocol.no_device) { if (driver.device_id != protocol.no_device) {
writeLine("device-manager: spawned {s} for device {d}\n", .{ driver.name(), driver.device_id }); writeLine("/system/services/device-manager: spawned {s} for device {d}\n", .{ driver.name(), driver.device_id });
} else { } else {
writeLine("device-manager: spawned {s}\n", .{driver.name()}); writeLine("/system/services/device-manager: spawned {s}\n", .{driver.name()});
} }
} }
@@ -281,7 +281,7 @@ fn onDriverExit(driver: *Driver) void {
const reason = runtime.process.exitReason(driver.process_id) orelse .fault; const reason = runtime.process.exitReason(driver.process_id) orelse .fault;
if (reason == .exited) { if (reason == .exited) {
driver.state = .stopped; driver.state = .stopped;
writeLine("device-manager: {s} exited cleanly; not restarting\n", .{driver.name()}); writeLine("/system/services/device-manager: {s} exited cleanly; not restarting\n", .{driver.name()});
return; return;
} }
const now = system.clock(); const now = system.clock();
@@ -289,13 +289,13 @@ fn onDriverExit(driver: *Driver) void {
driver.restarts = if (alive_ns < fast_death_ns) driver.restarts + 1 else 1; driver.restarts = if (alive_ns < fast_death_ns) driver.restarts + 1 else 1;
if (driver.restarts >= crash_loop_cap) { if (driver.restarts >= crash_loop_cap) {
driver.state = .failed; driver.state = .failed;
writeLine("device-manager: {s} is failing repeatedly (crash loop); giving up\n", .{driver.name()}); writeLine("/system/services/device-manager: {s} is failing repeatedly (crash loop); giving up\n", .{driver.name()});
return; return;
} }
const delay_ms = backoff_base_ms << @intCast(driver.restarts - 1); const delay_ms = backoff_base_ms << @intCast(driver.restarts - 1);
driver.state = .restarting; driver.state = .restarting;
driver.restart_due_ns = now + delay_ms * 1_000_000; driver.restart_due_ns = now + delay_ms * 1_000_000;
writeLine("device-manager: restarting {s} in {d} ms (died: {s})\n", .{ driver.name(), delay_ms, @tagName(reason) }); writeLine("/system/services/device-manager: restarting {s} in {d} ms (died: {s})\n", .{ driver.name(), delay_ms, @tagName(reason) });
_ = system.timerOnce(manager_endpoint, delay_ms + 50); _ = system.timerOnce(manager_endpoint, delay_ms + 50);
} }
@@ -306,7 +306,7 @@ fn onDriverExit(driver: *Driver) void {
fn sweepDeadlines() void { fn sweepDeadlines() void {
const now = system.clock(); const now = system.clock();
if (test_kill_pid != 0 and now >= test_kill_due_ns) { if (test_kill_pid != 0 and now >= test_kill_due_ns) {
writeLine("device-manager: test mode: killing the reporter\n", .{}); writeLine("/system/services/device-manager: test mode: killing the reporter\n", .{});
_ = system.kill(test_kill_pid); _ = system.kill(test_kill_pid);
test_kill_pid = 0; test_kill_pid = 0;
} }
@@ -314,7 +314,7 @@ fn sweepDeadlines() void {
if (!driver.used) continue; if (!driver.used) continue;
switch (driver.state) { switch (driver.state) {
.awaiting_hello => if (now >= driver.hello_deadline_ns) { .awaiting_hello => if (now >= driver.hello_deadline_ns) {
writeLine("device-manager: {s} missed its hello deadline\n", .{driver.name()}); writeLine("/system/services/device-manager: {s} missed its hello deadline\n", .{driver.name()});
_ = system.kill(driver.process_id); _ = system.kill(driver.process_id);
// The exit notification finishes the job via onDriverExit. // The exit notification finishes the job via onDriverExit.
}, },
@@ -331,7 +331,7 @@ fn initialise(endpoint: runtime.ipc.Handle) bool {
// Enumerate into a heap buffer (too big for the one-page user stack). // Enumerate into a heap buffer (too big for the one-page user stack).
const buffer = runtime.allocator().alloc(device.DeviceDescriptor, 64) catch { const buffer = runtime.allocator().alloc(device.DeviceDescriptor, 64) catch {
_ = runtime.system.write("device-manager: out of memory\n"); _ = runtime.system.write("/system/services/device-manager: out of memory\n");
return false; return false;
}; };
const total = device.enumerate(buffer); const total = device.enumerate(buffer);
@@ -372,9 +372,9 @@ fn initialise(endpoint: runtime.ipc.Handle) bool {
} }
if (matched == 0) { if (matched == 0) {
_ = runtime.system.write("device-manager: no matchable devices\n"); _ = runtime.system.write("/system/services/device-manager: no matchable devices\n");
} else { } else {
_ = runtime.system.write("device-manager: ok\n"); _ = runtime.system.write("/system/services/device-manager: ok\n");
} }
return true; return true;
} }
@@ -395,13 +395,13 @@ fn onMessage(message: []const u8, reply: []u8, sender: u32, capability: ?runtime
var status: i32 = 0; var status: i32 = 0;
if (hello.version != protocol.version) { if (hello.version != protocol.version) {
status = -1; status = -1;
writeLine("device-manager: refused hello (version {d}) from process {d}\n", .{ hello.version, sender }); writeLine("/system/services/device-manager: refused hello (version {d}) from process {d}\n", .{ hello.version, sender });
} else if (driverByProcess(sender)) |driver| { } else if (driverByProcess(sender)) |driver| {
driver.state = .running; driver.state = .running;
writeLine("device-manager: hello from {s} (device {d})\n", .{ driver.name(), hello.device_id }); writeLine("/system/services/device-manager: hello from {s} (device {d})\n", .{ driver.name(), hello.device_id });
} else { } else {
status = -1; status = -1;
writeLine("device-manager: hello from unknown process {d}\n", .{sender}); writeLine("/system/services/device-manager: hello from unknown process {d}\n", .{sender});
} }
const hello_reply = protocol.HelloReply{ .status = status }; const hello_reply = protocol.HelloReply{ .status = status };
@memcpy(reply[0..protocol.reply_size], std.mem.asBytes(&hello_reply)); @memcpy(reply[0..protocol.reply_size], std.mem.asBytes(&hello_reply));
@@ -417,7 +417,7 @@ fn onChildAdded(message: []const u8, reply: []u8, sender: u32) usize {
var status: i32 = 0; var status: i32 = 0;
if (driverByProcess(sender)) |driver| { if (driverByProcess(sender)) |driver| {
if (!addChild(report.parent, report.bus_address, report.identity, report.device_id, sender)) status = -1; if (!addChild(report.parent, report.bus_address, report.identity, report.device_id, sender)) status = -1;
writeLine("device-manager: child added (device {d} port {d}, identity {d}) by {s}\n", .{ report.parent, report.bus_address, report.identity, driver.name() }); writeLine("/system/services/device-manager: child added (device {d} port {d}, identity {d}) by {s}\n", .{ report.parent, report.bus_address, report.identity, driver.name() });
if (status == 0) publishEvent(message[0..protocol.child_added_size]); if (status == 0) publishEvent(message[0..protocol.child_added_size]);
// Matching from reports (M19.3): a registered child whose identity // Matching from reports (M19.3): a registered child whose identity
// names a driver gets one, once — re-reports after a bus restart // names a driver gets one, once — re-reports after a bus restart
@@ -478,7 +478,7 @@ fn onChildRemoved(message: []const u8, reply: []u8, sender: u32) usize {
var status: i32 = -1; var status: i32 = -1;
for (&children) |*child| { for (&children) |*child| {
if (child.used and child.parent == report.parent and child.bus_address == report.bus_address and child.reporter == sender) { if (child.used and child.parent == report.parent and child.bus_address == report.bus_address and child.reporter == sender) {
writeLine("device-manager: child removed (device {d} port {d})\n", .{ child.parent, child.bus_address }); writeLine("/system/services/device-manager: child removed (device {d} port {d})\n", .{ child.parent, child.bus_address });
child.used = false; child.used = false;
status = 0; status = 0;
} }
+9 -9
View File
@@ -1,5 +1,5 @@
//! /system/services/init — the first user-space program, PID 1. Built as its own //! /system/services/system/services/init: — the first user-space program, PID 1. Built as its own
//! freestanding binary (see build.zig), shipped on the boot volume at /system/services/init, //! freestanding binary (see build.zig), shipped on the boot volume at /system/services/system/services/init:,
//! loaded by the bootloader, and started in ring 3 as a scheduled process by the //! loaded by the bootloader, and started in ring 3 as a scheduled process by the
//! kernel (system/kernel/process.zig). It links against the shared user runtime //! kernel (system/kernel/process.zig). It links against the shared user runtime
//! library `runtime` and talks to the kernel only through `runtime`'s system_call wrappers. //! library `runtime` and talks to the kernel only through `runtime`'s system_call wrappers.
@@ -13,9 +13,9 @@
const runtime = @import("runtime"); const runtime = @import("runtime");
/// The system services init brings up at boot, in order. This is init's policy — the /// The system services system/services/init: brings up at boot, in order. This is system/services/init:'s policy — the
/// microkernel keeps such choices in user space, not the kernel. Drivers are absent /// microkernel keeps such choices in user space, not the kernel. Drivers are absent
/// on purpose: the device manager owns those. (A future init reads this from a /// on purpose: the device manager owns those. (A future system/services/init: reads this from a
/// manifest under /system/services instead of a hardcoded list.) /// manifest under /system/services instead of a hardcoded list.)
const boot_services = [_][]const u8{ "vfs", "input", "device-manager" }; const boot_services = [_][]const u8{ "vfs", "input", "device-manager" };
@@ -23,26 +23,26 @@ pub fn main() void {
// Prove the heap end to end: allocate through the runtime allocator (which // Prove the heap end to end: allocate through the runtime allocator (which
// mmaps pages from the kernel and carves them with the free list), write into // mmaps pages from the kernel and carves them with the free list), write into
// that heap buffer (exercising the widened debug_write bounds check), and // that heap buffer (exercising the widened debug_write bounds check), and
// free it. A fault here would kill init before it heartbeats — so the init // free it. A fault here would kill system/services/init: before it heartbeats — so the system/services/init:
// test doubles as the heap regression test. (C code links the same heap via // test doubles as the heap regression test. (C code links the same heap via
// the extern malloc/free symbols; Zig code uses this allocator.) // the extern malloc/free symbols; Zig code uses this allocator.)
const gpa = runtime.allocator(); const gpa = runtime.allocator();
if (gpa.alloc(u8, 64)) |buffer| { if (gpa.alloc(u8, 64)) |buffer| {
const message = "init: heap ok\n"; const message = "/system/services/init: heap ok\n";
@memcpy(buffer[0..message.len], message); @memcpy(buffer[0..message.len], message);
_ = runtime.system.write(buffer[0..message.len]); _ = runtime.system.write(buffer[0..message.len]);
gpa.free(buffer); gpa.free(buffer);
} else |_| {} } else |_| {}
// Bring up the boot services. Best-effort and silent: each service announces its // Bring up the boot services. Best-effort and silent: each service announces its
// own readiness (`vfs: ready`, ...), and in an isolation test that runs init with // own readiness (`vfs: ready`, ...), and in an isolation test that runs system/services/init: with
// no initial-ramdisk the spawns simply no-op rather than deranging the heartbeat. // no system/services/init:ial-ramdisk the spawns simply no-op rather than deranging the heartbeat.
for (boot_services) |service| { for (boot_services) |service| {
_ = runtime.system.spawn(service); _ = runtime.system.spawn(service);
} }
while (true) { while (true) {
_ = runtime.system.write("init: heartbeat\n"); _ = runtime.system.write("/system/services/init: heartbeat\n");
runtime.system.sleep(1000); runtime.system.sleep(1000);
} }
} }
+3 -3
View File
@@ -115,14 +115,14 @@ fn handle(message: []const u8, got: ipc.Received, out: []u8) usize {
pub fn main() void { pub fn main() void {
const endpoint = ipc.createIpcEndpoint() orelse { const endpoint = ipc.createIpcEndpoint() orelse {
_ = system.write("input: no endpoint\n"); _ = system.write("/system/services/input: no endpoint\n");
return; return;
}; };
if (!ipc.register(.input, endpoint)) { if (!ipc.register(.input, endpoint)) {
_ = system.write("input: register failed\n"); _ = system.write("/system/services/input: register failed\n");
return; return;
} }
_ = system.write("input: ready\n"); _ = system.write("/system/services/input: ready\n");
var reply_buffer: [protocol.reply_size]u8 = undefined; var reply_buffer: [protocol.reply_size]u8 = undefined;
var reply_len: usize = 0; var reply_len: usize = 0;
+3 -3
View File
@@ -87,7 +87,7 @@ fn releaseClientHandles(client: u32) void {
released += 1; released += 1;
} }
} }
if (released != 0) writeLine("vfs: released {d} handle(s) for dead client {d}\n", .{ released, client }); if (released != 0) writeLine("/system/services/vfs: released {d} handle(s) for dead client {d}\n", .{ released, client });
} }
/// Handle one request from `sender`; write the reply into `out`, return its length. /// Handle one request from `sender`; write the reply into `out`, return its length.
@@ -144,9 +144,9 @@ fn handle(message: []const u8, out: []u8, sender: u32, capability: ?runtime.ipc.
/// to release them (docs/process-lifecycle.md). /// to release them (docs/process-lifecycle.md).
fn initialise(endpoint: runtime.ipc.Handle) bool { fn initialise(endpoint: runtime.ipc.Handle) bool {
if (!runtime.process.subscribeExits(endpoint)) { if (!runtime.process.subscribeExits(endpoint)) {
_ = runtime.system.write("vfs: exit subscription failed\n"); _ = runtime.system.write("/system/services/vfs: exit subscription failed\n");
} }
_ = runtime.system.write("vfs: ready\n"); _ = runtime.system.write("/system/services/vfs: ready\n");
return true; return true;
} }