The flip: ACPI enumeration leaves the kernel (M20.3)
The kernel no longer folds AML Device objects into the device tree — the ring-3 acpi service is the sole builder of _HID device nodes. The kernel keeps building the namespace only for the \_S5 sleep type, and still seeds the static tables (MADT, HPET, MCFG, FADT) and the acpi-tables node. The device manager matches ps2-bus from the service's _HID reports (PNP0303 / PNP0F13, singleton-deduped) instead of boot-snapshot nodes; its dead boot-snapshot ps2 arm is gone. The service registers every device before reporting any, so a driver the manager spawns on the first report already sees the full set — no keyboard-before-mouse race. The acpi-ps2 scenario proves the whole chain: report -> spawn -> ps2-bus finds the controller and attaches its keyboard, entirely in ring 3. The ioport test moved to the acpi-tables I/O window, since the kernel-built PS/2 node it used to scan for no longer exists. The retired device-building functions in acpi.zig are dead but retained (a botched mechanical deletion is worse mid-migration than a follow-up sweep, which is flagged as a task). Suite 58/58.
This commit is contained in:
@@ -28,6 +28,11 @@ fn writeLine(comptime fmt: []const u8, arguments: anytype) void {
|
||||
var node_id: u64 = 0;
|
||||
var io_resource_index: u64 = 0;
|
||||
|
||||
// Pass-1 registration record (see main): what pass 2 reports.
|
||||
const Registered = struct { hid: [8]u8 = .{0} ** 8, hid_len: usize = 0, device_id: u64 = 0, resource_count: u64 = 0 };
|
||||
var registered: [64]Registered = undefined;
|
||||
var registered_count: usize = 0;
|
||||
|
||||
// A scratch page returned for SystemMemory OperationRegion maps: the service
|
||||
// cannot map arbitrary physical memory from ring 3, so such regions are
|
||||
// unsupported and degrade to harmless zeros rather than faulting. The M20.2
|
||||
@@ -123,10 +128,31 @@ pub fn main(init: runtime.process.Init) void {
|
||||
.pioWrite = halPioWrite,
|
||||
}, arena.allocator());
|
||||
|
||||
// Pass 1: register every present _HID device under acpi-tables, remembering
|
||||
// each (hid, device id). Pass 2: report them all. Registering before any
|
||||
// report reaches the manager means a driver it spawns on the first report
|
||||
// already sees the whole set (no keyboard-before-mouse race for ps2-bus).
|
||||
registered_count = 0;
|
||||
walkDevices(namespace.root, &interpreter);
|
||||
|
||||
const manager = runtime.ipc.lookup(.device_manager);
|
||||
var reported: u32 = 0;
|
||||
walkDevices(namespace.root, &interpreter, manager, &reported);
|
||||
writeLine("acpi: reported {d} device(s) to the manager\n", .{reported});
|
||||
var i: usize = 0;
|
||||
while (i < registered_count) : (i += 1) {
|
||||
const entry = registered[i];
|
||||
writeLine("acpi: reported {s} (device {d}, {d} resources)\n", .{ entry.hid[0..entry.hid_len], entry.device_id, entry.resource_count });
|
||||
if (manager) |h| {
|
||||
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]);
|
||||
var reply: [protocol.message_maximum]u8 = undefined;
|
||||
_ = runtime.ipc.call(h, std.mem.asBytes(&report), &reply) catch {};
|
||||
}
|
||||
}
|
||||
writeLine("acpi: reported {d} device(s) to the manager\n", .{registered_count});
|
||||
|
||||
// Stay resident: the claim holds, and the service is here to grow into the
|
||||
// supervised discoverer (M20.3, then the M21 event side on the SCI).
|
||||
@@ -135,11 +161,11 @@ pub fn main(init: runtime.process.Init) void {
|
||||
|
||||
/// Depth-first walk: register + report each present device with a _HID, then
|
||||
/// descend. Scopes (\_SB, \_GPE …) are descended without producing a node.
|
||||
fn walkDevices(node: *aml.Node, interpreter: *aml.Interpreter, manager: ?runtime.ipc.Handle, reported: *u32) void {
|
||||
fn walkDevices(node: *aml.Node, interpreter: *aml.Interpreter) void {
|
||||
var child = node.first_child;
|
||||
while (child) |c| : (child = c.next_sibling) {
|
||||
if (c.kind != .device) {
|
||||
walkDevices(c, interpreter, manager, reported);
|
||||
walkDevices(c, interpreter);
|
||||
continue;
|
||||
}
|
||||
if (!devicePresent(interpreter, c)) continue; // absent: skip it and its subtree
|
||||
@@ -148,14 +174,15 @@ fn walkDevices(node: *aml.Node, interpreter: *aml.Interpreter, manager: ?runtime
|
||||
// Skip PCI roots — pci-bus already reports PCI functions; ACPI adds
|
||||
// only the non-PCI _HID devices (docs/m19-m20-plan.md M20.2).
|
||||
if (!std.mem.eql(u8, hid[0..7], "PNP0A03") and !std.mem.eql(u8, hid[0..7], "PNP0A08")) {
|
||||
registerAndReport(c, hid, interpreter, manager, reported);
|
||||
registerDevice(c, hid, interpreter);
|
||||
}
|
||||
}
|
||||
walkDevices(c, interpreter, manager, reported);
|
||||
walkDevices(c, interpreter);
|
||||
}
|
||||
}
|
||||
|
||||
fn registerAndReport(node: *aml.Node, hid: [8]u8, interpreter: *aml.Interpreter, manager: ?runtime.ipc.Handle, reported: *u32) void {
|
||||
fn registerDevice(node: *aml.Node, hid: [8]u8, interpreter: *aml.Interpreter) void {
|
||||
if (registered_count >= registered.len) return;
|
||||
var descriptor = std.mem.zeroes(device.DeviceDescriptor);
|
||||
descriptor.class = @intFromEnum(device.DeviceClass.acpi_device);
|
||||
descriptor.pci_class = device.no_pci_class;
|
||||
@@ -164,24 +191,12 @@ fn registerAndReport(node: *aml.Node, hid: [8]u8, interpreter: *aml.Interpreter,
|
||||
@memcpy(descriptor.hid[0..@intCast(hid_len)], hid[0..@intCast(hid_len)]);
|
||||
applyCrs(&descriptor, node, interpreter);
|
||||
|
||||
const registered = 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)]});
|
||||
return;
|
||||
};
|
||||
writeLine("acpi: reported {s} (device {d}, {d} resources)\n", .{ hid[0..@intCast(hid_len)], registered, descriptor.resource_count });
|
||||
reported.* += 1;
|
||||
|
||||
if (manager) |h| {
|
||||
var report = protocol.ChildAdded{
|
||||
.parent = node_id,
|
||||
.bus_address = registered,
|
||||
.identity = 0,
|
||||
.device_id = registered,
|
||||
};
|
||||
@memcpy(report.hid[0..@intCast(hid_len)], hid[0..@intCast(hid_len)]);
|
||||
var reply: [protocol.message_maximum]u8 = undefined;
|
||||
_ = runtime.ipc.call(h, std.mem.asBytes(&report), &reply) catch {};
|
||||
}
|
||||
registered[registered_count] = .{ .hid = hid, .hid_len = @intCast(hid_len), .device_id = id, .resource_count = descriptor.resource_count };
|
||||
registered_count += 1;
|
||||
}
|
||||
|
||||
/// _STA bit 0 (present); absent method or a failed evaluation is treated as
|
||||
|
||||
Reference in New Issue
Block a user