Sfoglia il codice sorgente

Add ExtendedField abstraction

restioson 6 anni fa
parent
commit
4241314c57
4 ha cambiato i file con 62 aggiunte e 22 eliminazioni
  1. 1 0
      acpi/Cargo.toml
  2. 26 21
      acpi/src/fadt.rs
  3. 1 0
      acpi/src/lib.rs
  4. 34 1
      acpi/src/sdt.rs

+ 1 - 0
acpi/Cargo.toml

@@ -12,3 +12,4 @@ edition = "2018"
 [dependencies]
 log = "0.4"
 bit_field = "0.9"
+typenum = "1"

+ 26 - 21
acpi/src/fadt.rs

@@ -1,5 +1,7 @@
 use crate::{sdt::SdtHeader, Acpi, AcpiError, AcpiHandler, GenericAddress, PhysicalMapping};
 
+type ExtendedField<T> = crate::sdt::ExtendedField<T, typenum::U2>;
+
 /// Represents the Fixed ACPI Description Table (FADT). This table contains various fixed hardware
 /// details, such as the addresses of the hardware register blocks. It also contains a pointer to
 /// the Differentiated Definition Block (DSDT).
@@ -15,7 +17,7 @@ pub struct Fadt {
     dsdt_address: u32,
 
     // used in acpi 1.0; compatibility only, should be zero
-    reserved: u8,
+    _reserved: u8,
 
     preferred_pm_profile: u8,
     sci_interrupt: u16,
@@ -50,25 +52,25 @@ pub struct Fadt {
     month_alarm: u8,
     century: u8,
     iapc_boot_arch: u16,
-    reserved2: u8, // must be 0
+    _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,
+    x_firmware_ctrl: ExtendedField<u64>,
+    x_dsdt_address: ExtendedField<u64>,
+    x_pm1a_event_block: ExtendedField<GenericAddress>,
+    x_pm1b_event_block: ExtendedField<GenericAddress>,
+    x_pm1a_control_block: ExtendedField<GenericAddress>,
+    x_pm1b_control_block: ExtendedField<GenericAddress>,
+    x_pm2_control_block: ExtendedField<GenericAddress>,
+    x_pm_timer_block: ExtendedField<GenericAddress>,
+    x_gpe0_block: ExtendedField<GenericAddress>,
+    x_gpe1_block: ExtendedField<GenericAddress>,
+    sleep_control_reg: ExtendedField<GenericAddress>,
+    sleep_status_reg: ExtendedField<GenericAddress>,
+    hypervisor_vendor_id: ExtendedField<u64>,
 }
 
 pub(crate) fn parse_fadt<H>(
@@ -82,12 +84,15 @@ where
     let fadt = &*mapping;
     fadt.header.validate(b"FACP")?;
 
-    // TODO more generic typesafe way of accessing the x_ fields
-    acpi.dsdt_address = Some(if fadt.header.revision() > 1 && fadt.x_dsdt_address != 0 {
-        fadt.x_dsdt_address as usize
-    } else {
-        fadt.dsdt_address as usize
-    });
+    unsafe {
+        acpi.dsdt_address = fadt
+            .x_dsdt_address
+            .get(fadt.header.revision())
+            .filter(|p| *p != 0)
+            .or(Some(fadt.dsdt_address as u64))
+            .filter(|p| *p != 0)
+            .map(|p| p as usize);
+    }
 
     Ok(())
 }

+ 1 - 0
acpi/src/lib.rs

@@ -34,6 +34,7 @@ extern crate std;
 extern crate log;
 extern crate alloc;
 extern crate bit_field;
+extern crate typenum;
 
 mod fadt;
 pub mod handler;

+ 34 - 1
acpi/src/sdt.rs

@@ -1,5 +1,38 @@
 use crate::{fadt::Fadt, hpet::HpetTable, madt::Madt, Acpi, AcpiError, AcpiHandler};
-use core::{mem, str};
+use core::{marker::PhantomData, mem, str};
+use typenum::Unsigned;
+
+/// A union that represents a field that is not necessarily present and is only present in a later
+/// ACPI version (represented by the compile time number and type parameter `R`)
+#[allow(dead_code)]
+#[derive(Copy, Clone)]
+#[repr(C, packed)]
+pub union ExtendedField<T: Copy, R: Unsigned> {
+    field: T,
+    nothing: (),
+    _phantom: PhantomData<R>,
+}
+
+impl<T: Copy, R: Unsigned> ExtendedField<T, R> {
+    fn new(field: T) -> Self {
+        ExtendedField { field }
+    }
+
+    /// Checks that the given revision is greater than `R` (typenum revision number) and then
+    /// returns the field, otherwise returning `None`.
+    ///
+    /// # Unsafety
+    ///
+    /// This is unsafe as the given `revision` could be incorrect or fabricated. However, it should
+    /// be safe if it represents the revision of the table this field is present in.
+    pub unsafe fn get(&self, revision: u8) -> Option<T> {
+        if revision >= R::to_u8() {
+            Some(self.field)
+        } else {
+            None
+        }
+    }
+}
 
 /// All SDTs share the same header, and are `length` bytes long. The signature tells us which SDT
 /// this is.