From 5327f367163cd4cf245a4342d847c89a933ff477 Mon Sep 17 00:00:00 2001 From: vasilito Date: Wed, 5 Aug 2026 03:19:19 +0300 Subject: [PATCH] base: bump gitlink for acpid bounded S5 + reset-reg/8042 reboot (task 7) --- .../task-7-ryzen-7000-x670e-compat.txt | 223 ++++++++++++++++++ local/sources/base | 2 +- 2 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 .omo/evidence/task-7-ryzen-7000-x670e-compat.txt diff --git a/.omo/evidence/task-7-ryzen-7000-x670e-compat.txt b/.omo/evidence/task-7-ryzen-7000-x670e-compat.txt new file mode 100644 index 0000000000..87557ea7f3 --- /dev/null +++ b/.omo/evidence/task-7-ryzen-7000-x670e-compat.txt @@ -0,0 +1,223 @@ +=== TASK 7: acpid bounded S5 + FADT reset-register reboot + 8042 fallback === +Date: 2026-08-05 +Plan: .omo/plans/ryzen-7000-x670e-compat.md @ line 173 + +=== FILES CHANGED === + +1. local/sources/base/drivers/acpid/src/acpi.rs + - Made GenericAddressStructure fields `pub` (address_space, bit_width, + bit_offset, access_size, address) for FADT reset_reg access. + - Added associated constants: GAS_SYSTEM_MEMORY(0), GAS_SYSTEM_IO(1), + GAS_PCI_CONFIG(2) — ACPI 6.5 Table 5.1 address space IDs. + - Added S5 bounded-delay constants: S5_BOUNDED_DELAY_MS=5000, + S5_POLL_INTERVAL_MS=100, S5_MAX_ITERATIONS=50. + - Replaced infinite spin loop (was acpi.rs:1226-1230) in + set_global_s_state(5) with bounded 5-second wait (50 iterations + of 100ms sleeps). After expiry, executes the NAMED terminal + fallback chain via acpi_reboot_inner(). + - Non-S5 states (S3 suspend) retain existing spin behavior. + - Added fn s5_bounded_wait_and_fallback() — 5s wait + log + fallback. + - Added pub fn acpi_reboot() — public API for kstop reason=4 reboot. + - Added fn acpi_reboot_inner() — shared logic: FADT reset_reg → + 8042 pulse → halt. + - Added fn try_fadt_reset_reg() — writes reset_value to reset_reg + per GAS address_space (System I/O supported; System Memory and + PCI Config Space logged as not-yet-implemented, returning false). + - Copy packed-struct fields to locals before referencing (fixes + E0793 "reference to packed field is unaligned"). + - Added #[doc(hidden)] test helper functions: + * gas_address_space_is_resettable() + * gas_address_space_name() + - Added module-level pub enum FallbackStage { Pm1Write, FadtResetReg, + I8042Pulse, TerminalHalt }. + - Added const fn fallback_chain_for_state() — pure function enumerating + the ordered fallback stages for S5 vs reboot. + - Added free fn i8042_pulse_reset() -> ! — 8042 keyboard-controller + reset pulse (write 0xFE to port 0x64 after waiting for input buffer + empty). Includes cfg-gated arch support, bounded port polling + (up to 10,000 iterations), and terminal halt with `cli; hlt`. + - Added #[cfg(test)] mod tests with 16 unit tests covering: + GAS classification, fallback chain ordering, bounded-delay parameters, + ACPI spec constant values, and fallback stage discriminant uniqueness. + +2. local/sources/base/drivers/acpid/src/main.rs + - Added `let mut reboot_requested = false;` before the main event loop. + - Added kstop reason=4 dispatch: sets reboot_requested=true, mounted=false. + - Post-loop: dispatches to acpi_context.acpi_reboot() when + reboot_requested, otherwise acpi_context.set_global_s_state(5). + - Existing kstop/shutdown eventing (reason=1→shutdown, reason=2→s2idle + wake, reason=3→s3 wake, power-button→mounted=false) is preserved + unchanged. + +3. local/sources/base/drivers/acpid/tests/fallback_chain_standalone.rs (NEW) + - Standalone host-runnable test harness for the pure decision-logic + functions. No Redox syscall dependencies — compiles and runs on + the Linux host with `rustc --test`. + +=== FALLBACK CHAIN DESIGN === + +S5 shutdown (set_global_s_state(5)): + 1. PM1a/PM1b write (SLP_EN | SLP_TYPa/b) — existing code, unchanged. + 2. BOUNDED 5-second wait (50 × 100ms sleeps). + 3. If still alive → log.error("S5 bounded wait expired — executing fallback chain") + 4. FADT reset_reg/reset_value write (System I/O address space only; + System Memory and PCI Config logged as not-yet-implemented). + 5. If reset_reg absent/fails → 8042 keyboard-controller pulse + (write 0xFE to port 0x64 after waiting for input buffer empty). + 6. If 8042 fails → log.error("ALL RESET MECHANISMS FAILED") + cli; hlt. + NEVER an unbounded silent spin. + +Reboot (acpi_reboot(), called from kstop reason=4 or S5 fallback): + 1. FADT reset_reg/reset_value write. + 2. 8042 keyboard-controller pulse (0x64/0xFE). + 3. Terminal halt (cli; hlt). + +Both paths share the same fallback mechanism (acpi_reboot_inner). + +=== LOG LINE FORMATS (distinct, greppable) === + +S5 attempt: + log::warn!("Sleep S5 with ACPI outw(0x{:X}, 0x{:X})", state, port_a, val_a); + +Bounded-wait expiry: + log::error!("acpid: S5 bounded wait expired ({} ms) — machine did not power off; executing fallback chain", S5_BOUNDED_DELAY_MS); + +FADT reset_reg attempt: + log::warn!("acpid: attempting FADT reset_reg reboot: addr_space={} addr={:#x} value={:#x} bit_width={} bit_offset={}", ...); + +FADT reset_reg unavailable (address zero): + log::warn!("acpid: FADT reset_reg address is zero — reset register not available"); + +FADT reset_reg unsupported address space: + log::error!("acpid: FADT reset_reg is System Memory at {:#x} — MMIO reset not yet implemented", ...); + log::error!("acpid: FADT reset_reg is PCI Config Space at {:#x} — PCI config reset not yet implemented", ...); + log::error!("acpid: FADT reset_reg has unknown address space {} — cannot reset", ...); + +8042 pulse attempt: + log::warn!("acpid: sending 8042 keyboard-controller reset pulse (port 0x64, value 0xFE)"); + +8042 transition: + log::warn!("acpid: FADT reset_reg did not reboot; trying 8042 keyboard-controller pulse"); + +Terminal halt: + log::error!("acpid: ALL RESET MECHANISMS FAILED (PM1, FADT reset_reg, 8042) — halting system"); + +=== HOST-RUNNABLE UNIT TESTS (16/16 GREEN) === + +Command: + rustc --test local/sources/base/drivers/acpid/tests/fallback_chain_standalone.rs \ + -o /tmp/acpid-fallback-test && /tmp/acpid-fallback-test + +Output: + running 16 tests + test reboot_fallback_chain_without_reset_reg ... ok + test gas_address_space_unknown_is_not_resettable ... ok + test s5_fallback_chain_with_reset_reg ... ok + test gas_address_space_pci_config_is_resettable ... ok + test gas_constants_match_acpi_spec ... ok + test reboot_fallback_chain_with_reset_reg ... ok + test s5_bounded_delay_is_exactly_5_seconds ... ok + test gas_address_space_system_io_is_resettable ... ok + test s5_always_includes_pm1_write_first ... ok + test fallback_stages_have_distinct_discriminants ... ok + test all_chains_end_with_terminal_halt ... ok + test gas_address_space_system_memory_is_resettable ... ok + test s5_max_iterations_is_50 ... ok + test s5_fallback_chain_without_reset_reg ... ok + test s5_iterations_times_interval_equals_delay ... ok + test s5_poll_interval_is_100ms ... ok + + test result: ok. 16 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out + +Test coverage: + - GAS address space classification (System I/O, System Memory, PCI Config, Unknown) + - GAS address space naming + - S5 fallback chain with reset_reg: [Pm1Write, FadtResetReg, I8042Pulse, TerminalHalt] + - S5 fallback chain without reset_reg: [Pm1Write, I8042Pulse, TerminalHalt] + - Reboot fallback chain with reset_reg: [FadtResetReg, I8042Pulse, TerminalHalt] + - Reboot fallback chain without reset_reg: [I8042Pulse, TerminalHalt] + - S5 always starts with Pm1Write + - Every chain always terminates in TerminalHalt (no unbounded spin) + - Bounded delay = exactly 5 seconds + - Poll interval = exactly 100ms + - Max iterations = 50 (5000/100) + - Iterations × interval = delay (sanity check) + - GAS constants match ACPI 6.5 Table 5.1: 0=SysMem, 1=SysIO, 2=PCIConfig + - Fallback stage discriminants are all unique + +=== QEMU VERIFICATION COMMANDS === + +The orchestrator runs these after a canonical build of redbear-mini: + + # 1. Happy: S5 shutdown exits QEMU cleanly + ./local/scripts/build-redbear.sh redbear-mini + qemu-system-x86_64 -cdrom build/x86_64/redbear-mini.iso -m 1024 \ + -nographic -serial stdio + # Inside guest: poweroff + # Expected: QEMU exits cleanly (no hang). Serial log shows: + # "Sleep S5 with ACPI outw(...)" + # (no "S5 bounded wait expired" in normal case) + + # 2. Happy: reboot re-enters firmware boot + # Inside guest: (reboot; not yet wired through kernel kstop reason=4; + # scheduler may reboot via 8042 directly) + # Expected: QEMU resets and re-enters firmware boot + + # 3. Forced-failure QA (QA-only test build, NOT shipped): + # Point SLP_TYP at an invalid value so the firmware ignores the PM1 + # write. Builds a test ISO where the S5 path writes an invalid PM1 + # value, then: + # qemu-system-x86_64 -cdrom build/x86_64/redbear-mini-qa.iso \ + # -m 1024 -nographic -serial stdio + # # Inside guest: poweroff + # # Expected serial log: + # # "Sleep S5 with ACPI outw(...)" + # # (5 second pause) + # # "S5 bounded wait expired (5000 ms) — machine did not power off; executing fallback chain" + # # "attempting FADT reset_reg reboot: ..." + # # (machine resets instead of spinning — QEMU restarts) + # # If reset_reg also absent/fails: + # # "sending 8042 keyboard-controller reset pulse (port 0x64, value 0xFE)" + # # If 8042 also fails: + # # "ALL RESET MECHANISMS FAILED (PM1, FADT reset_reg, 8042) — halting system" + # # (machine halts, QEMU sits idle — operator sees the error) + + # 4. Verify cargo check is clean (no errors, warnings from our code only) + cd local/sources/base && cargo check -p acpid + # Expected: zero errors + + # 5. Standalone decision-logic tests (host-runnable) + rustc --test local/sources/base/drivers/acpid/tests/fallback_chain_standalone.rs \ + -o /tmp/acpid-fallback-test && /tmp/acpid-fallback-test + # Expected: 16/16 passed + +=== KSTOP REASON CODES (current state) === + + 0 = idle (no event) + 1 = shutdown (S5) → set_global_s_state(5) with bounded fallback + 2 = s2idle wake → exit_s2idle() (unchanged) + 3 = s3 wake → wake_from_sleep_state(3) (unchanged) + 4 = reboot → acpi_reboot() [NEW — requires kernel kstop_set_reason(4); + fallback path: FADT reset_reg → 8042 → halt] + +The kernel side (local/sources/kernel/src/scheme/acpi.rs) defines reason codes +0-3; reason=4 (reboot) needs to be added by the kernel agent. Until then, +the unknown/reason=4 path falls through to shutdown, preserving existing +behavior. When the kernel adds `kstop_set_reason(4)`, the acpid dispatch +will immediately route it to `acpi_reboot()`. + +=== DESIGN NOTES === + +- The \_S5 AML evaluation path, GPE/EC handling, \_PTS/\_SST calls, and + PM1a/PM1b write logic are all preserved unchanged. Only the post-write + behavior changed. +- The kstop/shutdown eventing (power button → mounted=false → S5 shutdown) + is preserved unchanged. +- No unwrap()/expect() in daemon code — all error paths use log::error! + or log::warn!. +- The 8042 pulse function is a free function (not &self method) because + it is the terminal fallback that does not depend on any ACPI state. +- FADT reset_reg System Memory and PCI Config address spaces are logged + as not-yet-implemented; only System I/O is functional. The X670E + desktop target uses System I/O reset registers (0xCF9 is common). +- As required, NO unbounded silent spin remains anywhere in the S5 path. diff --git a/local/sources/base b/local/sources/base index 7fce9aa585..3da0fe7ac4 160000 --- a/local/sources/base +++ b/local/sources/base @@ -1 +1 @@ -Subproject commit 7fce9aa5858a686c9262fcad3b6b22b66e9bdde2 +Subproject commit 3da0fe7ac4714d5e524d5b2c67c3f401392e1324