Browse Source

Merge #3

3: Add Fadt structure r=IsaacWoods a=Sh4d1

Start to fix #2 

Signed-off-by: Patrik Cyvoct <patrik@ptrk.io>

Co-authored-by: Patrik Cyvoct <patrik@ptrk.io>
bors[bot] 7 years ago
parent
commit
248d374ba6
4 changed files with 217 additions and 5 deletions
  1. 22 2
      src/constructed_tables_test.rs
  2. 182 0
      src/fadt.rs
  3. 4 0
      src/lib.rs
  4. 9 3
      src/sdt.rs

+ 22 - 2
src/constructed_tables_test.rs

@@ -1,4 +1,4 @@
-use super::{parse_rsdp, rsdp::Rsdp, sdt::SdtHeader, AcpiHandler, PhysicalMapping};
+use super::{fadt::Fadt, parse_rsdp, rsdp::Rsdp, sdt::SdtHeader, AcpiHandler, PhysicalMapping};
 use std::boxed::Box;
 /// These tests cover ideal sets of ACPI tables, which we construct on the fly. Eventually, this
 /// should cover all compliant implementations, but does not guarantee we'll be able to parse a
@@ -15,10 +15,12 @@ const OEM_ID: &[u8; 6] = b"RUST  ";
  */
 const RSDP_ADDRESS: usize = 0x0;
 const RSDT_ADDRESS: usize = 0x1;
+const FADT_ADDRESS: usize = 0x2;
 
 #[repr(C, packed)]
 struct TestRsdt {
     header: SdtHeader,
+    fadt: u32,
     // TODO: We should probably actually add some SDTs
 }
 
@@ -64,6 +66,7 @@ impl AcpiHandler for TestHandler {
                         0xDEADBEEF,
                         0xDEADBEEF,
                     ),
+                    fadt: FADT_ADDRESS as u32,
                 });
 
                 PhysicalMapping {
@@ -75,6 +78,23 @@ impl AcpiHandler for TestHandler {
                     mapped_length: mem::size_of::<TestRsdt>(),
                 }
             }
