Author SHA1 Message Date
Daniel Samson dd22bfbc48 Merge feat/power-events: ACPI events + system power (M21)
The QMP harness channel, the SCI + power button published from ring 3,
Notify/GPE dispatch in the AML interpreter, and orderly shutdown — init's
M17 stop cascade into a ring-3 S5 write. Proven by injecting a real ACPI
power-button event; QEMU powers off through the whole chain.

# Conflicts:
#	system/services/init/init.zig
2026-07-13 06:27:18 +01:00
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
11 changed files with 146 additions and 141 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, .{
+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
@@ -211,6 +211,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", .{});
@@ -1380,7 +1387,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);
@@ -1642,11 +1649,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;
@@ -1659,11 +1666,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();
} }
@@ -1705,8 +1712,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);
@@ -1868,13 +1875,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();
} }
@@ -1898,7 +1903,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);
@@ -1910,7 +1915,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);
@@ -2060,12 +2065,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);
@@ -2145,12 +2150,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);
@@ -2190,12 +2195,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);
@@ -2287,12 +2292,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());
@@ -2393,12 +2398,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());
@@ -2442,12 +2447,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
@@ -108,16 +108,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;
} }
@@ -151,17 +151,17 @@ pub fn main(init: runtime.process.Init) void {
block_count += 1; block_count += 1;
} }
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");
@@ -214,9 +214,9 @@ fn onInit(endpoint: runtime.ipc.Handle) bool {
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{ .parent = node_id, .bus_address = entry.device_id, .identity = 0, .device_id = entry.device_id }; var report = protocol.ChildAdded{ .parent = node_id, .bus_address = entry.device_id, .identity = 0, .device_id = entry.device_id };
@memcpy(report.hid[0..entry.hid_len], entry.hid[0..entry.hid_len]); @memcpy(report.hid[0..entry.hid_len], entry.hid[0..entry.hid_len]);
@@ -224,7 +224,7 @@ fn onInit(endpoint: runtime.ipc.Handle) bool {
_ = 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});
armPowerButton(endpoint); armPowerButton(endpoint);
return true; return true;
@@ -498,7 +498,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;
} }
+4 -4
View File
@@ -40,7 +40,7 @@ pub fn main() void {
// 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);
@@ -50,7 +50,7 @@ pub fn main() void {
// notifications (they are spawned supervised against it), init's own // notifications (they are spawned supervised against it), init's own
// signals, and power events it subscribes to. All arrive in the loop below. // signals, and power events it subscribes to. All arrive in the loop below.
supervision_endpoint = runtime.ipc.createIpcEndpoint() orelse { supervision_endpoint = runtime.ipc.createIpcEndpoint() orelse {
_ = runtime.system.write("init: no endpoint\n"); _ = runtime.system.write("/system/services/init: no endpoint\n");
return; return;
}; };
_ = runtime.process.bindSignals(supervision_endpoint); _ = runtime.process.bindSignals(supervision_endpoint);
@@ -83,7 +83,7 @@ pub fn main() void {
continue; continue;
} }
if (got.isTimer()) { if (got.isTimer()) {
_ = runtime.system.write("init: heartbeat\n"); _ = runtime.system.write("/system/services/init: heartbeat\n");
_ = runtime.system.timerOnce(supervision_endpoint, 1000); _ = runtime.system.timerOnce(supervision_endpoint, 1000);
continue; continue;
} }
@@ -119,7 +119,7 @@ fn subscribePower() void {
/// other services may flush through it), waiting up to a deadline for each to /// other services may flush through it), waiting up to a deadline for each to
/// exit before killing it, then ask the power service to enter S5. /// exit before killing it, then ask the power service to enter S5.
fn shutDown() void { fn shutDown() void {
_ = runtime.system.write("init: shutting down\n"); _ = runtime.system.write("/system/services/init: shutting down\n");
var i = child_count; var i = child_count;
while (i > 0) { while (i > 0) {
i -= 1; i -= 1;
+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;
} }