浏览代码

Add structures for RSDP and SDT headers

Isaac Woods 7 年之前
父节点
当前提交
ca97d035a3
共有 2 个文件被更改,包括 109 次插入0 次删除
  1. 54 0
      src/lib.rs
  2. 55 0
      src/rsdp.rs

+ 54 - 0
src/lib.rs

@@ -2,3 +2,57 @@
 
 #[cfg(test)]
 extern crate std;
+
+mod rsdp;
+
+pub use rsdp::Rsdp;
+
+use core::str;
+
+/// All SDTs share the same header, and are `length` bytes long. The signature tells us which SDT
+/// this is.
+#[repr(C, packed)]
+pub struct SdtHeader
+{
+    signature           : [u8; 4],
+    length              : u32,
+    revision            : u8,
+    checksum            : u8,
+    oem_id              : [u8; 6],
+    oem_table_id        : [u8; 8],
+    oem_revision        : u32,
+    creator_id          : u32,
+    creator_revision    : u32,
+}
+
+impl SdtHeader
+{
+    /// Check that:
+    ///     a) The signature is valid UTF8
+    ///     b) The checksum of the SDT.
+    ///
+    /// This assumes that the whole SDT is mapped.
+    fn validate(&self) -> Result<(), &str>
+    {
+        // Check the signature
+        if str::from_utf8(&self.signature).is_err()
+        {
+            return Err("SDT signature is not valid UTF8");
+        }
+
+        // Sum all bytes in the SDT (not just the header)
+        let mut sum : usize = 0;
+        for i in 0..self.length
+        {
+            sum += unsafe { *(self as *const SdtHeader as *const u8).offset(i as isize) } as usize;
+        }
+
+        // Check that the lowest byte is 0
+        if sum & 0b1111_1111 != 0
+        {
+            return Err("SDT has incorrect checksum");
+        }
+
+        Ok(())
+    }
+}

+ 55 - 0
src/rsdp.rs

@@ -0,0 +1,55 @@
+use core::mem;
+
+/// The first structure found in ACPI. It just tells us where the RSDT is.
+///
+/// On BIOS systems, it is either found in the first 1KB of the Extended Bios Data Area, or between
+/// 0x000E0000 and 0x000FFFFF. The signature is always on a 16 byte boundary. On (U)EFI, it may not
+/// be located in these locations, and so an address should be found in the EFI_SYSTEM_TABLE instead.
+///
+/// The recommended way of locating the RSDP is to let the bootloader do it - Multiboot2 can pass a
+/// tag with the physical address of it. If this is not possible, a manual scan can be done.
+#[repr(C, packed)]
+pub struct Rsdp
+{
+    pub(crate) signature    : [u8; 8],
+    pub(crate) checksum     : u8,
+    pub(crate) oem_id       : [u8; 6],
+    pub(crate) revision     : u8,
+    pub(crate) rsdt_address : u32,
+}
+
+impl Rsdp
+{
+    /// Checks that:
+    ///     1) The signature is correct
+    ///     2) The checksum is correct
+    ///     3) For Version 2.0+, that the extension checksum is correct
+    pub(crate) fn validate(&self) -> Result<(), &str>
+    {
+        // 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 "
+        {
+            return Err("RSDP has incorrect signature");
+        }
+
+        // Sum all bytes in the structure
+        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;
+        }
+
+        // Check that the lowest byte is 0
+        if sum & 0b1111_1111 != 0
+        {
+            return Err("RSDP has incorrect checksum");
+        }
+
+        Ok(())
+    }
+}