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:
@@ -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 });
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user