فهرست منبع

Merge #70

70: Prepare for stabilisation of the `acpi` crate r=IsaacWoods a=IsaacWoods

The `acpi` crate is nearing the point where I'd like to get it stabilised and publish a `v1.0.0` version. This PR will make a few breaking changes for either correctness or future-proofing for the stuff that isn't yet implemented (e.g. the x2APIC) - I'd be interested in getting people's feedback on both the idea of stabilisation, and whether they think any other changes should be made to the crate before stabilisation.

Note that we're not stabilising the `aml` crate at this time.

cc @rust-osdev/acpi @64 @phil-opp 

Co-authored-by: Isaac Woods <isaacwoods.home@gmail.com>
bors[bot] 5 سال پیش
والد
کامیت
5a016adee4
9فایلهای تغییر یافته به همراه81 افزوده شده و 35 حذف شده
  1. 1 1
      acpi/Cargo.toml
  2. 27 0
      acpi/src/fadt.rs
  3. 1 1
      acpi/src/handler.rs
  4. 4 1
      acpi/src/interrupt.rs
  5. 9 6
      acpi/src/lib.rs
  6. 23 15
      acpi/src/madt.rs
  7. 5 5
      acpi/src/mcfg.rs
  8. 2 1
      acpi/src/rsdp_search.rs
  9. 9 5
      acpi/src/sdt.rs

+ 1 - 1
acpi/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = "acpi"
-version = "0.8.0"
+version = "1.0.0"
 authors = ["Isaac Woods"]
 repository = "https://github.com/rust-osdev/acpi"
 description = "Library for parsing ACPI tables"

+ 27 - 0
acpi/src/fadt.rs

@@ -8,6 +8,20 @@ use crate::{
     PhysicalMapping,
 };
 
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub enum PowerProfile {
+    Unspecified,
+    Desktop,
+    Mobile,
+    Workstation,
+    EnterpriseServer,
+    SohoServer,
+    AppliancePc,
+    PerformanceServer,
+    Tablet,
+    Reserved(u8),
+}
+
 /// 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).
@@ -90,6 +104,19 @@ where
     let fadt = &*mapping;
     fadt.header.validate(crate::sdt::Signature::FADT)?;
 
