The power button, in ring 3: SCI bound, fixed event published (M21.1)
The kernel publishes the FADT as one more acpi-tables memory resource (tagged by its intact FACP header — the AML blobs are header-stripped); the acpi service reads the PM1 event/control and GPE register ports from that copy, so the kernel's own FADT parse is untouched. A power-protocol module (ServiceId.power = 5, domain-named so an ARM PSCI service can serve the same id) carries subscribe / shutdown / events. The acpi service converts to runtime.service.run — device discovery, the .power protocol, and the SCI notification all fold into one loop. At startup it enables ACPI mode if SCI_EN is clear (the SMI dance), binds the SCI (found as the node's len-1 irq resource, distinct from the broad window), and sets PWRBTN_EN. On the SCI it reads PM1_STS, clears PWRBTN_STS write-1, logs the press, publishes power_button to subscribers, and always acks. The power-button scenario proves it with a real QMP system_powerdown injected mid-run through the M21.0 channel.
This commit is contained in:
@@ -157,6 +157,13 @@ pub var namespace: ?aml.Namespace = null;
|
||||
/// Physical address of the DSDT the FADT points at, or 0.
|
||||
pub var dsdt_physical: u64 = 0;
|
||||
|
||||
/// The FADT itself (physical + length), published on the acpi-tables node so
|
||||
/// the ring-3 acpi service can read the PM1 event and GPE blocks it needs for
|
||||
/// the event side (docs/m21-plan.md decision 3). Distinguished from the AML
|
||||
/// blob resources by its intact "FACP" header — the blobs are header-stripped.
|
||||
var fadt_physical: u64 = 0;
|
||||
var fadt_length: u64 = 0;
|
||||
|
||||
// AML blocks (DSDT + any SSDTs) collected during the table walk, as physical
|
||||
// address + length of each table's post-header bytecode. Scanned after the walk
|
||||
// for the sleep-state (`_Sx`) packages.
|
||||
@@ -373,6 +380,8 @@ pub fn discover(rsdp_physical: u64, memory_regions: []const boot_handoff.MemoryR
|
||||
|
||||
// Start clean so a re-run doesn't accumulate stale state.
|
||||
power_information = .{};
|
||||
fadt_physical = 0;
|
||||
fadt_length = 0;
|
||||
platform_information = .{};
|
||||
aml_stats = .{};
|
||||
namespace = null;
|
||||
@@ -447,6 +456,9 @@ fn publishAcpiTablesNode(device_tree: *DeviceTree) !void {
|
||||
// SCI (recorded first, len 1) stays distinct so M21 can pick it out.
|
||||
if (power_information.sci_interrupt != 0) _ = node.addResource(.irq, power_information.sci_interrupt, 1);
|
||||
_ = node.addResource(.irq, 0, 256);
|
||||
// The FADT rides along (M21): the service reads the PM1 event / GPE blocks
|
||||
// from its own copy, telling it apart from the AML blobs by signature.
|
||||
if (fadt_physical != 0) _ = node.addResource(.memory, fadt_physical, fadt_length);
|
||||
}
|
||||
|
||||
/// The number of Device objects in the namespace built during discovery, or 0.
|
||||
@@ -482,6 +494,8 @@ fn handleTable(device_tree: *DeviceTree, hal: Hal, sdt_physical: u64) !void {
|
||||
} else if (std.mem.eql(u8, &sig, &HPET)) {
|
||||
try parseHpet(device_tree, hal, header);
|
||||
} else if (std.mem.eql(u8, &sig, &FACP)) {
|
||||
fadt_physical = sdt_physical;
|
||||
fadt_length = header.length;
|
||||
parseFadt(header);
|
||||
} else if (std.mem.eql(u8, &sig, &SPCR)) {
|
||||
parseSpcr(header);
|
||||
|
||||
Reference in New Issue
Block a user