diff --git a/src/arch/x86_shared/interrupt/mod.rs b/src/arch/x86_shared/interrupt/mod.rs index 794d5354b6..ad1ba0367f 100644 --- a/src/arch/x86_shared/interrupt/mod.rs +++ b/src/arch/x86_shared/interrupt/mod.rs @@ -107,6 +107,19 @@ pub unsafe fn mwait_loop(eax_hint: u32, ecx_hint: u32) { ); #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] let _ = (eax_hint, ecx_hint); + + // MWAIT returns when an interrupt fires (ecx=0 means + // "break on any interrupt"). The interrupt dispatcher + // has already run and returned by the time we get here. + // If the CPU was in s2idle (S2IDLE_REQUESTED was set by + // the kstop handler), we now know an SCI or other wake + // event has occurred. Clear the s2idle flag and trigger + // the kstop handle's EVENT_READ so acpid's main loop + // wakes up and runs the _WAK AML sequence. + if crate::scheme::acpi::s2idle_requested() { + crate::scheme::acpi::s2idle_request_clear(); + crate::scheme::acpi::s2idle_signal_wake(); + } } /// Probe MWAIT support and enter the deepest available C-state diff --git a/src/scheme/acpi.rs b/src/scheme/acpi.rs index 4ca307e818..66cede11eb 100644 --- a/src/scheme/acpi.rs +++ b/src/scheme/acpi.rs @@ -73,6 +73,28 @@ pub fn s2idle_requested() -> bool { S2IDLE_REQUESTED.load(Ordering::Acquire) } +/// Phase I: signal acpid that s2idle MWAIT was broken by an +/// interrupt. Called from `mwait_loop` after MWAIT returns. +/// Triggers the kstop handle's EVENT_READ so acpid's main loop +/// wakes and runs the \_SST(2) → \_WAK(0) → \_SST(1) AML +/// sequence on resume. +/// +/// Mirrors Linux 7.1 `acpi_s2idle_wake` in +/// `drivers/acpi/sleep.c:758` — the kernel clears +/// s2idle_state and signals the userspace ACPI driver. +pub fn s2idle_signal_wake() { + let mut token = CleanLockToken::new(); + *KSTOP_FLAG.lock(token.token()) = true; + if EXISTS_KSTOP_HANDLE.load(Ordering::Relaxed) { + crate::event::trigger( + GlobalSchemes::Acpi.scheme_id(), + HandleBits::KSTOP_HANDLE.bits(), + EventFlags::EVENT_READ, + &mut token, + ); + } +} + pub fn register_kstop(token: &mut CleanLockToken) -> bool { *KSTOP_FLAG.lock(token.token()) = true;