From 41e75d6721594ed0e412d35eab1abaa090f7e9c8 Mon Sep 17 00:00:00 2001 From: Donjuanplatinum Date: Thu, 16 Jul 2026 14:07:11 +0800 Subject: [PATCH 1/2] fix rsdp revision and rsdp checksum to fit linux kernel impl Signed-off-by: Donjuanplatinum --- src/lib.rs | 13 +++++-------- src/rsdp.rs | 13 +++++++++++-- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index feb69593..a898f5cd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -112,15 +112,12 @@ where } let rsdp_revision = rsdp_mapping.revision(); - let rsdt_address = if rsdp_revision == 0 { - // We're running on ACPI Version 1.0. We should use the 32-bit RSDT address. - rsdp_mapping.rsdt_address() as usize - } else { - /* - * We're running on ACPI Version 2.0+. We should use the 64-bit XSDT address, truncated - * to 32 bits on x86. - */ + // Use XSDT only when revision > 1, following Linux (tbutils.c). + // revision == 0 and revision == 1 both use the 32-bit RSDT address. + let rsdt_address = if rsdp_revision > 1 { rsdp_mapping.xsdt_address() as usize + } else { + rsdp_mapping.rsdt_address() as usize }; unsafe { Self::from_rsdt(handler, rsdp_revision, rsdt_address) } diff --git a/src/rsdp.rs b/src/rsdp.rs index 6cc37c2c..eccff81d 100644 --- a/src/rsdp.rs +++ b/src/rsdp.rs @@ -3,6 +3,8 @@ use core::{mem, ops::Range, slice, str}; /// The size in bytes of the ACPI 1.0 RSDP. const RSDP_V1_LENGTH: usize = 20; +/// The size in bytes covered by the ACPI 2.0+ extended checksum (mirrors Linux ACPI_RSDP_XCHECKSUM_LENGTH). +const RSDP_XCHECKSUM_LENGTH: usize = 36; /// The total size in bytes of the RSDP fields introduced in ACPI 2.0. const RSDP_V2_EXT_LENGTH: usize = mem::size_of::() - RSDP_V1_LENGTH; @@ -114,10 +116,17 @@ impl Rsdp { /* * `self.length` doesn't exist on ACPI version 1.0, so we mustn't rely on it. Instead, * check for version 1.0 and use a hard-coded length instead. + * + * For Version 2.0+, use the fixed constant size_of::() (= 36) rather than + * `self.length`, following Linux's ACPI_RSDP_XCHECKSUM_LENGTH. Trusting the + * firmware-provided `length` is unsafe: if it exceeds 36, `slice::from_raw_parts` + * would read past the mapped region, causing undefined behaviour. */ let length = if self.revision > 0 { - // For Version 2.0+, include the number of bytes specified by `length` - self.length as usize + if self.length as usize > RSDP_XCHECKSUM_LENGTH { + return Err(AcpiError::RsdpInvalidChecksum); + } + RSDP_XCHECKSUM_LENGTH } else { RSDP_V1_LENGTH }; From 8e496827d9a6d7403f5a13b4c6b76ae083f2e98a Mon Sep 17 00:00:00 2001 From: DonjuanPlatinum <113148619+donjuanplatinum@users.noreply.github.com> Date: Thu, 16 Jul 2026 16:16:43 +0800 Subject: [PATCH 2/2] Update rsdp.rs --- src/rsdp.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/rsdp.rs b/src/rsdp.rs index eccff81d..61c522a2 100644 --- a/src/rsdp.rs +++ b/src/rsdp.rs @@ -117,15 +117,9 @@ impl Rsdp { * `self.length` doesn't exist on ACPI version 1.0, so we mustn't rely on it. Instead, * check for version 1.0 and use a hard-coded length instead. * - * For Version 2.0+, use the fixed constant size_of::() (= 36) rather than - * `self.length`, following Linux's ACPI_RSDP_XCHECKSUM_LENGTH. Trusting the - * firmware-provided `length` is unsafe: if it exceeds 36, `slice::from_raw_parts` - * would read past the mapped region, causing undefined behaviour. + * For Version 2.0+, use the Linux's ACPI_RSDP_XCHECKSUM_LENGTH. */ - let length = if self.revision > 0 { - if self.length as usize > RSDP_XCHECKSUM_LENGTH { - return Err(AcpiError::RsdpInvalidChecksum); - } + let length = if self.revision > 1 { RSDP_XCHECKSUM_LENGTH } else { RSDP_V1_LENGTH