Browse Source

Properly extend SDT mappings and fix DSDT mapping

Isaac Woods 6 years ago
parent
commit
57f8ccd2a0
4 changed files with 64 additions and 44 deletions
  1. 1 5
      src/dsdt.rs
  2. 4 1
      src/fadt.rs
  3. 14 8
      src/lib.rs
  4. 45 30
      src/sdt.rs

+ 1 - 5
src/dsdt.rs

@@ -10,10 +10,6 @@ pub struct Dsdt {
 }
 
 impl Dsdt {
-    pub fn validate(&self) -> Result<(), AcpiError> {
-        self.header.validate(b"DSDT")
-    }
-
     /// Get the AML stream encoded in this table so it can be safely accessed
     pub fn stream(&self) -> &[u8] {
         assert!(self.header.length() as usize > mem::size_of::<SdtHeader>());
@@ -25,7 +21,7 @@ impl Dsdt {
 }
 
 pub fn parse_dsdt(mapping: &PhysicalMapping<Dsdt>) -> Result<(), AcpiError> {
-    (*mapping).validate()?;
+    (*mapping).header.validate(b"DSDT")?;
 
     let stream = (*mapping).stream();
     // TODO: pass off to the AML parser

+ 4 - 1
src/fadt.rs

@@ -1,4 +1,5 @@
 use dsdt::{parse_dsdt, Dsdt};
+use sdt;
 use sdt::SdtHeader;
 use {AcpiError, AcpiHandler, GenericAddress, PhysicalMapping};
 
@@ -86,7 +87,9 @@ where
     };
 
     // Parse the DSDT
-    let dsdt_mapping = handler.map_physical_region::<Dsdt>(dsdt_physical_address);
+    let dsdt_header = sdt::peek_at_sdt_header(handler, dsdt_physical_address);
+    let dsdt_mapping =
+        handler.map_physical_region::<Dsdt>(dsdt_physical_address, dsdt_header.length() as usize);
     parse_dsdt(&dsdt_mapping)?;
     handler.unmap_physical_region(dsdt_mapping);
 

+ 14 - 8
src/lib.rs

@@ -66,11 +66,16 @@ impl<T> Deref for PhysicalMapping<T> {
 /// `acpi` to tell the kernel about the tables it's parsing, such as how the kernel should
 /// configure the APIC or PCI routing.
 pub trait AcpiHandler {
-    /// Given a starting physical address, map a region of physical memory that contains a `T`
-    /// somewhere in the virtual address space. The address doesn't have to be page-aligned, so
-    /// the implementation may have to add padding to either end. The supplied size must be large
-    /// enough to hold a `T`, but may also be larger.
-    fn map_physical_region<T>(&mut self, physical_address: usize) -> PhysicalMapping<T>;
+    /// Given a starting physical address and a size, map a region of physical memory that contains
+    /// a `T` (but may be bigger than `size_of::<T>()`). The address doesn't have to be page-aligned,
+    /// so the implementation may have to add padding to either end. The given size must be greater
+    /// or equal to the size of a `T`. The virtual address the memory is mapped to does not matter,
+    /// as long as it is accessibly by `acpi`.
+    fn map_physical_region<T>(
+        &mut self,
+        physical_address: usize,
+        size: usize,
+    ) -> PhysicalMapping<T>;
 
     /// Unmap the given physical mapping. Safe because we consume the mapping, and so it can't be
     /// used after being passed to this function.
@@ -84,7 +89,7 @@ pub fn parse_rsdp<H>(handler: &mut H, rsdp_address: usize) -> Result<(), AcpiErr
 where
     H: AcpiHandler,
 {
-    let rsdp_mapping = handler.map_physical_region::<Rsdp>(rsdp_address);
+    let rsdp_mapping = handler.map_physical_region::<Rsdp>(rsdp_address, mem::size_of::<Rsdp>());
     (*rsdp_mapping).validate()?;
     let revision = (*rsdp_mapping).revision();
 
@@ -122,8 +127,9 @@ pub fn parse_rsdt<H>(
 where
     H: AcpiHandler,
 {
-    let mapping = handler.map_physical_region::<SdtHeader>(physical_address);
-    // TODO: extend the mapping to header.length
+    let header = sdt::peek_at_sdt_header(handler, physical_address);
+    let mapping =
+        handler.map_physical_region::<SdtHeader>(physical_address, header.length() as usize);
 
     if revision == 0 {
         /*

+ 45 - 30
src/sdt.rs

@@ -80,7 +80,6 @@ impl SdtHeader {
         }
 
         if sum > 0 {
-            error!("Checksum wrong: {}", sum);
             return Err(AcpiError::SdtInvalidChecksum(*signature));
         }
 
@@ -140,43 +139,59 @@ impl SdtHeader {
     }
 }
 
+/// Takes the physical address of an SDT, and maps, clones and unmaps its header. Useful for
+/// finding out how big it is to map it correctly later.
+pub(crate) fn peek_at_sdt_header<H>(handler: &mut H, physical_address: usize) -> SdtHeader
+where
+    H: AcpiHandler,
+{
+    let mapping =
+        handler.map_physical_region::<SdtHeader>(physical_address, mem::size_of::<SdtHeader>());
+    let header = (*mapping).clone();
+    handler.unmap_physical_region(mapping);
+
+    header
+}
+
 /// This takes the physical address of an SDT, maps it correctly and dispatches it to whatever
 /// function parses that table.
 pub(crate) fn dispatch_sdt<H>(handler: &mut H, physical_address: usize) -> Result<(), AcpiError>
 where
     H: AcpiHandler,
 {
-    let header_mapping = handler.map_physical_region::<SdtHeader>(physical_address);
-    {
-        let signature = (*header_mapping).signature();
-        let length = (*header_mapping).length();
-
-        /*
-         * For a recognised signature, a new physical mapping should be created with the correct type
-         * and length, and then the dispatched to the correct function to actually parse the table.
-         */
-        match signature {
-            "FACP" => {
-                let fadt_mapping = handler.map_physical_region::<Fadt>(physical_address);
-                ::fadt::parse_fadt(handler, &fadt_mapping)?;
-                handler.unmap_physical_region(fadt_mapping);
-            }
-            "HPET" => {
-                let hpet_mapping = handler.map_physical_region::<Hpet>(physical_address);
-                ::hpet::parse_hpet(&hpet_mapping)?;
-                handler.unmap_physical_region(hpet_mapping);
-            }
-
-            _ => {
-                /*
-                 * We don't recognise this signature. Early on, this probably just means we don't
-                 * have support yet, but later on maybe this should become an actual error
-                 */
-                warn!("Unsupported SDT signature: {}. Skipping.", signature);
-            }
+    let header = peek_at_sdt_header(handler, physical_address);
+    info!(
+        "Dispatching SDT with signature {:?} and length {:?}",
+        header.signature(),
+        header.length()
+    );
+
+    /*
+     * For a recognised signature, a new physical mapping should be created with the correct type
+     * and length, and then the dispatched to the correct function to actually parse the table.
+     */
+    match header.signature() {
+        "FACP" => {
+            let fadt_mapping =
+                handler.map_physical_region::<Fadt>(physical_address, mem::size_of::<Fadt>());
+            ::fadt::parse_fadt(handler, &fadt_mapping)?;
+            handler.unmap_physical_region(fadt_mapping);
+        }
+
+        "HPET" => {
+            let hpet_mapping = handler.map_physical_region::<Hpet>(physical_address);
+            ::hpet::parse_hpet(&hpet_mapping)?;
+            handler.unmap_physical_region(hpet_mapping);
+        }
+
+        signature => {
+            /*
+             * We don't recognise this signature. Early on, this probably just means we don't
+             * have support yet, but later on maybe this should become an actual error
+             */
+            warn!("Unsupported SDT signature: {}. Skipping.", signature);
         }
     }
 
-    handler.unmap_physical_region(header_mapping);
     Ok(())
 }