Browse Source

Fix RSDP validation

Isaac Woods 7 years ago
parent
commit
d85db248f4
1 changed files with 24 additions and 11 deletions
  1. 24 11
      src/rsdp.rs

+ 24 - 11
src/rsdp.rs

@@ -1,4 +1,4 @@
-use core::{str,mem};
+use core::str;
 use super::AcpiError;
 
 /// The first structure found in ACPI. It just tells us where the RSDT is.
@@ -12,6 +12,8 @@ use super::AcpiError;
 ///
 /// If `revision > 0`, (the hardware ACPI version is Version 2.0 or greater), the RSDP contains
 /// some new fields. For ACPI Version 1.0, these fields are not valid and should not be accessed.
+/// For ACPI Version 2.0+, `xsdt_address` should be used (truncated to `u32` on x86) instead of
+/// `rsdt_address`.
 #[repr(C, packed)]
 pub(crate) struct Rsdp
 {
@@ -38,11 +40,6 @@ impl Rsdp
     ///     3) For Version 2.0+, that the extension checksum is correct
     pub(crate) fn validate(&self) -> Result<(), AcpiError>
     {
-        // FIXME: Check what version of ACPI this is. This works for Version 1.0 (revision=0), but
-        // for subsequent versions, we also need to check the checksum for the extension fields.
-        // In fact, should we rewrite this to be clearer what fields we're testing for each
-        // checksum?
-
         // Check the signature
         if &self.signature != b"RSD PTR "
         {
@@ -55,12 +52,13 @@ impl Rsdp
             return Err(AcpiError::RsdpInvalidOemId);
         }
 
-        // Sum all bytes in the structure
+        // Check the fields present in all versions against `checksum`
         let mut sum : usize = 0;
-        for i in 0..mem::size_of::<Rsdp>()
-        {
-            sum += unsafe { *(self as *const Rsdp as *const u8).offset(i as isize) } as usize;
-        }
+        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
@@ -68,6 +66,21 @@ impl Rsdp
             return Err(AcpiError::RsdpInvalidChecksum);
         }
 
+        // 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);
+            }
+        }
+
         Ok(())
     }