acpid: Phase II.X.W S3 wake handling + kstop_enter_s3 helper
Phase II.X.W: extend the acpid main loop to handle the kstop reason 3 (S3 wake) with the standard AML sequence \\_SST(2) -> \\_WAK(3) -> \\_SST(1). Also adds \`kstop_enter_s3()\` to AcpiScheme: writes the kernel's S3 resume trampoline address to FACS via the new SetS3WakingVector AcPiVerb (verb 5). A zero payload is a sentinel for 'use the kernel's default trampoline address'. The acpid's enter_sleep_state for S3 will: 1. Do the AML prep (\\_TTS(3), \\_PTS(3), \\_SST(3)) - the existing set_global_s_state path. 2. Call kstop_enter_s3(0) to write the trampoline address to FACS. 3. Write 's3' to /scheme/sys/kstop to trigger the kernel's S3 entry path. Hardware-agnostic: works on any x86_64 system with standard ACPI S3 support (Dell, HP, Lenovo, LG Gram 14). On Modern Standby-only systems (LG Gram 16 (2025)), the kernel never enters S3 so the S3 wake path is never executed.
This commit is contained in:
@@ -166,9 +166,14 @@ fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
acpi_context.exit_s2idle();
|
||||
}
|
||||
3 => {
|
||||
// s3 wake (Phase II)
|
||||
log::info!("s3 wake (Phase II — not yet implemented)");
|
||||
// TODO: Phase II
|
||||
// s3 wake (Phase II.X.W)
|
||||
// Run the standard S3 resume AML sequence:
|
||||
// \_SST(2) -> \_WAK(3) -> \_SST(1). The kernel
|
||||
// trampoline at s3_resume::s3_trampoline
|
||||
// has already restored the kernel state. The
|
||||
// acpid's job is the AML wake sequence.
|
||||
log::info!("s3 wake: running \\_SST(2) -> \\_WAK(3) -> \\_SST(1)");
|
||||
acpi_context.wake_from_sleep_state(3);
|
||||
}
|
||||
other => {
|
||||
log::warn!("unknown kstop reason {}, treating as shutdown", other);
|
||||
|
||||
@@ -195,6 +195,25 @@ impl<'acpi, 'sock> AcpiScheme<'acpi, 'sock> {
|
||||
handle.call_wo(&[], CallFlags::empty(), &[verb])?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Phase II.X.W: write the kernel's S3 resume
|
||||
/// trampoline address to FACS.xfirmware_waking_vector so
|
||||
/// the platform firmware jumps to it on S3 wake.
|
||||
///
|
||||
/// `trampoline_addr` is the address of the kernel's
|
||||
/// `s3_resume::s3_trampoline` function. The kernel
|
||||
/// writes this to FACS via the `SetS3WakingVector`
|
||||
/// AcPiVerb (verb 5).
|
||||
pub fn kstop_enter_s3(&self, trampoline_addr: u64) -> syscall::Result<()> {
|
||||
let handle = self.kstop_fd.ok_or(syscall::error::Error::new(syscall::error::EBADF))?;
|
||||
let verb = AcpiVerb::SetS3WakingVector as u64;
|
||||
// Payload: 8-byte little-endian u64 (the trampoline
|
||||
// address). The kernel's `SetS3WakingVector` handler
|
||||
// requires the payload to be exactly 8 bytes.
|
||||
let payload = trampoline_addr.to_ne_bytes();
|
||||
handle.call_wo(&payload, CallFlags::empty(), &[verb])?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_hex_digit(hex: u8) -> Option<u8> {
|
||||
|
||||
Reference in New Issue
Block a user