Compare commits
17
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dd22bfbc48 | ||
|
|
6e60daed6a | ||
|
|
dd044fb115 | ||
|
|
3ec14509a0 | ||
|
|
d71a5f25d3 | ||
|
|
2a0f17ae86 | ||
|
|
9ef61a0844 | ||
|
|
688b9101e8 | ||
|
|
1d7ba814dc | ||
|
|
8aba86b4ce | ||
|
|
a0c83f4b3f | ||
|
|
1ea48ed5d6 | ||
|
|
77a3ccd33d | ||
|
|
07da27dc39 | ||
|
|
d89657d0a4 | ||
|
|
849b4b62d4 | ||
|
|
8589bf713b |
+6
-6
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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, .{
|
||||||
|
|||||||
@@ -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
@@ -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});
|
||||||
|
|||||||
+33
-28
@@ -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];
|
if (std.mem.indexOf(u8, line, count_prefix)) |start| {
|
||||||
const digits_end = std.mem.indexOf(u8, line, count_suffix) orelse {
|
if (std.mem.indexOf(u8, line, count_suffix)) |digits_end| {
|
||||||
scheduler.yield();
|
reported = std.fmt.parseInt(u32, line[start + count_prefix.len .. digits_end], 10) catch 0;
|
||||||
continue;
|
}
|
||||||
};
|
|
||||||
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();
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user