+            FADT_ADDRESS => {
+                let fadt = Box::new(Fadt::make_testcase(
+                    *OEM_ID,
+                    *b"OEMFADT ",
+                    0xDEADBEEF,
+                    0xDEADBEEF,
+                    0xDEADBEEF,
+                ));
+                PhysicalMapping {
+                    physical_start: FADT_ADDRESS,
+                    virtual_start: unsafe {
+                        NonNull::<T>::new_unchecked(Box::into_raw(fadt) as *mut T)
+                    },
+                    region_length: mem::size_of::<Fadt>(),
+                    mapped_length: mem::size_of::<Fadt>(),
+                }
+            }
 
             _ => panic!(
                 "ACPI requested invalid physical address: {:#x}",
@@ -85,7 +105,7 @@ impl AcpiHandler for TestHandler {
 
     fn unmap_physical_region<T>(&mut self, region: PhysicalMapping<T>) {
         match region.physical_start {
-            RSDP_ADDRESS | RSDT_ADDRESS => {
+            RSDP_ADDRESS | RSDT_ADDRESS | FADT_ADDRESS => {
                 let _ = unsafe { Box::from_raw(region.virtual_start.as_ptr()) };
             }
 

+ 182 - 0
src/fadt.rs

@@ -0,0 +1,182 @@
+use sdt::SdtHeader;
+#[cfg(test)]
+use std::mem;
+use {AcpiError, PhysicalMapping};
+
+#[repr(C, packed)]
+struct GenericAddress {
+    address_space: u8,
+    bit_width: u8,
+    bit_offset: u8,
+    access_size: u8,
+    address: u64,
+}
+
+impl GenericAddress {
+    #[cfg(test)]
+    pub(crate) fn make_testcase() -> GenericAddress {
+        GenericAddress {
+            address_space: 0 as u8,
+            bit_width: 0 as u8,
+            bit_offset: 0 as u8,
+            access_size: 0 as u8,
+            address: 0 as u64,
+        }
+    }
+}
+
+#[repr(C, packed)]
+pub struct Fadt {
+    // header
+    header: SdtHeader,
+
+    firmware_ctrl: u32,
+    dsdt_address: u32,
+
+    // used in acpi 1.0; compatibility only, should be zero
+    reserved: u8,
+
+    preferred_pm_profile: u8,
+    sci_interrupt: u16,
+    smi_cmd_port: u32,
+    acpi_enable: u8,
+    acpi_disable: u8,
+    s4bios_req: u8,
+    pstate_control: u8,
+    pm1a_event_block: u32,
+    pm1b_event_block: u32,
+    pm1a_control_block: u32,
+    pm1b_control_block: u32,
+    pm2_control_block: u32,
+    pm_timer_block: u32,
+    gpe0_block: u32,
+    gpe1_block: u32,
+    pm1_event_length: u8,
+    pm1_control_length: u8,
+    pm2_control_length: u8,
+    pm_timer_length: u8,
+    gpe0_block_length: u8,
+    gpe1_block_length: u8,
+    gpe1_base: u8,
+    c_state_control: u8,
+    worst_c2_latency: u16,
+    worst_c3_latency: u16,
+    flush_size: u16,
+    flush_stride: u16,
+    duty_offset: u8,
+    duty_width: u8,
+    day_alarm: u8,
+    month_alarm: u8,
+    century: u8,
+    iapc_boot_arch: u16,
+    reserved2: u8, // must be 0
+    flags: u32,
+    reset_reg: GenericAddress,
+    reset_value: u8,
+    arm_boot_arch: u16,
+    fadt_minor_version: u8,
+    x_firmware_control: u64,
+    x_dsdt_address: u64,
+    x_pm1a_event_block: GenericAddress,
+    x_pm1b_event_block: GenericAddress,
+    x_pm1a_control_block: GenericAddress,
+    x_pm1b_control_block: GenericAddress,
+    x_pm2_control_block: GenericAddress,
+    x_pm_timer_block: GenericAddress,
+    x_gpe0_block: GenericAddress,
+    x_gpe1_block: GenericAddress,
+    sleep_control_reg: GenericAddress,
+    sleep_status_reg: GenericAddress,
+    hypervisor_vendor_id: u64,
+}
+
+impl Fadt {
+    pub fn validate(&self) -> Result<(), AcpiError> {
+        self.header.validate(b"FADT")
+    }
+
+    #[cfg(test)]
+    pub(crate) fn make_testcase(
+        oem_id: [u8; 6],
+        oem_table_id: [u8; 8],
+        oem_revision: u32,
+        creator_id: u32,
+        creator_revision: u32,
+    ) -> Fadt {
+        Fadt {
+            header: SdtHeader::make_testcase(
+                *b"FADT",
+                mem::size_of::<Fadt>() as u32,
+                6,
+                5, //checksum
+                oem_id,
+                oem_table_id,
+                oem_revision,
+                creator_id,
+                creator_revision,
+            ),
+            firmware_ctrl: 0xDEADBEEF as u32,
+            dsdt_address: 0xDEADBEEF as u32,
+
+            // used in acpi 1.0; compatibility only, should be zero
+            reserved: 0 as u8,
+
+            preferred_pm_profile: 0 as u8,
+            sci_interrupt: 0 as u16,
+            smi_cmd_port: 0 as u32,
+            acpi_enable: 0 as u8,
+            acpi_disable: 0 as u8,
+            s4bios_req: 0 as u8,
+            pstate_control: 0 as u8,
+            pm1a_event_block: 0xDEADBEEF as u32,
+            pm1b_event_block: 0xDEADBEEF as u32,
+            pm1a_control_block: 0xDEADBEEF as u32,
+            pm1b_control_block: 0xDEADBEEF as u32,
+            pm2_control_block: 0xDEADBEEF as u32,
+            pm_timer_block: 0xDEADBEEF as u32,
+            gpe0_block: 0xDEADBEEF as u32,
+            gpe1_block: 0xDEADBEEF as u32,
+            pm1_event_length: 4 as u8,
+            pm1_control_length: 2 as u8,
+            pm2_control_length: 0 as u8,
+            pm_timer_length: 0 as u8,
+            gpe0_block_length: 2 as u8,
+            gpe1_block_length: 2 as u8,
+            gpe1_base: 0 as u8,
+            c_state_control: 0 as u8,
+            worst_c2_latency: 0 as u16,
+            worst_c3_latency: 0 as u16,
+            flush_size: 0 as u16,
+            flush_stride: 0 as u16,
+            duty_offset: 0 as u8,
+            duty_width: 0 as u8,
+            day_alarm: 0 as u8,
+            month_alarm: 0 as u8,
+            century: 0 as u8,
+            iapc_boot_arch: 0 as u16,
+            reserved2: 0 as u8,
+            flags: 0 as u32,
+            reset_reg: GenericAddress::make_testcase(),
+            reset_value: 0 as u8,
+            arm_boot_arch: 0 as u16,
+            fadt_minor_version: 2 as u8,
+            x_firmware_control: 0 as u64,
+            x_dsdt_address: 0 as u64,
+            x_pm1a_event_block: GenericAddress::make_testcase(),
+            x_pm1b_event_block: GenericAddress::make_testcase(),
+            x_pm1a_control_block: GenericAddress::make_testcase(),
+            x_pm1b_control_block: GenericAddress::make_testcase(),
+            x_pm2_control_block: GenericAddress::make_testcase(),
+            x_pm_timer_block: GenericAddress::make_testcase(),
+            x_gpe0_block: GenericAddress::make_testcase(),
+            x_gpe1_block: GenericAddress::make_testcase(),
+            sleep_control_reg: GenericAddress::make_testcase(),
+            sleep_status_reg: GenericAddress::make_testcase(),
+            hypervisor_vendor_id: 0 as u64,
+        }
+    }
+}
+
+pub fn parse_fadt(mapping: &PhysicalMapping<Fadt>) -> Result<(), AcpiError> {
+    (*mapping).validate()
+}

+ 4 - 0
src/lib.rs

@@ -1,6 +1,7 @@
 #![no_std]
 
 #[cfg(test)]
+#[macro_use]
 extern crate std;
 
 #[macro_use]
@@ -8,6 +9,7 @@ extern crate log;
 
 #[cfg(test)]
 mod constructed_tables_test;
+mod fadt;
 mod rsdp;
 mod sdt;
 
@@ -27,6 +29,8 @@ pub enum AcpiError {
     SdtInvalidOemId,
     SdtInvalidTableId,
     SdtInvalidChecksum,
+
+    FadtIncorrectSignature,
 }
 
 /// Describes a physical mapping created by `AcpiHandler::map_physical_region` and unmapped by

+ 9 - 3
src/sdt.rs

@@ -1,4 +1,5 @@
 use core::str;
+use fadt::{parse_fadt, Fadt};
 use {AcpiError, AcpiHandler};
 
 /// All SDTs share the same header, and are `length` bytes long. The signature tells us which SDT
@@ -22,9 +23,9 @@ impl SdtHeader {
     ///     b) The checksum of the SDT
     ///
     /// This assumes that the whole SDT is mapped.
-    fn validate(&self, signature: &[u8; 4]) -> Result<(), AcpiError> {
+    pub fn validate(&self, signature: &[u8; 4]) -> Result<(), AcpiError> {
         // Check the signature
-        if &self.signature == signature {
+        if &self.signature != signature {
             return Err(AcpiError::SdtInvalidSignature);
         }
 
@@ -45,7 +46,7 @@ impl SdtHeader {
         }
 
         // Check that the lowest byte is 0
-        if sum & 0b1111_1111 != 0 {
+        if sum % 0b1111_1111 != 0 {
             return Err(AcpiError::SdtInvalidChecksum);
         }
 
@@ -117,6 +118,11 @@ where
          * and length, and then the dispatched to the correct function to actually parse the table.
          */
         match signature {
+            "FADT" => {
+                let fadt_mapping = handler.map_physical_region::<Fadt>(physical_address);
+                parse_fadt(&fadt_mapping)?;
+                handler.unmap_physical_region(fadt_mapping);
+            }
             _ => {
                 /*
                  * We don't recognise this signature. Early on, this probably just means we don't