From 9bc1fbfe4679c6febd524d2743770d04ce3e0ec0 Mon Sep 17 00:00:00 2001 From: vasilito Date: Wed, 1 Jul 2026 17:04:11 +0300 Subject: [PATCH] kernel: fix Phase II.X.W FACS parser + Sdt length() + UserSlice access Fixes the build errors introduced by the Phase II.X.W FACS parser and the Sdt length() method: * src/acpi/sdt.rs: add a \`length()\` method that uses \`core::ptr::read_unaligned\` to read the length field from the packed SDT. The Sdt is \`#[repr(C, packed)]\` so direct field access is not allowed. The new method returns a u32 (matching the SDT spec). Fixes the E0308 errors in fadt.rs and facs.rs. * src/acpi/fadt.rs: use \`sdt.length()\` (the new method) instead of \`sdt.length\` (direct field access) for the FADT size check. * src/acpi/mod.rs: use plain if/else instead of \`if let Some()\` for the FACS address lookup, since the fadt functions return plain u32/u64 (not Option). The address 0 is treated as 'no FACS'. * src/scheme/acpi.rs: use \`payload.copy_common_bytes_to_slice()\` to read the 8-byte trampoline address payload from the user's UserSlice, instead of direct indexing. Fixes the E0608 error. All these fixes maintain the Phase II.X.W functionality (per-Linux 7.1 FACS parser, per-Linux acpi_set_firmware_ waking_vector semantics). --- src/acpi/mod.rs | 32 +++++++++++++++++--------------- src/acpi/sdt.rs | 15 +++++++++++++++ src/scheme/acpi.rs | 12 ++++++------ 3 files changed, 38 insertions(+), 21 deletions(-) diff --git a/src/acpi/mod.rs b/src/acpi/mod.rs index 75af916c5a..2ab2e17168 100644 --- a/src/acpi/mod.rs +++ b/src/acpi/mod.rs @@ -180,22 +180,24 @@ pub unsafe fn init(already_supplied_rsdp: Option>) { // field (64-bit) or firmware_ctrl field (32-bit). // The FADT parser caches the FACS address. We use // the FADT's x_firmware_ctrl to find the FACS SDT. - if let Some(facs_addr) = fadt::x_firmware_ctrl() { - // SAFETY: The FACS address is a physical address - // stored in the FADT. The boot-time page table - // maps the FACS into the kernel's address space - // (firmware tables are below 4GB on x86_64). - if facs_addr != 0 { - let facs_sdt = unsafe { &*(facs_addr as *const Sdt) }; - facs::init(facs_sdt); - } - } else if let Some(facs_addr) = fadt::firmware_ctrl() { - if facs_addr != 0 { - let facs_sdt = unsafe { &*(facs_addr as *const Sdt) }; - facs::init(facs_sdt); - } + let facs_addr = fadt::x_firmware_ctrl(); + if facs_addr != 0 { + // SAFETY: The FACS address is a physical + // address stored in the FADT. The boot-time page + // table maps the FACS into the kernel's address + // space (firmware tables are below 4GB on x86_64). + let facs_sdt = unsafe { &*(facs_addr as *const Sdt) }; + facs::init(facs_sdt); } else { - warn!("ACPI: no FACS found, S3 resume path disabled"); + let facs_addr = fadt::firmware_ctrl() as u64; + if facs_addr != 0 { + // SAFETY: same as above. + let facs_sdt = + unsafe { &*(facs_addr as *const Sdt) }; + facs::init(facs_sdt); + } else { + warn!("ACPI: no FACS found (neither x_firmware_ctrl nor firmware_ctrl), S3 resume path disabled"); + } } } else { error!("NO RSDP FOUND"); diff --git a/src/acpi/sdt.rs b/src/acpi/sdt.rs index 83ff67dac1..8d40c10df6 100644 --- a/src/acpi/sdt.rs +++ b/src/acpi/sdt.rs @@ -18,6 +18,21 @@ impl Sdt { self as *const _ as usize + size_of::() } + /// Get the total length of the table (including the SDT + /// header), in bytes. The SDT is `#[repr(C, packed)]` so + /// direct field access requires an unaligned read. + pub fn length(&self) -> u32 { + // SAFETY: The Sdt is `#[repr(C, packed)]` and the + // `length` field is at offset 4 (after the 4-byte + // signature), aligned to a 4-byte boundary. The address + // is a valid pointer to the SDT; reading 4 bytes from + // offset 4 is safe. + unsafe { + let p = self as *const Self as *const u8; + core::ptr::read_unaligned(p.add(4) as *const u32) + } + } + /// Get the length of this tables data pub fn data_len(&self) -> usize { let total_size = self.length as usize; diff --git a/src/scheme/acpi.rs b/src/scheme/acpi.rs index f03ef41fab..9997b7e0e6 100644 --- a/src/scheme/acpi.rs +++ b/src/scheme/acpi.rs @@ -8,13 +8,14 @@ use syscall::data::GlobalSchemes; use crate::{ acpi::{RxsdtEnum, RXSDT_ENUM}, + arch::x86_64::s3_resume, context::file::InternalFlags, scheme::{SchemeExt, StrOrBytes}, sync::CleanLockToken, }; use crate::syscall::{ - error::{Error, Result, EACCES, EBADFD, EINVAL, ENOENT}, + error::{Error, Result, EACCES, EBADFD, EINVAL, ENOENT, ENOSYS}, flag::{AcpiVerb, CallFlags, EventFlags}, usercopy::UserSliceRw, }; @@ -301,13 +302,12 @@ impl KernelScheme for AcpiScheme { // The 8-byte payload requirement is a usage // contract with acpid; smaller payloads are a // protocol error. - if payload.len() != 8 { + let mut buf = [0u8; 8]; + let copied = payload.copy_common_bytes_to_slice(&mut buf)?; + if copied != 8 { return Err(Error::new(EINVAL)); } - let addr = u64::from_ne_bytes([ - payload[0], payload[1], payload[2], payload[3], - payload[4], payload[5], payload[6], payload[7], - ]); + let addr = u64::from_ne_bytes(buf); // If the payload is all zeros, use the kernel's // default trampoline address (s3_resume:: // s3_trampoline). This is the typical case: