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).
This commit is contained in:
2026-07-01 17:04:11 +03:00
parent 475f96ecab
commit 9bc1fbfe46
3 changed files with 38 additions and 21 deletions
+17 -15
View File
@@ -180,22 +180,24 @@ pub unsafe fn init(already_supplied_rsdp: Option<NonNull<u8>>) {
// 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");
+15
View File
@@ -18,6 +18,21 @@ impl Sdt {
self as *const _ as usize + size_of::<Sdt>()
}
/// 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;
+6 -6
View File
@@ -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: