kernel: flatten the device/discovery code, merge power into acpi, rename fdt

Follow-up cleanup of the just-moved kernel device code:

- power.zig -> acpi.zig. Its reboot() is built entirely on the FADT reset
  register (acpi.power_information) plus the legacy 0xCF9/8042 fallbacks — it is
  ACPI reboot, so it becomes acpi.reboot (the "P" in ACPI). platform.reboot
  still delegates; soft-off/S5 stays the ring-3 acpi service's job as before.

- device-tree.zig -> fdt.zig. It is a discovery *backend* (the ARM/FDT parser,
  a sibling of acpi.zig), not part of the model — renaming it to its actual
  subject kills the confusing device-tree / device-model DeviceTree name clash
  and makes acpi.zig + fdt.zig read as the two parallel backends.

- Flatten: device-model.zig, acpi.zig, fdt.zig, platform.zig move out of the
  system/kernel/devices/ subdir up into system/kernel/, joining devices-broker.zig
  (already flat). The kernel dir is a flat pile by convention (only architecture/
  is a subdir), so the subdir — and its poor "devices" name — is gone.

Pure restructure; "platform" module name unchanged, all cross-file deps are
relative siblings that moved together. zig build + test green; smoke, discovery,
acpi-parse, acpi-ps2, acpi-report, power-button, orderly-shutdown, reboot pass.
This commit is contained in:
Daniel Samson
2026-07-22 21:49:20 +01:00
parent 3a155cdc7d
commit 11f567ee20
12 changed files with 67 additions and 72 deletions
@@ -60,7 +60,7 @@ pub const PowerInformation = struct {
reset_supported: bool = false,
};
/// Filled in by `discover`; the power service reads it to reboot/shutdown.
/// Filled in by `discover`; `reboot` (below) reads it to restart the machine.
pub var power_information: PowerInformation = .{};
/// A legacy ISA IRQ remapped to a different global system interrupt (GSI), from a
@@ -839,3 +839,50 @@ fn rd(comptime T: type, bytes: [*]align(1) const u8, off: usize) T {
const p: *align(1) const T = @ptrCast(bytes + off);
return p.*;
}
// --- machine reboot -------------------------------------------------------------
// Restart via the FADT reset register (from `power_information` above), with legacy
// fallbacks, driven through the injected `Hal`. Soft-off (ACPI S5) and suspend (S3)
// are NOT here: they need the AML sleep-state (`_Sx`) values, which the kernel no
// longer parses — the ring-3 acpi service owns power management (it re-parses the
// blobs and writes the PM1 control register itself). Reboot stays in the kernel
// because it needs no AML — only the FADT reset register and the well-known legacy
// fallbacks — so it survives as a last-resort restart. See docs/power.md.
/// Restart the machine. Tries the ACPI reset register first, then the two legacy
/// fallbacks. Returns only if every method failed (very unlikely).
pub fn reboot(hal: device_model.Hal) void {
const pi = power_information;
// 1. The FADT reset register, when the firmware advertises support.
if (pi.reset_supported and pi.reset.present()) {
writeResetRegister(hal, pi.reset, pi.reset_value);
rebootDelay();
}
// 2. The PCI reset-control register at port 0xCF9 (RST_CPU | SYSTEM_RST).
hal.pioWrite(1, 0xCF9, 0x0E);
hal.pioWrite(1, 0xCF9, 0x06);
rebootDelay();
// 3. Pulse the 8042 keyboard controller's reset line.
hal.pioWrite(1, 0x64, 0xFE);
rebootDelay();
}
fn writeResetRegister(hal: device_model.Hal, register: RegisterAccess, value: u32) void {
if (register.mmio) {
const p: *align(1) volatile u32 = @ptrFromInt(hal.mapMmio(register.address, 4, true));
p.* = value;
} else {
hal.pioWrite(register.width, @intCast(register.address), value);
}
}
/// A short busy-wait so a reset takes effect before we fall through to the next
/// method. The empty asm is an architecture-neutral barrier that keeps the loop
/// from being optimised away.
fn rebootDelay() void {
var i: usize = 0;
while (i < 50_000_000) : (i += 1) {
asm volatile ("" ::: .{ .memory = true });
}
}
-51
View File
@@ -1,51 +0,0 @@
//! Machine reboot: restart via the FADT reset register, with legacy fallbacks.
//!
//! Built on the register map `acpi` extracted from the FADT, driven through the
//! injected `Hal` (port I/O and MMIO). Soft-off (ACPI S5) and suspend (S3) are
//! **not** here: they need the AML sleep-state (`_Sx`) values, which the kernel no
//! longer parses — the ring-3 acpi service owns power management (it re-parses the
//! blobs and writes the PM1 control register itself). See docs/power.md. Reboot
//! stays in the kernel because it needs no AML — only the FADT reset register and
//! the well-known legacy fallbacks — so it survives as a last-resort restart.
const acpi = @import("acpi.zig");
const device_model = @import("device-model.zig");
const Hal = device_model.Hal;
/// Restart the machine. Tries the ACPI reset register first, then the two legacy
/// fallbacks. Returns only if every method failed (very unlikely).
pub fn reboot(hal: Hal) void {
const pi = acpi.power_information;
// 1. The FADT reset register, when the firmware advertises support.
if (pi.reset_supported and pi.reset.present()) {
writeRegister(hal, pi.reset, pi.reset_value);
delay();
}
// 2. The PCI reset-control register at port 0xCF9 (RST_CPU | SYSTEM_RST).
hal.pioWrite(1, 0xCF9, 0x0E);
hal.pioWrite(1, 0xCF9, 0x06);
delay();
// 3. Pulse the 8042 keyboard controller's reset line.
hal.pioWrite(1, 0x64, 0xFE);
delay();
}
fn writeRegister(hal: Hal, register: acpi.RegisterAccess, value: u32) void {
if (register.mmio) {
const p: *align(1) volatile u32 = @ptrFromInt(hal.mapMmio(register.address, 4, true));
p.* = value;
} else {
hal.pioWrite(register.width, @intCast(register.address), value);
}
}
/// A short busy-wait so a reset takes effect before we fall through to the next
/// method. The empty asm is an architecture-neutral barrier that keeps the loop
/// from being optimised away.
fn delay() void {
var i: usize = 0;
while (i < 50_000_000) : (i += 1) {
asm volatile ("" ::: .{ .memory = true });
}
}
@@ -12,8 +12,7 @@ const std = @import("std");
const boot_handoff = @import("boot-handoff");
const device_model = @import("device-model.zig");
const acpi = @import("acpi.zig");
const power = @import("power.zig");
const devicetree = @import("device-tree.zig");
const fdt = @import("fdt.zig");
pub const DeviceTree = device_model.DeviceTree;
pub const Device = device_model.Device;
@@ -74,7 +73,7 @@ pub fn discover(
// No ACPI RSDP. A device-tree boot would parse its blob here; today that
// path is a stub, so this reports the machine described itself no way we
// understand yet.
try devicetree.discover(&device_tree);
try fdt.discover(&device_tree);
}
return device_tree;
@@ -84,5 +83,5 @@ pub fn discover(
/// worked (extremely unlikely). Backend-agnostic entry the kernel calls. Soft-off
/// (S5) is not a kernel operation — the ring-3 acpi service owns it (docs/power.md).
pub fn reboot(hal: Hal) void {
power.reboot(hal);
acpi.reboot(hal);
}