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>