瀏覽代碼

Merge #10

10: Checksums once and for all r=IsaacWoods a=IsaacWoods

This isn't ready yet, but the SDT checksum code has been bugging me and definitely isn't correct because it doesn't validate tables produced by `iasl` (the official compiler for ASL), so I decided to look into it properly.

ACPICA does this to calculate the checksum of a SDT:
``` c
UINT8
AcpiTbChecksum (
    UINT8                   *Buffer,
    UINT32                  Length)
{
    UINT8                   Sum = 0;
    UINT8                   *End = Buffer + Length;

    while (Buffer < End)
    {
        Sum = (UINT8) (Sum + *(Buffer++));
    }

    return (Sum);
}
```
Now, this works because in C, unsigned integer overflow is defined like so (ISO/IEC 9899:2011 6.2.5.9):
> A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.

So effectively, addition on unsigned types is a wrapping operator, and so the correct code in Rust afaik would look like:
``` rust
let self_ptr = self as *const SdtHeader 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);
}

if sum > 0 {
    return Err(AcpiError::SdtInvalidChecksum);
}
```

I still have no idea why the other way works in Pebble but not here, but this does appear to work now with the RSDP, just need to test with some more real and constructed SDTs now.

Co-authored-by: Isaac Woods <isaacwoods.home@gmail.com>
bors[bot] 7 年之前
父節點
當前提交
fac8b37314
共有 2 個文件被更改,包括 9 次插入5 次删除
  1. 4 0
      src/lib.rs
  2. 5 5
      src/sdt.rs

+ 4 - 0
src/lib.rs

@@ -122,6 +122,8 @@ where
         /*
          * ACPI Version 1.0. It's a RSDT!
          */
+        (*mapping).validate(b"RSDT")?;
+
         let num_tables =
             ((*mapping).length() as usize - mem::size_of::<SdtHeader>()) / mem::size_of::<u32>();
         let tables_base =
@@ -134,6 +136,8 @@ where
         /*
          * ACPI Version 2.0+. It's a XSDT!
          */
+        (*mapping).validate(b"XSDT")?;
+
         let num_tables =
             ((*mapping).length() as usize - mem::size_of::<SdtHeader>()) / mem::size_of::<u64>();
         let tables_base =

+ 5 - 5
src/sdt.rs

@@ -39,14 +39,14 @@ impl SdtHeader {
             return Err(AcpiError::SdtInvalidTableId);
         }
 
-        // Sum all bytes in the SDT (not just the header)
-        let mut sum: usize = 0;
+        // Validate the checksum
+        let self_ptr = self as *const SdtHeader as *const u8;
+        let mut sum: u8 = 0;
         for i in 0..self.length {
-            sum += unsafe { *(self as *const SdtHeader as *const u8).offset(i as isize) } as usize;
+            sum = sum.wrapping_add(unsafe { *(self_ptr.offset(i as isize)) } as u8);
         }
 
-        // Check that the lowest byte is 0
-        if sum % 0b1111_1111 != 0 {
+        if sum > 0 {
             return Err(AcpiError::SdtInvalidChecksum);
         }