Browse Source

Nicer public API to parse RSDT & start of SDT dispatch

Isaac Woods 7 years ago
parent
commit
cbd5e7bc03
2 changed files with 94 additions and 60 deletions
  1. 62 59
      src/lib.rs
  2. 32 1
      src/sdt.rs

+ 62 - 59
src/lib.rs

@@ -67,79 +67,82 @@ pub trait AcpiHandler
     fn unmap_physical_region<T>(&mut self, region : PhysicalMapping<T>);
 }
 
-pub struct AcpiInfo<'a, H : 'a>
+/// This is the entry point of `acpi` if you have the **physical** address of the RSDP. It maps
+/// the RSDP, works out what version of ACPI the hardware supports, and passes the physical
+/// address of the RSDT/XSDT to `parse_rsdt`.
+pub fn parse_rsdp<H>(handler : &mut H, rsdp_address : usize) -> Result<(), AcpiError>
     where H : AcpiHandler
 {
-    handler     : &'a mut H,
-    revision    : u8,
+    let rsdp_mapping = handler.map_physical_region::<Rsdp>(rsdp_address);
+    (*rsdp_mapping).validate()?;
+    let revision = (*rsdp_mapping).revision();
+
+    if revision == 0
+    {
+        /*
+         * We're running on ACPI Version 1.0. We should use the 32-bit RSDT address.
+         */
+        let rsdt_address = (*rsdp_mapping).rsdt_address();
+        handler.unmap_physical_region(rsdp_mapping);
+        parse_rsdt(handler, revision, rsdt_address as usize)?;
+    }
+    else
+    {
+        /*
+         * We're running on ACPI Version 2.0+. We should use the 64-bit XSDT address, truncated
+         * to 32 bits on x86.
+         */
+        let xsdt_address = (*rsdp_mapping).xsdt_address();
+        handler.unmap_physical_region(rsdp_mapping);
+        parse_rsdt(handler, revision, xsdt_address as usize)?;
+    }
+
+    Ok(())
 }
 
-impl<'a, H> AcpiInfo<'a, H>
+/// This is the entry point of `acpi` if you already have the **physical** address of the
+/// RSDT/XSDT; it parses all the SDTs in the RSDT/XSDT, calling the relevant handlers in the
+/// implementation's `AcpiHandler`.
+///
+/// If the given revision is 0, an address to the RSDT is expected. Otherwise, an address to
+/// the XSDT is expected.
+pub fn parse_rsdt<H>(handler            : &mut H,
+                     revision           : u8,
+                     physical_address   : usize) -> Result<(), AcpiError>
     where H : AcpiHandler
 {
-    /// This is the entry point of `acpi` if you have the **physical** address of the RSDP. It maps
-    /// the RSDP, works out what version of ACPI the hardware supports, and passes the physical
-    /// address of the RSDT/XSDT to `parse_rsdt`.
-    pub fn parse_rsdp(handler : &'a mut H, rsdp_address : usize) -> Result<AcpiInfo<H>, AcpiError>
+    let mapping = handler.map_physical_region::<SdtHeader>(physical_address);
+
+    // TODO: extend the mapping to header.length
+    // TODO: validate the signature and checksum
+
+    if revision == 0
     {
-        let rsdp_mapping = handler.map_physical_region::<Rsdp>(rsdp_address);
-        (*rsdp_mapping).validate()?;
-        let revision = (*rsdp_mapping).revision();
+        /*
+         * ACPI Version 1.0. It's a RSDT!
+         */
+        let num_tables = ((*mapping).length() as usize - mem::size_of::<SdtHeader>()) / mem::size_of::<u32>();
+        let tables_base = ((mapping.virtual_start.as_ptr() as usize) + mem::size_of::<SdtHeader>()) as *const u32;
 
-        if revision == 0
+        for i in 0..num_tables
         {
-            /*
-             * We're running on ACPI Version 1.0. We should use the 32-bit RSDT address.
-             */
-            let rsdt_address = (*rsdp_mapping).rsdt_address();
-            handler.unmap_physical_region(rsdp_mapping);
-            AcpiInfo::parse_rsdt(handler, revision, rsdt_address as usize)
-        }
-        else
-        {
-            /*
-             * We're running on ACPI Version 2.0+. We should use the 64-bit XSDT address, truncated
-             * to 32 bits on x86.
-             */
-            let xsdt_address = (*rsdp_mapping).xsdt_address();
-            handler.unmap_physical_region(rsdp_mapping);
-            AcpiInfo::parse_rsdt(handler, revision, xsdt_address as usize)
+            sdt::dispatch_sdt(handler, unsafe { *tables_base.offset(i as isize) } as usize)?;
         }
     }
-
-    /// This is the entry point of `acpi` if you already have the **physical** address of the
-    /// RSDT/XSDT; it parses all the SDTs in the RSDT/XSDT, calling the relevant handlers in the
-    /// implementation's `AcpiHandler`.
-    ///
-    /// If the given revision is 0, an address to the RSDT is expected. Otherwise, an address to
-    /// the XSDT is expected.
-    pub fn parse_rsdt(handler           : &'a mut H,
-                      revision          : u8,
-                      physical_address  : usize) -> Result<AcpiInfo<H>, AcpiError>
+    else
     {
-        let mapping = handler.map_physical_region::<SdtHeader>(physical_address);
-
-        // TODO: extend the mapping to header.length
-        // TODO: validate the signature and checksum
+        /*
+         * ACPI Version 2.0+. It's a XSDT!
+         */
+        let num_tables = ((*mapping).length() as usize - mem::size_of::<SdtHeader>()) / mem::size_of::<u64>();
+        let tables_base = ((mapping.virtual_start.as_ptr() as usize) + mem::size_of::<SdtHeader>()) as *const u64;
 
-        if revision == 0
+        for i in 0..num_tables
         {
-            /*
-             * ACPI Version 1.0. It's a RSDT!
-             */
-            let num_tables = ((*mapping).length() as usize - mem::size_of::<SdtHeader>()) / mem::size_of::<u32>();
-            let pointer_base = ((mapping.virtual_start.as_ptr() as usize) + mem::size_of::<SdtHeader>()) as *const u32;
+            sdt::dispatch_sdt(handler, unsafe { *tables_base.offset(i as isize) } as usize)?;
         }
-        else
-        {
-            /*
-             * ACPI Version 2.0+. It's a XSDT!
-             */
-            let num_tables = ((*mapping).length() as usize - mem::size_of::<SdtHeader>()) / mem::size_of::<u64>();
-            let pointer_base = ((mapping.virtual_start.as_ptr() as usize) + mem::size_of::<SdtHeader>()) as *const u64;
-        }
-
-        handler.unmap_physical_region(mapping);
-        unimplemented!();
     }
+
+    handler.unmap_physical_region(mapping);
+    Ok(())
 }

+ 32 - 1
src/sdt.rs

@@ -1,5 +1,5 @@
 use core::str;
-use AcpiError;
+use {AcpiError, AcpiHandler};
 
 /// All SDTs share the same header, and are `length` bytes long. The signature tells us which SDT
 /// this is.
@@ -88,3 +88,34 @@ impl SdtHeader
         str::from_utf8(&self.oem_table_id).unwrap()
     }
 }
+
+/// 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
+        {
+            _ =>
+            {
+                /*
+                 * 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
+                 */
+                // TODO: add warn!()
+            },
+        }
+    }
+
+    handler.unmap_physical_region(header_mapping);
+    Ok(())
+}