+    acpi.power_profile = match fadt.preferred_pm_profile {
+        0 => PowerProfile::Unspecified,
+        1 => PowerProfile::Desktop,
+        2 => PowerProfile::Mobile,
+        3 => PowerProfile::Workstation,
+        4 => PowerProfile::EnterpriseServer,
+        5 => PowerProfile::SohoServer,
+        6 => PowerProfile::AppliancePc,
+        7 => PowerProfile::PerformanceServer,
+        8 => PowerProfile::Tablet,
+        other => PowerProfile::Reserved(other),
+    };
+
     let dsdt_address = unsafe {
         fadt.x_dsdt_address
             .access(fadt.header.revision)

+ 1 - 1
acpi/src/handler.rs

@@ -27,7 +27,7 @@ pub trait AcpiHandler {
     /// 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 accessible from `acpi`.
-    fn map_physical_region<T>(&mut self, physical_address: usize, size: usize) -> PhysicalMapping<T>;
+    unsafe 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.

+ 4 - 1
acpi/src/interrupt.rs

@@ -22,7 +22,9 @@ pub enum LocalInterruptLine {
 #[derive(Debug)]
 pub enum NmiProcessor {
     All,
-    ProcessorUid(u8),
+    /// Refers to a processor with the given UID. This is stored as a `u32`, but should be casted to `u8` when the
+    /// DSDT uses the deprecated `DefProcessor` operator to define processor UIDs.
+    ProcessorUid(u32),
 }
 
 #[derive(Debug)]
@@ -75,6 +77,7 @@ pub struct Apic {
 }
 
 #[derive(Debug)]
+#[non_exhaustive]
 pub enum InterruptModel {
     /// This model is only chosen when a newer one can not be found and the system supports the
     /// legacy dual-8259 PIC.

+ 9 - 6
acpi/src/lib.rs

@@ -40,6 +40,7 @@ mod rsdp_search;
 mod sdt;
 
 pub use crate::{
+    fadt::PowerProfile,
     handler::{AcpiHandler, PhysicalMapping},
     hpet::HpetInfo,
     interrupt::InterruptModel,
@@ -142,6 +143,7 @@ pub struct Acpi {
     /// just error in cases that the tables detail more than one.
     pub interrupt_model: Option<InterruptModel>,
     pub hpet: Option<HpetInfo>,
+    pub power_profile: PowerProfile,
 
     /// Info about the DSDT, if we find it.
     pub dsdt: Option<AmlTable>,
@@ -156,11 +158,11 @@ pub struct Acpi {
 /// 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<Acpi, AcpiError>
+pub unsafe fn parse_rsdp<H>(handler: &mut H, rsdp_address: usize) -> Result<Acpi, AcpiError>
 where
     H: AcpiHandler,
 {
-    let rsdp_mapping = handler.map_physical_region::<Rsdp>(rsdp_address, mem::size_of::<Rsdp>());
+    let rsdp_mapping = unsafe { handler.map_physical_region::<Rsdp>(rsdp_address, mem::size_of::<Rsdp>()) };
     (*rsdp_mapping).validate()?;
 
     parse_validated_rsdp(handler, rsdp_mapping)
@@ -178,7 +180,7 @@ where
          */
         let rsdt_address = (*rsdp_mapping).rsdt_address();
         handler.unmap_physical_region(rsdp_mapping);
-        parse_rsdt(handler, revision, rsdt_address as usize)
+        unsafe { 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
@@ -186,7 +188,7 @@ where
          */
         let xsdt_address = (*rsdp_mapping).xsdt_address();
         handler.unmap_physical_region(rsdp_mapping);
-        parse_rsdt(handler, revision, xsdt_address as usize)
+        unsafe { parse_rsdt(handler, revision, xsdt_address as usize) }
     }
 }
 
@@ -196,7 +198,7 @@ where
 ///
 /// 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<Acpi, AcpiError>
+pub unsafe fn parse_rsdt<H>(handler: &mut H, revision: u8, physical_address: usize) -> Result<Acpi, AcpiError>
 where
     H: AcpiHandler,
 {
@@ -206,13 +208,14 @@ where
         application_processors: Vec::new(),
         interrupt_model: None,
         hpet: None,
+        power_profile: PowerProfile::Unspecified,
         dsdt: None,
         ssdts: Vec::new(),
         pci_config_regions: None,
     };
 
     let header = sdt::peek_at_sdt_header(handler, physical_address);
-    let mapping = handler.map_physical_region::<SdtHeader>(physical_address, header.length as usize);
+    let mapping = unsafe { handler.map_physical_region::<SdtHeader>(physical_address, header.length as usize) };
 
     if revision == 0 {
         /*

+ 23 - 15
acpi/src/madt.rs

@@ -1,5 +1,15 @@
 use crate::{
-    interrupt::{Apic, InterruptModel, InterruptSourceOverride, IoApic, NmiLine, NmiProcessor, NmiSource, Polarity, TriggerMode},
+    interrupt::{
+        Apic,
+        InterruptModel,
+        InterruptSourceOverride,
+        IoApic,
+        NmiLine,
+        NmiProcessor,
+        NmiSource,
+        Polarity,
+        TriggerMode,
+    },
     sdt::SdtHeader,
     Acpi,
     AcpiError,
@@ -476,20 +486,18 @@ fn parse_apic_model(acpi: &mut Acpi, mapping: &PhysicalMapping<Madt>) -> Result<
                 });
             }
 
-            MadtEntry::LocalApicNmi(ref entry) => {
-                local_apic_nmi_lines.push(NmiLine {
-                    processor: if entry.processor_id == 0xff {
-                        NmiProcessor::All
-                    } else {
-                        NmiProcessor::ProcessorUid(entry.processor_id)
-                    },
-                    line: match entry.nmi_line {
-                        0 => LocalInterruptLine::Lint0,
-                        1 => LocalInterruptLine::Lint1,
-                        _ => return Err(AcpiError::InvalidMadt(MadtError::InvalidLocalNmiLine)),
-                    },
-                })
-            }
+            MadtEntry::LocalApicNmi(ref entry) => local_apic_nmi_lines.push(NmiLine {
+                processor: if entry.processor_id == 0xff {
+                    NmiProcessor::All
+                } else {
+                    NmiProcessor::ProcessorUid(entry.processor_id as u32)
+                },
+                line: match entry.nmi_line {
+                    0 => LocalInterruptLine::Lint0,
+                    1 => LocalInterruptLine::Lint1,
+                    _ => return Err(AcpiError::InvalidMadt(MadtError::InvalidLocalNmiLine)),
+                },
+            }),
 
             MadtEntry::LocalApicAddressOverride(ref entry) => {
                 local_apic_address = entry.local_apic_address;

+ 5 - 5
acpi/src/mcfg.rs

@@ -2,18 +2,18 @@ use crate::{handler::PhysicalMapping, sdt::SdtHeader, Acpi, AcpiError};
 use alloc::vec::Vec;
 use core::{mem, slice};
 
-/// Describes a set of regions of physical memory used to access the PCI-E configuration space. A
-/// region  is created for each entry in the MCFG. Given the segment group, bus, device number, and
-/// function of a PCI-E device, the `physical_address` method on this will give you the physical
+/// Describes a set of regions of physical memory used to access the PCIe configuration space. A
+/// region is created for each entry in the MCFG. Given the segment group, bus, device number, and
+/// function of a PCIe device, the `physical_address` method on this will give you the physical
 /// address of the start of that device function's configuration space (each function has 4096
-/// bytes of configuration space in PCI-E).
+/// bytes of configuration space in PCIe).
 #[derive(Debug)]
 pub struct PciConfigRegions {
     regions: Vec<McfgEntry>,
 }
 
 impl PciConfigRegions {
-    /// Get the physical address of the start of the configuration space for a given PCI-E device
+    /// Get the physical address of the start of the configuration space for a given PCIe device
     /// function. Returns `None` if there isn't an entry in the MCFG that manages that device.
     pub fn physical_address(&self, segment_group_no: u16, bus: u8, device: u8, function: u8) -> Option<u64> {
         // First, find the memory region that handles this segment and bus. This method is fine

+ 2 - 1
acpi/src/rsdp_search.rs

@@ -25,7 +25,8 @@ where
 {
     // Read base segment from BIOS area. This is not always given by the bios, so it needs to be
     // checked. We left shift 4 because it is a segment ptr.
-    let ebda_start_mapping = handler.map_physical_region::<u16>(EBDA_START_SEGMENT_PTR, mem::size_of::<u16>());
+    let ebda_start_mapping =
+        unsafe { handler.map_physical_region::<u16>(EBDA_START_SEGMENT_PTR, mem::size_of::<u16>()) };
     let ebda_start = (*ebda_start_mapping as usize) << 4;
     handler.unmap_physical_region(ebda_start_mapping);
 

+ 9 - 5
acpi/src/sdt.rs

@@ -154,7 +154,8 @@ pub(crate) fn peek_at_sdt_header<H>(handler: &mut H, physical_address: usize) ->
 where
     H: AcpiHandler,
 {
-    let mapping = handler.map_physical_region::<SdtHeader>(physical_address, mem::size_of::<SdtHeader>());
+    let mapping =
+        unsafe { handler.map_physical_region::<SdtHeader>(physical_address, mem::size_of::<SdtHeader>()) };
     let header = (*mapping).clone();
     handler.unmap_physical_region(mapping);
 
@@ -176,26 +177,29 @@ where
      */
     match header.signature {
         Signature::FADT => {
-            let fadt_mapping = handler.map_physical_region::<Fadt>(physical_address, mem::size_of::<Fadt>());
+            let fadt_mapping =
+                unsafe { handler.map_physical_region::<Fadt>(physical_address, mem::size_of::<Fadt>()) };
             crate::fadt::parse_fadt(acpi, handler, &fadt_mapping)?;
             handler.unmap_physical_region(fadt_mapping);
         }
 
         Signature::HPET => {
             let hpet_mapping =
-                handler.map_physical_region::<HpetTable>(physical_address, mem::size_of::<HpetTable>());
+                unsafe { handler.map_physical_region::<HpetTable>(physical_address, mem::size_of::<HpetTable>()) };
             crate::hpet::parse_hpet(acpi, &hpet_mapping)?;
             handler.unmap_physical_region(hpet_mapping);
         }
 
         Signature::MADT => {
-            let madt_mapping = handler.map_physical_region::<Madt>(physical_address, header.length as usize);
+            let madt_mapping =
+                unsafe { handler.map_physical_region::<Madt>(physical_address, header.length as usize) };
             crate::madt::parse_madt(acpi, handler, &madt_mapping)?;
             handler.unmap_physical_region(madt_mapping);
         }
 
         Signature::MCFG => {
-            let mcfg_mapping = handler.map_physical_region::<Mcfg>(physical_address, header.length as usize);
+            let mcfg_mapping =
+                unsafe { handler.map_physical_region::<Mcfg>(physical_address, header.length as usize) };
             crate::mcfg::parse_mcfg(acpi, &mcfg_mapping)?;
             handler.unmap_physical_region(mcfg_mapping);
         }