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:
+17
-15
@@ -180,22 +180,24 @@ pub unsafe fn init(already_supplied_rsdp: Option<NonNull<u8>>) {
|
|||||||
// field (64-bit) or firmware_ctrl field (32-bit).
|
// field (64-bit) or firmware_ctrl field (32-bit).
|
||||||
// The FADT parser caches the FACS address. We use
|
// The FADT parser caches the FACS address. We use
|
||||||
// the FADT's x_firmware_ctrl to find the FACS SDT.
|
// the FADT's x_firmware_ctrl to find the FACS SDT.
|
||||||
if let Some(facs_addr) = fadt::x_firmware_ctrl() {
|
let facs_addr = fadt::x_firmware_ctrl();
|
||||||
// SAFETY: The FACS address is a physical address
|
if facs_addr != 0 {
|
||||||
// stored in the FADT. The boot-time page table
|
// SAFETY: The FACS address is a physical
|
||||||
// maps the FACS into the kernel's address space
|
// address stored in the FADT. The boot-time page
|
||||||
// (firmware tables are below 4GB on x86_64).
|
// table maps the FACS into the kernel's address
|
||||||
if facs_addr != 0 {
|
// space (firmware tables are below 4GB on x86_64).
|
||||||
let facs_sdt = unsafe { &*(facs_addr as *const Sdt) };
|
let facs_sdt = unsafe { &*(facs_addr as *const Sdt) };
|
||||||
facs::init(facs_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);
|
|
||||||
}
|
|
||||||
} else {
|
} 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 {
|
} else {
|
||||||
error!("NO RSDP FOUND");
|
error!("NO RSDP FOUND");
|
||||||
|
|||||||
@@ -18,6 +18,21 @@ impl Sdt {
|
|||||||
self as *const _ as usize + size_of::<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
|
/// Get the length of this tables data
|
||||||
pub fn data_len(&self) -> usize {
|
pub fn data_len(&self) -> usize {
|
||||||
let total_size = self.length as usize;
|
let total_size = self.length as usize;
|
||||||
|
|||||||
+6
-6
@@ -8,13 +8,14 @@ use syscall::data::GlobalSchemes;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
acpi::{RxsdtEnum, RXSDT_ENUM},
|
acpi::{RxsdtEnum, RXSDT_ENUM},
|
||||||
|
arch::x86_64::s3_resume,
|
||||||
context::file::InternalFlags,
|
context::file::InternalFlags,
|
||||||
scheme::{SchemeExt, StrOrBytes},
|
scheme::{SchemeExt, StrOrBytes},
|
||||||
sync::CleanLockToken,
|
sync::CleanLockToken,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::syscall::{
|
use crate::syscall::{
|
||||||
error::{Error, Result, EACCES, EBADFD, EINVAL, ENOENT},
|
error::{Error, Result, EACCES, EBADFD, EINVAL, ENOENT, ENOSYS},
|
||||||
flag::{AcpiVerb, CallFlags, EventFlags},
|
flag::{AcpiVerb, CallFlags, EventFlags},
|
||||||
usercopy::UserSliceRw,
|
usercopy::UserSliceRw,
|
||||||
};
|
};
|
||||||
@@ -301,13 +302,12 @@ impl KernelScheme for AcpiScheme {
|
|||||||
// The 8-byte payload requirement is a usage
|
// The 8-byte payload requirement is a usage
|
||||||
// contract with acpid; smaller payloads are a
|
// contract with acpid; smaller payloads are a
|
||||||
// protocol error.
|
// 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));
|
return Err(Error::new(EINVAL));
|
||||||
}
|
}
|
||||||
let addr = u64::from_ne_bytes([
|
let addr = u64::from_ne_bytes(buf);
|
||||||
payload[0], payload[1], payload[2], payload[3],
|
|
||||||
payload[4], payload[5], payload[6], payload[7],
|
|
||||||
]);
|
|
||||||
// If the payload is all zeros, use the kernel's
|
// If the payload is all zeros, use the kernel's
|
||||||
// default trampoline address (s3_resume::
|
// default trampoline address (s3_resume::
|
||||||
// s3_trampoline). This is the typical case:
|
// s3_trampoline). This is the typical case:
|
||||||
|
|||||||
Reference in New Issue
Block a user