浏览代码

Merge pull request #86 from IsaacWoods/public_tables

Make table types public
Isaac Woods 4 年之前
父节点
当前提交
c97b46af27
共有 7 个文件被更改,包括 280 次插入68 次删除
  1. 220 39
      acpi/src/fadt.rs
  2. 29 6
      acpi/src/hpet.rs
  3. 5 4
      acpi/src/lib.rs
  4. 2 2
      acpi/src/madt.rs
  5. 4 3
      acpi/src/mcfg.rs
  6. 17 9
      acpi/src/platform/address.rs
  7. 3 5
      acpi/src/platform/mod.rs

+ 220 - 39
acpi/src/fadt.rs

@@ -1,9 +1,10 @@
 use crate::{
-    platform::address::{GenericAddress, RawGenericAddress},
+    platform::address::{AccessSize, AddressSpace, GenericAddress, RawGenericAddress},
     sdt::{ExtendedField, SdtHeader},
     AcpiError,
     AcpiTable,
 };
+use bit_field::BitField;
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
 pub enum PowerProfile {
@@ -37,12 +38,31 @@ pub struct Fadt {
     _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,
+    /// On systems with an i8259 PIC, this is the vector the System Control Interrupt (SCI) is wired to. On other systems, this is
+    /// the Global System Interrupt (GSI) number of the SCI.
+    ///
+    /// The SCI should be treated as a sharable, level, active-low interrupt.
+    pub sci_interrupt: u16,
+    /// The system port address of the SMI Command Port. This port should only be accessed from the boot processor.
+    /// A value of `0` indicates that System Management Mode.
+    ///
+    ///    - Writing the value in `acpi_enable` to this port will transfer control of the ACPI hardware registers
+    ///      from the firmware to the OS. You must synchronously wait for the transfer to complete, indicated by the
+    ///      setting of `SCI_EN`.
+    ///    - Writing the value in `acpi_disable` will relinquish ownership of the hardware registers to the
+    ///      firmware. This should only be done if you've previously acquired ownership. Before writing this value,
+    ///      the OS should mask all SCI interrupts and clear the `SCI_EN` bit.
+    ///    - Writing the value in `s4bios_req` requests that the firmware enter the S4 state through the S4BIOS
+    ///      feature. This is only supported if the `S4BIOS_F` flag in the FACS is set.
+    ///    - Writing the value in `pstate_control` yields control of the processor performance state to the OS.
+    ///      If this field is `0`, this feature is not supported.
+    ///    - Writing the value in `c_state_control` tells the firmware that the OS supports `_CST` AML objects and
+    ///      notifications of C State changes.
+    pub smi_cmd_port: u32,
+    pub acpi_enable: u8,
+    pub acpi_disable: u8,
+    pub s4bios_req: u8,
+    pub pstate_control: u8,
     pm1a_event_block: u32,
     pm1b_event_block: u32,
     pm1a_control_block: u32,
@@ -57,22 +77,28 @@ pub struct Fadt {
     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,
+    pub gpe1_base: u8,
+    pub c_state_control: u8,
+    /// The worst-case latency to enter and exit the C2 state, in microseconds. A value `>100` indicates that the
+    /// system does not support the C2 state.
+    pub worst_c2_latency: u16,
+    /// The worst-case latency to enter and exit the C3 state, in microseconds. A value `>1000` indicates that the
+    /// system does not support the C3 state.
+    pub worst_c3_latency: u16,
+    pub flush_size: u16,
+    pub flush_stride: u16,
+    pub duty_offset: u8,
+    pub duty_width: u8,
+    pub day_alarm: u8,
+    pub month_alarm: u8,
+    pub century: u8,
+    // TODO: expose through a type
     iapc_boot_arch: u16,
     _reserved2: u8, // must be 0
-    pub flags: u32,
+    pub flags: Flags,
     reset_reg: RawGenericAddress,
-    reset_value: u8,
+    pub reset_value: u8,
+    // TODO: expose through a type
     arm_boot_arch: u16,
     fadt_minor_version: u8,
     x_firmware_ctrl: ExtendedField<u64, 2>,
@@ -101,13 +127,25 @@ impl Fadt {
         self.header.validate(crate::sdt::Signature::FADT)
     }
 
+    pub fn facs_address(&self) -> Result<usize, AcpiError> {
+        unsafe {
+            self.x_firmware_ctrl
+                .access(self.header.revision)
+                .filter(|&p| p != 0)
+                .or(Some(self.firmware_ctrl as u64))
+                .filter(|&p| p != 0)
+                .map(|p| p as usize)
+                .ok_or(AcpiError::InvalidFacsAddress)
+        }
+    }
+
     pub fn dsdt_address(&self) -> Result<usize, AcpiError> {
         unsafe {
             self.x_dsdt_address
                 .access(self.header.revision)
                 .filter(|&p| p != 0)
                 .or(Some(self.dsdt_address as u64))
-                .filter(|p| *p != 0)
+                .filter(|&p| p != 0)
                 .map(|p| p as usize)
                 .ok_or(AcpiError::InvalidDsdtAddress)
         }
@@ -128,26 +166,169 @@ impl Fadt {
         }
     }
 
-    pub fn pm_timer_block(&self) -> Result<Option<GenericAddress>, AcpiError> {
-        let raw = unsafe {
-            self.x_pm_timer_block.access(self.header().revision).or_else(|| {
-                if self.pm_timer_block != 0 {
-                    Some(RawGenericAddress {
-                        address_space: 1,
-                        bit_width: 0,
-                        bit_offset: 0,
-                        access_size: self.pm_timer_length,
-                        address: self.pm_timer_block.into(),
-                    })
-                } else {
-                    None
-                }
+    pub fn pm1a_event_block(&self) -> Result<GenericAddress, AcpiError> {
+        if let Some(raw) = unsafe { self.x_pm1a_event_block.access(self.header().revision) } {
+            Ok(GenericAddress::from_raw(raw)?)
+        } else {
+            Ok(GenericAddress {
+                address_space: AddressSpace::SystemIo,
+                bit_width: self.pm1_event_length * 8,
+                bit_offset: 0,
+                access_size: AccessSize::Undefined,
+                address: self.pm1a_event_block.into(),
+            })
+        }
+    }
+
+    pub fn pm1b_event_block(&self) -> Result<Option<GenericAddress>, AcpiError> {
+        if let Some(raw) = unsafe { self.x_pm1b_event_block.access(self.header().revision) } {
+            Ok(Some(GenericAddress::from_raw(raw)?))
+        } else {
+            if self.pm1b_event_block != 0 {
+                Ok(Some(GenericAddress {
+                    address_space: AddressSpace::SystemIo,
+                    bit_width: self.pm1_event_length * 8,
+                    bit_offset: 0,
+                    access_size: AccessSize::Undefined,
+                    address: self.pm1b_event_block.into(),
+                }))
+            } else {
+                Ok(None)
+            }
+        }
+    }
+
+    pub fn pm1a_control_block(&self) -> Result<GenericAddress, AcpiError> {
+        if let Some(raw) = unsafe { self.x_pm1a_control_block.access(self.header().revision) } {
+            Ok(GenericAddress::from_raw(raw)?)
+        } else {
+            Ok(GenericAddress {
+                address_space: AddressSpace::SystemIo,
+                bit_width: self.pm1_control_length * 8,
+                bit_offset: 0,
+                access_size: AccessSize::Undefined,
+                address: self.pm1a_control_block.into(),
             })
-        };
+        }
+    }
+
+    pub fn pm1b_control_block(&self) -> Result<Option<GenericAddress>, AcpiError> {
+        if let Some(raw) = unsafe { self.x_pm1b_control_block.access(self.header().revision) } {
+            Ok(Some(GenericAddress::from_raw(raw)?))
+        } else {
+            if self.pm1b_control_block != 0 {
+                Ok(Some(GenericAddress {
+                    address_space: AddressSpace::SystemIo,
+                    bit_width: self.pm1_control_length * 8,
+                    bit_offset: 0,
+                    access_size: AccessSize::Undefined,
+                    address: self.pm1b_control_block.into(),
+                }))
+            } else {
+                Ok(None)
+            }
+        }
+    }
 
-        match raw {
-            Some(raw) => Ok(Some(GenericAddress::from_raw(raw)?)),
-            None => Ok(None),
+    pub fn pm2_control_block(&self) -> Result<Option<GenericAddress>, AcpiError> {
+        if let Some(raw) = unsafe { self.x_pm2_control_block.access(self.header().revision) } {
+            Ok(Some(GenericAddress::from_raw(raw)?))
+        } else {
+            if self.pm2_control_block != 0 {
+                Ok(Some(GenericAddress {
+                    address_space: AddressSpace::SystemIo,
+                    bit_width: self.pm2_control_length * 8,
+                    bit_offset: 0,
+                    access_size: AccessSize::Undefined,
+                    address: self.pm2_control_block.into(),
+                }))
+            } else {
+                Ok(None)
+            }
         }
     }
+
+    pub fn pm_timer_block(&self) -> Result<Option<GenericAddress>, AcpiError> {
+        if let Some(raw) = unsafe { self.x_pm_timer_block.access(self.header().revision) } {
+            Ok(Some(GenericAddress::from_raw(raw)?))
+        } else {
+            if self.pm_timer_block != 0 {
+                Ok(Some(GenericAddress {
+                    address_space: AddressSpace::SystemIo,
+                    bit_width: self.pm_timer_length * 8,
+                    bit_offset: 0,
+                    access_size: AccessSize::Undefined,
+                    address: self.pm_timer_block.into(),
+                }))
+            } else {
+                Ok(None)
+            }
+        }
+    }
+
+    pub fn gpe0_block(&self) -> Result<Option<GenericAddress>, AcpiError> {
+        if let Some(raw) = unsafe { self.x_gpe0_block.access(self.header().revision) } {
+            Ok(Some(GenericAddress::from_raw(raw)?))
+        } else {
+            if self.gpe0_block != 0 {
+                Ok(Some(GenericAddress {
+                    address_space: AddressSpace::SystemIo,
+                    bit_width: self.gpe0_block_length * 8,
+                    bit_offset: 0,
+                    access_size: AccessSize::Undefined,
+                    address: self.gpe0_block.into(),
+                }))
+            } else {
+                Ok(None)
+            }
+        }
+    }
+
+    pub fn gpe1_block(&self) -> Result<Option<GenericAddress>, AcpiError> {
+        if let Some(raw) = unsafe { self.x_gpe1_block.access(self.header().revision) } {
+            Ok(Some(GenericAddress::from_raw(raw)?))
+        } else {
+            if self.gpe1_block != 0 {
+                Ok(Some(GenericAddress {
+                    address_space: AddressSpace::SystemIo,
+                    bit_width: self.gpe1_block_length * 8,
+                    bit_offset: 0,
+                    access_size: AccessSize::Undefined,
+                    address: self.gpe1_block.into(),
+                }))
+            } else {
+                Ok(None)
+            }
+        }
+    }
+
+    pub fn reset_register(&self) -> Result<GenericAddress, AcpiError> {
+        GenericAddress::from_raw(self.reset_reg)
+    }
+
+    pub fn sleep_control_register(&self) -> Result<Option<GenericAddress>, AcpiError> {
+        if let Some(raw) = unsafe { self.sleep_control_reg.access(self.header().revision) } {
+            Ok(Some(GenericAddress::from_raw(raw)?))
+        } else {
+            Ok(None)
+        }
+    }
+
+    pub fn sleep_status_register(&self) -> Result<Option<GenericAddress>, AcpiError> {
+        if let Some(raw) = unsafe { self.sleep_status_reg.access(self.header().revision) } {
+            Ok(Some(GenericAddress::from_raw(raw)?))
+        } else {
+            Ok(None)
+        }
+    }
+}
+
+#[derive(Clone, Copy)]
+// TODO: methods for other flags
+pub struct Flags(u32);
+
+impl Flags {
+    pub fn pm_timer_is_32_bit(&self) -> bool {
+        self.0.get_bit(8)
+    }
 }

+ 29 - 6
acpi/src/hpet.rs

@@ -4,16 +4,17 @@ use bit_field::BitField;
 #[derive(Debug)]
 pub enum PageProtection {
     None,
-    /// Access to the adjacent 3KB to the base address will not generate a fault.
+    /// Access to the rest of the 4KiB, relative to the base address, will not generate a fault.
     Protected4K,
-    /// Access to the adjacent 64KB to the base address will not generate a fault.
+    /// Access to the rest of the 64KiB, relative to the base address, will not generate a fault.
     Protected64K,
     Other,
 }
 
-/// Information about the High Precision Event Timer
+/// Information about the High Precision Event Timer (HPET)
 #[derive(Debug)]
 pub struct HpetInfo {
+    // TODO(3.0.0): unpack these fields directly, and get rid of methods
     pub event_timer_block_id: u32,
     pub base_address: usize,
     pub hpet_number: u8,
@@ -41,7 +42,7 @@ impl HpetInfo {
             base_address: hpet.base_address.address as usize,
             hpet_number: hpet.hpet_number,
             clock_tick_unit: hpet.clock_tick_unit,
-            page_protection: match hpet.page_protection_oem.get_bits(0..5) {
+            page_protection: match hpet.page_protection_and_oem.get_bits(0..4) {
                 0 => PageProtection::None,
                 1 => PageProtection::Protected4K,
                 2 => PageProtection::Protected64K,
@@ -50,16 +51,38 @@ impl HpetInfo {
             },
         })
     }
+
+    pub fn hardware_rev(&self) -> u8 {
+        self.event_timer_block_id.get_bits(0..8) as u8
+    }
+
+    pub fn num_comparators(&self) -> u8 {
+        self.event_timer_block_id.get_bits(8..13) as u8
+    }
+
+    pub fn main_counter_is_64bits(&self) -> bool {
+        self.event_timer_block_id.get_bit(13)
+    }
+
+    pub fn legacy_irq_capable(&self) -> bool {
+        self.event_timer_block_id.get_bit(15)
+    }
+
+    pub fn pci_vendor_id(&self) -> u16 {
+        self.event_timer_block_id.get_bits(16..32) as u16
+    }
 }
 
 #[repr(C, packed)]
-pub(crate) struct HpetTable {
+pub struct HpetTable {
+    /// The contents of the HPET's 'General Capabilities and ID register'
     header: SdtHeader,
     event_timer_block_id: u32,
     base_address: RawGenericAddress,
     hpet_number: u8,
     clock_tick_unit: u16,
-    page_protection_oem: u8,
+    /// Bits `0..4` specify the page protection guarantee. Bits `4..8` are reserved for OEM attributes.
+    page_protection_and_oem: u8,
 }
 
 impl AcpiTable for HpetTable {

+ 5 - 4
acpi/src/lib.rs

@@ -46,10 +46,10 @@ extern crate alloc;
 #[cfg(test)]
 extern crate std;
 
-mod fadt;
-mod hpet;
-mod madt;
-mod mcfg;
+pub mod fadt;
+pub mod hpet;
+pub mod madt;
+pub mod mcfg;
 pub mod platform;
 pub mod sdt;
 
@@ -81,6 +81,7 @@ pub enum AcpiError {
     SdtInvalidChecksum(Signature),
 
     TableMissing(Signature),
+    InvalidFacsAddress,
     InvalidDsdtAddress,
     InvalidMadt(MadtError),
     InvalidGenericAddress,

+ 2 - 2
acpi/src/madt.rs

@@ -37,8 +37,8 @@ pub enum MadtError {
 /// In modern versions of ACPI, the MADT can detail one of four interrupt models:
 ///     * The ancient dual-i8259 legacy PIC model
 ///     * The Advanced Programmable Interrupt Controller (APIC) model
-///     * The Streamlined Advanced Programmable Interrupt Controller (SAPIC) model
-///     * The Generic Interrupt Controller (GIC) model (ARM systems only)
+///     * The Streamlined Advanced Programmable Interrupt Controller (SAPIC) model (for Itanium systems)
+///     * The Generic Interrupt Controller (GIC) model (for ARM systems)
 #[repr(C, packed)]
 pub struct Madt {
     header: SdtHeader,

+ 4 - 3
acpi/src/mcfg.rs

@@ -46,7 +46,7 @@ impl PciConfigRegions {
 }
 
 #[repr(C, packed)]
-pub(crate) struct Mcfg {
+pub struct Mcfg {
     header: SdtHeader,
     _reserved: u64,
     // Followed by `n` entries with format `McfgEntry`
@@ -62,7 +62,8 @@ impl Mcfg {
     fn entries(&self) -> &[McfgEntry] {
         let length = self.header.length as usize - mem::size_of::<Mcfg>();
 
-        // intentionally round down in case length isn't an exact multiple of McfgEntry size
+        // Intentionally round down in case length isn't an exact multiple of McfgEntry size
+        // (see rust-osdev/acpi#58)
         let num_entries = length / mem::size_of::<McfgEntry>();
 
         unsafe {
@@ -75,7 +76,7 @@ impl Mcfg {
 
 #[derive(Clone, Copy, Debug)]
 #[repr(C, packed)]
-struct McfgEntry {
+pub struct McfgEntry {
     base_address: u64,
     pci_segment_group: u16,
     bus_number_start: u8,

+ 17 - 9
acpi/src/platform/address.rs

@@ -2,6 +2,7 @@
 //! in a wide range of address spaces.
 
 use crate::AcpiError;
+use core::convert::TryFrom;
 
 /// This is the raw form of a Generic Address Structure, and follows the layout found in the ACPI tables. It does
 /// not form part of the public API, and should be turned into a `GenericAddress` for most use-cases.
@@ -49,6 +50,21 @@ pub enum AccessSize {
     QWordAccess,
 }
 
+impl TryFrom<u8> for AccessSize {
+    type Error = AcpiError;
+
+    fn try_from(size: u8) -> Result<Self, Self::Error> {
+        match size {
+            0 => Ok(AccessSize::Undefined),
+            1 => Ok(AccessSize::ByteAccess),
+            2 => Ok(AccessSize::WordAccess),
+            3 => Ok(AccessSize::DWordAccess),
+            4 => Ok(AccessSize::QWordAccess),
+            _ => Err(AcpiError::InvalidGenericAddress),
+        }
+    }
+}
+
 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
 pub struct GenericAddress {
     pub address_space: AddressSpace,
@@ -77,20 +93,12 @@ impl GenericAddress {
             0x80..=0xbf => return Err(AcpiError::InvalidGenericAddress),
             0xc0..=0xff => AddressSpace::OemDefined(raw.address_space),
         };
-        let access_size = match raw.access_size {
-            0 => AccessSize::Undefined,
-            1 => AccessSize::ByteAccess,
-            2 => AccessSize::WordAccess,
-            3 => AccessSize::DWordAccess,
-            4 => AccessSize::QWordAccess,
-            _ => return Err(AcpiError::InvalidGenericAddress),
-        };
 
         Ok(GenericAddress {
             address_space,
             bit_width: raw.bit_width,
             bit_offset: raw.bit_offset,
-            access_size,
+            access_size: AccessSize::try_from(raw.access_size)?,
             address: raw.address,
         })
     }

+ 3 - 5
acpi/src/platform/mod.rs

@@ -2,7 +2,6 @@ pub mod address;
 pub mod interrupt;
 
 use address::GenericAddress;
-use bit_field::BitField;
 pub use interrupt::{
     Apic,
     InterruptModel,
@@ -57,18 +56,17 @@ pub struct ProcessorInfo {
 pub struct PmTimer {
     /// A generic address to the register block of ACPI PM Timer.
     pub base: GenericAddress,
-    /// This field is true if the hardware supports 32-bit timer, and false if the hardware
-    /// supports 24-bit timer.
+    /// This field is `true` if the hardware supports 32-bit timer, and `false` if the hardware supports 24-bit timer.
     pub supports_32bit: bool,
 }
+
 impl PmTimer {
-    /// Creates a new instance of `PmTimer`.
     pub fn new(fadt: &Fadt) -> Result<Option<PmTimer>, AcpiError> {
         let base = fadt.pm_timer_block()?;
         let flags = fadt.flags;
 
         match base {
-            Some(base) => Ok(Some(PmTimer { base, supports_32bit: flags.get_bit(8) })),
+            Some(base) => Ok(Some(PmTimer { base, supports_32bit: fadt.flags.pm_timer_is_32_bit() })),
             None => Ok(None),
         }
     }