base: bump gitlink for acpid bounded S5 + reset-reg/8042 reboot (task 7)

This commit is contained in:
2026-08-05 03:19:19 +03:00
parent e6f6dbefaf
commit 5327f36716
2 changed files with 224 additions and 1 deletions
@@ -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.