Browse Source

Merge #26

26: Fixed rsdp validation and dsdt address finding r=IsaacWoods a=Restioson

This is kind of a "band-aid" fix to get ACPI to work. It fixes RSDP checksumming and makes sure that the FACP `x_dsdt` field is not used if it is not there (`rev > 1`). In future for `x_` fields we should have a type safe solution, so this is just an interim fix.

WIP:
- [x] Check that the lowest revision with `x_dsdt` is correct

Co-authored-by: restioson <restiosondev@gmail.com>
bors[bot] 6 years ago
parent
commit
a3dfbf54b6
2 changed files with 21 additions and 31 deletions
  1. 6 4
      src/fadt.rs
  2. 15 27
      src/rsdp.rs

+ 6 - 4
src/fadt.rs

@@ -82,12 +82,14 @@ pub(crate) fn parse_fadt<H>(
 where
     H: AcpiHandler,
 {
-    (*mapping).header.validate(b"FACP")?;
+    let fadt = &*mapping;
+    fadt.header.validate(b"FACP")?;
 
-    let dsdt_physical_address: usize = if (*mapping).x_dsdt_address != 0 {
-        (*mapping).x_dsdt_address as usize
+    // TODO more generic typesafe way of accessing the x_ fields
+    let dsdt_physical_address: usize = if fadt.header.revision() > 1 && fadt.x_dsdt_address != 0 {
+        fadt.x_dsdt_address as usize
     } else {
-        (*mapping).dsdt_address as usize
+        fadt.dsdt_address as usize
     };
 
     // Parse the DSDT

+ 15 - 27
src/rsdp.rs

@@ -1,5 +1,5 @@
 use super::AcpiError;
-use core::str;
+use core::{mem, str};
 
 /// The first structure found in ACPI. It just tells us where the RSDT is.
 ///
@@ -47,34 +47,22 @@ impl Rsdp {
             return Err(AcpiError::RsdpInvalidOemId);
         }
 
-        // Check the fields present in all versions against `checksum`
-        let mut sum: usize = 0;
-        sum += self
-            .signature
-            .iter()
-            .map(|&b| usize::from(b))
-            .sum::<usize>();
-        sum += self.checksum as usize;
-        sum += self.oem_id.iter().map(|&b| usize::from(b)).sum::<usize>();
-        sum += self.revision as usize;
-        sum += self.rsdt_address as usize;
-
-        // Check that the lowest byte is 0
-        if sum & 0b1111_1111 != 0 {
-            return Err(AcpiError::RsdpInvalidChecksum);
+        let len = if self.revision > 0 {
+            // For Version 2.0+, check ALL the fields
+            mem::size_of::<Self>()
+        } else {
+            // For Version 1, only check fields up to v1 length only
+            20
+        };
+
+        let self_ptr = self as *const Rsdp as *const u8;
+        let mut sum: u8 = 0;
+        for i in 0..self.length {
+            sum = sum.wrapping_add(unsafe { *(self_ptr.offset(i as isize)) } as u8);
         }
 
-        // For Version 2.0+, check the extension checksum too
-        if self.revision > 0 {
-            let mut sum: usize = 0;
-            sum += self.length as usize;
-            sum += self.xsdt_address as usize;
-            sum += self.ext_checksum as usize;
-            sum += self.reserved.iter().map(|&b| usize::from(b)).sum::<usize>();
-
-            if sum & 0b1111_1111 != 0 {
-                return Err(AcpiError::RsdpInvalidChecksum);
-            }
+        if sum != 0 {
+            return Err(AcpiError::RsdpInvalidChecksum);
         }
 
         Ok(())