浏览代码

Merge #39

39: Get a release out r=IsaacWoods a=IsaacWoods

This crate's been a little neglected, so this is an attempt to sanitise some stuff and get a MVP release out so the crate is actually of use

One of the major changes I hope to make here is to split the static table discovery and AML parsing: the latter step is much less complete and you may not even want to do them at the same time (e.g. in Pebble, I want to find all the tables in the bootloader, and then parse AML in a safer environment in a userspace process). This enables that, without much trouble for people who want to parse it all at once.

Co-authored-by: Isaac Woods <isaacwoods.home@gmail.com>
bors[bot] 6 年之前
父节点
当前提交
ef13e64ecd
共有 21 个文件被更改,包括 239 次插入930 次删除
  1. 2 13
      Cargo.toml
  2. 8 8
      README.md
  3. 14 0
      acpi/Cargo.toml
  4. 3 15
      acpi/src/fadt.rs
  5. 39 0
      acpi/src/handler.rs
  6. 62 0
      acpi/src/hpet.rs
  7. 0 0
      acpi/src/interrupt.rs
  8. 50 75
      acpi/src/lib.rs
  9. 25 12
      acpi/src/madt.rs
  10. 3 5
      acpi/src/rsdp.rs
  11. 1 3
      acpi/src/rsdp_search.rs
  12. 8 9
      acpi/src/sdt.rs
  13. 12 0
      aml_parser/Cargo.toml
  14. 1 0
      aml_parser/src/lib.rs
  15. 11 0
      rustfmt.toml
  16. 0 60
      src/aml/mod.rs
  17. 0 19
      src/aml/opcodes.rs
  18. 0 531
      src/aml/parser.rs
  19. 0 67
      src/aml/stream.rs
  20. 0 94
      src/aml/value.rs
  21. 0 19
      src/hpet.rs

+ 2 - 13
Cargo.toml

@@ -1,13 +1,2 @@
-[package]
-name = "acpi"
-version = "0.1.0"
-authors = ["Isaac Woods <isaacwoods.home@gmail.com>"]
-repository = "https://github.com/rust-osdev/acpi"
-description = "Library for parsing ACPI tables and AML"
-readme = "README.md"
-license = "MIT/Apache-2.0"
-edition = "2018"
-
-[dependencies]
-log = "0.*"
-bit_field = "0.9.0"
+[workspace]
+members = ["acpi", "aml_parser"]

+ 8 - 8
README.md

@@ -2,20 +2,20 @@
 [![Build Status](https://travis-ci.org/rust-osdev/acpi.svg?branch=master)](https://travis-ci.org/rust-osdev/acpi)
 [![Version](https://img.shields.io/crates/v/acpi.svg?style=rounded-square)](https://crates.io/crates/acpi/)
 
-A library to parse ACPI tables and AML, written in Rust. Designed to be easy to use from inside a
-kernel written in Rust, and fully tested.
-**Acpi is currently very early in development, will be highly unstable and is next to useless for
-actually parsing ACPI or AML.**
+### [Documentation (`acpi`)](https://docs.rs/acpi)
+### [Documentation (`aml_parser`)](https://docs.rs/aml_parser)
 
-## Using
-`acpi` uses the nightly channel, and currently builds on `rustc 1.27.0-nightly (7925ff4e 2018-04-19)`.
-If `acpi` fails to build on a later nightly, please file an issue!
+A library to parse ACPI tables and AML, written in pure Rust. Designed to be easy to use from Rust bootloaders and kernels. The library is split into two crates:
+- `acpi` parses the static tables (useful but not feature-complete)
+- `aml_parser` parses the AML tables (still a work-in-progress, not that useful yet)
 
 ## Contributing
 Contributions are more than welcome! You can:
 - Write code - the ACPI spec is huge and there are bound to be things we don't support yet!
+- Documentation
+- Using the crates within your kernel and file bug reports and feature requests!
 
-## Resources
+Useful resources for contributing are:
 - [The ACPI specification](http://www.uefi.org/sites/default/files/resources/ACPI%206_2_A_Sept29.pdf)
 - [OSDev Wiki](https://wiki.osdev.org/ACPI)
 

+ 14 - 0
acpi/Cargo.toml

@@ -0,0 +1,14 @@
+[package]
+name = "acpi"
+version = "0.2.1"
+authors = ["Isaac Woods"]
+repository = "https://github.com/rust-osdev/acpi"
+description = "Library for parsing ACPI tables"
+categories = ["hardware-support", "no-std"]
+readme = "../README.md"
+license = "MIT/Apache-2.0"
+edition = "2018"
+
+[dependencies]
+log = "0.4"
+bit_field = "0.9"

+ 3 - 15
src/fadt.rs → acpi/src/fadt.rs

@@ -1,7 +1,4 @@
-use crate::aml::{parse_aml_table, AmlTable};
-use crate::sdt;
-use crate::sdt::SdtHeader;
-use crate::{Acpi, AcpiError, AcpiHandler, GenericAddress, PhysicalMapping};
+use crate::{sdt::SdtHeader, Acpi, AcpiError, AcpiHandler, GenericAddress, PhysicalMapping};
 
 /// 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
@@ -86,20 +83,11 @@ where
     fadt.header.validate(b"FACP")?;
 
     // TODO more generic typesafe way of accessing the x_ fields
-    let dsdt_physical_address: usize = if fadt.header.revision() > 1 && fadt.x_dsdt_address != 0 {
+    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
-    };
-
-    // Parse the DSDT
-    let dsdt_header = sdt::peek_at_sdt_header(handler, dsdt_physical_address);
-    let dsdt_mapping = handler
-        .map_physical_region::<AmlTable>(dsdt_physical_address, dsdt_header.length() as usize);
-    if let Err(error) = parse_aml_table(acpi, handler, &dsdt_mapping, b"DSDT") {
-        error!("Failed to parse DSDT: {:?}. At this stage, this is expected, but should be fatal in the future", error);
-    }
-    handler.unmap_physical_region(dsdt_mapping);
+    });
 
     Ok(())
 }

+ 39 - 0
acpi/src/handler.rs

@@ -0,0 +1,39 @@
+use core::{ops::Deref, ptr::NonNull};
+
+/// Describes a physical mapping created by `AcpiHandler::map_physical_region` and unmapped by
+/// `AcpiHandler::unmap_physical_region`. The region mapped must be at least `size_of::<T>()`
+/// bytes, but may be bigger.
+pub struct PhysicalMapping<T> {
+    pub physical_start: usize,
+    pub virtual_start: NonNull<T>,
+    pub region_length: usize, // Can be equal or larger than size_of::<T>()
+    pub mapped_length: usize, // Differs from `region_length` if padding is added for alignment
+}
+
+impl<T> Deref for PhysicalMapping<T> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        unsafe { self.virtual_start.as_ref() }
+    }
+}
+
+/// An implementation of this trait must be provided to allow `acpi` to access platform-specific
+/// functionality, such as mapping regions of physical memory. You are free to implement these
+/// however you please, as long as they conform to the documentation of each function.
+pub trait AcpiHandler {
+    /// Given a starting physical address and a size, map a region of physical memory that contains
+    /// a `T` (but may be bigger than `size_of::<T>()`). The address doesn't have to be
+    /// 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>;
+
+    /// Unmap the given physical mapping. Safe because we consume the mapping, and so it can't be
+    /// used after being passed to this function.
+    fn unmap_physical_region<T>(&mut self, region: PhysicalMapping<T>);
+}

+ 62 - 0
acpi/src/hpet.rs

@@ -0,0 +1,62 @@
+use crate::{sdt::SdtHeader, Acpi, AcpiError, GenericAddress, PhysicalMapping};
+use bit_field::BitField;
+
+#[derive(Debug)]
+pub enum PageProtection {
+    None,
+    /// Access to the adjacent 3KB to the base address will not generate a fault.
+    Protected4K,
+    /// Access to the adjacent 64KB to the base address will not generate a fault.
+    Protected64K,
+    Other,
+}
+
+/// Information about the High Precision Event Timer
+#[derive(Debug)]
+pub struct HpetInfo {
+    event_timer_block_id: u32,
+    base_address: usize,
+    hpet_number: u8,
+    /// The minimum number of clock ticks that can be set without losing interrupts (for timers in
+    /// Periodic Mode)
+    clock_tick_unit: u16,
+    page_protection: PageProtection,
+}
+
+#[repr(C, packed)]
+pub(crate) struct HpetTable {
+    header: SdtHeader,
+    event_timer_block_id: u32,
+    base_address: GenericAddress,
+    hpet_number: u8,
+    clock_tick_unit: u16,
+    page_protection_oem: u8,
+}
+
+pub(crate) fn parse_hpet(
+    acpi: &mut Acpi,
+    mapping: &PhysicalMapping<HpetTable>,
+) -> Result<(), AcpiError> {
+    (*mapping).header.validate(b"HPET")?;
+    let hpet = &*mapping;
+
+    // Make sure the HPET's in system memory
+    assert_eq!(hpet.base_address.address_space, 0);
+
+    info!("HPET address: {:#?}", hpet.base_address);
+    acpi.hpet = Some(HpetInfo {
+        event_timer_block_id: hpet.event_timer_block_id,
+        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) {
+            0 => PageProtection::None,
+            1 => PageProtection::Protected4K,
+            2 => PageProtection::Protected64K,
+            3..=15 => PageProtection::Other,
+            _ => unreachable!(),
+        },
+    });
+
+    Ok(())
+}

+ 0 - 0
src/interrupt.rs → acpi/src/interrupt.rs


+ 50 - 75
src/lib.rs → acpi/src/lib.rs

@@ -1,8 +1,30 @@
+//! A library for parsing ACPI tables. This crate can be used by bootloaders and kernels for
+//! architectures that support ACPI. The crate is far from feature-complete, but can still be used
+//! for finding and parsing the static tables, which is enough to set up hardware such as the APIC
+//! and HPET on x86_64.
+//!
+//! The crate is designed for use in conjunction with the `aml_parser` crate, which is the (much
+//! less complete) AML parser used to parse the DSDT and SSDTs. These crates are separate because
+//! some kernels may want to detect the static tables, but delay AML parsing to a later stage.
+//!
+//! ### Usage
+//! To use the library, you will need to provide an implementation of the `AcpiHandler` trait,
+//! which allows the library to make requests such as mapping a particular region of physical
+//! memory into the virtual address space.
+//!
+//! You should then call one of the entry points, based on how much information you have:
+//!     * Call `parse_rsdp` if you have the physical address of the RSDP
+//!     * Call `parse_rsdt` if you have the physical address of the RSDT / XSDT
+//!     * Call `search_for_rsdp_bios` if you don't have the address of either structure, but **you
+//!     know you're running on BIOS, not UEFI**
+//!
+//! All of these methods return an instance of `Acpi`. This struct contains all the information
+//! gathered from the static tables, and can be queried to set up hardware etc.
+
 #![no_std]
 #![feature(nll)]
 #![feature(alloc)]
-#![feature(exclusive_range_pattern, range_contains)]
-#![feature(exhaustive_integer_patterns)]
+#![feature(exclusive_range_pattern)]
 
 #[cfg_attr(test, macro_use)]
 #[cfg(test)]
@@ -13,8 +35,8 @@ extern crate log;
 extern crate alloc;
 extern crate bit_field;
 
-mod aml;
 mod fadt;
+pub mod handler;
 mod hpet;
 pub mod interrupt;
 mod madt;
@@ -22,18 +44,15 @@ mod rsdp;
 mod rsdp_search;
 mod sdt;
 
-pub use crate::aml::AmlError;
-pub use crate::madt::MadtError;
-pub use crate::rsdp_search::search_for_rsdp_bios;
+pub use crate::{
+    handler::{AcpiHandler, PhysicalMapping},
+    madt::MadtError,
+    rsdp_search::search_for_rsdp_bios,
+};
 
-use crate::aml::AmlValue;
-use crate::interrupt::InterruptModel;
-use crate::rsdp::Rsdp;
-use crate::sdt::SdtHeader;
-use alloc::{collections::BTreeMap, string::String, vec::Vec};
+use crate::{hpet::HpetInfo, interrupt::InterruptModel, rsdp::Rsdp, sdt::SdtHeader};
+use alloc::vec::Vec;
 use core::mem;
-use core::ops::Deref;
-use core::ptr::NonNull;
 
 #[derive(Debug)]
 // TODO: manually implement Debug to print signatures correctly etc.
@@ -48,11 +67,10 @@ pub enum AcpiError {
     SdtInvalidTableId([u8; 4]),
     SdtInvalidChecksum([u8; 4]),
 
-    InvalidAmlTable([u8; 4], AmlError),
-
     InvalidMadt(MadtError),
 }
 
+#[derive(Clone, Copy, Debug)]
 #[repr(C, packed)]
 pub(crate) struct GenericAddress {
     address_space: u8,
@@ -62,7 +80,7 @@ pub(crate) struct GenericAddress {
     address: u64,
 }
 
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum ProcessorState {
     /// A processor in this state is unusable, and you must not attempt to bring it up.
     Disabled,
@@ -75,7 +93,7 @@ pub enum ProcessorState {
     Running,
 }
 
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub struct Processor {
     pub processor_uid: u8,
     pub local_apic_id: u8,
@@ -97,57 +115,13 @@ impl Processor {
         state: ProcessorState,
         is_ap: bool,
     ) -> Processor {
-        Processor {
-            processor_uid,
-            local_apic_id,
-            state,
-            is_ap,
-        }
+        Processor { processor_uid, local_apic_id, state, is_ap }
     }
 }
 
-/// Describes a physical mapping created by `AcpiHandler::map_physical_region` and unmapped by
-/// `AcpiHandler::unmap_physical_region`. The region mapped must be at least `size_of::<T>()`
-/// bytes, but may be bigger.
-pub struct PhysicalMapping<T> {
-    pub physical_start: usize,
-    pub virtual_start: NonNull<T>,
-    pub region_length: usize, // Can be equal or larger than size_of::<T>()
-    pub mapped_length: usize, // Differs from `region_length` if padding is added for alignment
-}
-
-impl<T> Deref for PhysicalMapping<T> {
-    type Target = T;
-
-    fn deref(&self) -> &T {
-        unsafe { self.virtual_start.as_ref() }
-    }
-}
-
-/// An implementation of this trait must be provided to allow `acpi` to access platform-specific
-/// functionality, such as mapping regions of physical memory. You are free to implement these
-/// however you please, as long as they conform to the documentation of each function.
-pub trait AcpiHandler {
-    /// Given a starting physical address and a size, map a region of physical memory that contains
-    /// a `T` (but may be bigger than `size_of::<T>()`). The address doesn't have to be 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>;
-
-    /// Unmap the given physical mapping. Safe because we consume the mapping, and so it can't be
-    /// used after being passed to this function.
-    fn unmap_physical_region<T>(&mut self, region: PhysicalMapping<T>);
-}
-
 #[derive(Debug)]
 pub struct Acpi {
     acpi_revision: u8,
-    namespace: BTreeMap<String, AmlValue>,
     boot_processor: Option<Processor>,
     application_processors: Vec<Processor>,
 
@@ -155,6 +129,13 @@ pub struct Acpi {
     /// hardware. For simplicity and because hardware practically will only support one model, we
     /// just error in cases that the tables detail more than one.
     interrupt_model: Option<InterruptModel>,
+    hpet: Option<HpetInfo>,
+
+    /// The physical address of the DSDT, if we manage to find it.
+    dsdt_address: Option<usize>,
+
+    /// The physical addresses of the SSDTs, if there are any,
+    ssdt_addresses: Vec<usize>,
 }
 
 impl Acpi {
@@ -233,10 +214,12 @@ where
 {
     let mut acpi = Acpi {
         acpi_revision: revision,
-        namespace: BTreeMap::new(),
         boot_processor: None,
         application_processors: Vec::new(),
         interrupt_model: None,
+        hpet: None,
+        dsdt_address: None,
+        ssdt_addresses: Vec::with_capacity(0),
     };
 
     let header = sdt::peek_at_sdt_header(handler, physical_address);
@@ -255,11 +238,8 @@ where
             ((mapping.virtual_start.as_ptr() as usize) + mem::size_of::<SdtHeader>()) as *const u32;
 
         for i in 0..num_tables {
-            sdt::dispatch_sdt(
-                &mut acpi,
-                handler,
-                unsafe { *tables_base.offset(i as isize) } as usize,
-            )?;
+            sdt::dispatch_sdt(&mut acpi, handler, unsafe { *tables_base.offset(i as isize) }
+                as usize)?;
         }
     } else {
         /*
@@ -273,16 +253,11 @@ where
             ((mapping.virtual_start.as_ptr() as usize) + mem::size_of::<SdtHeader>()) as *const u64;
 
         for i in 0..num_tables {
-            sdt::dispatch_sdt(
-                &mut acpi,
-                handler,
-                unsafe { *tables_base.offset(i as isize) } as usize,
-            )?;
+            sdt::dispatch_sdt(&mut acpi, handler, unsafe { *tables_base.offset(i as isize) }
+                as usize)?;
         }
     }
 
-    info!("Parsed namespace: {:#?}", acpi.namespace);
-
     handler.unmap_physical_region(mapping);
     Ok(acpi)
 }

+ 25 - 12
src/madt.rs → acpi/src/madt.rs

@@ -1,12 +1,23 @@
-use crate::interrupt::{
-    InterruptModel, InterruptSourceOverride, IoApic, NmiSource, Polarity, TriggerMode,
+use crate::{
+    interrupt::{
+        InterruptModel,
+        InterruptSourceOverride,
+        IoApic,
+        NmiSource,
+        Polarity,
+        TriggerMode,
+    },
+    sdt::SdtHeader,
+    Acpi,
+    AcpiError,
+    AcpiHandler,
+    PhysicalMapping,
+    Processor,
+    ProcessorState,
 };
-use crate::sdt::SdtHeader;
-use crate::{Acpi, AcpiError, AcpiHandler, PhysicalMapping, Processor, ProcessorState};
 use alloc::vec::Vec;
 use bit_field::BitField;
-use core::marker::PhantomData;
-use core::mem;
+use core::{marker::PhantomData, mem};
 
 #[derive(Debug)]
 pub enum MadtError {
@@ -200,7 +211,8 @@ struct LocalApicAddressOverrideEntry {
     local_apic_address: u64,
 }
 
-/// If this entry is present, the system has an I/O SAPIC, which must be used instead of the I/O APIC.
+/// If this entry is present, the system has an I/O SAPIC, which must be used instead of the I/O
+/// APIC.
 #[repr(C, packed)]
 struct IoSapicEntry {
     header: EntryHeader,
@@ -337,9 +349,10 @@ where
     (*mapping).header.validate(b"APIC")?;
 
     /*
-     * If the MADT doesn't contain another supported interrupt model (either APIC, SAPIC, X2APIC or
-     * GIC), and the system supports the legacy i8259 PIC, recommend that.
-     * TODO: It's not clear how trustworthy this field is - should we be relying on it in any way?
+     * If the MADT doesn't contain another supported interrupt model (either APIC, SAPIC, X2APIC
+     * or GIC), and the system supports the legacy i8259 PIC, recommend that.
+     * TODO: It's not clear how trustworthy this field is - should we be relying on it in any
+     * way?
      */
     if (*mapping).supports_8259() {
         acpi.interrupt_model = Some(InterruptModel::Pic);
@@ -402,8 +415,8 @@ fn parse_apic_model(
         match entry {
             MadtEntry::LocalApic(ref entry) => {
                 /*
-                 * The first processor is the BSP. Subsequent ones are APs. If we haven't found the
-                 * BSP yet, this must be it.
+                 * The first processor is the BSP. Subsequent ones are APs. If we haven't found
+                 * the BSP yet, this must be it.
                  */
                 let is_ap = acpi.boot_processor.is_some();
                 let is_disabled = !unsafe { entry.flags.get_bit(0) };

+ 3 - 5
src/rsdp.rs → acpi/src/rsdp.rs

@@ -5,7 +5,8 @@ use core::{mem, str};
 ///
 /// On BIOS systems, it is either found in the first 1KB of the Extended Bios Data Area, or between
 /// 0x000E0000 and 0x000FFFFF. The signature is always on a 16 byte boundary. On (U)EFI, it may not
-/// be located in these locations, and so an address should be found in the EFI_SYSTEM_TABLE instead.
+/// be located in these locations, and so an address should be found in the EFI_SYSTEM_TABLE
+/// instead.
 ///
 /// The recommended way of locating the RSDP is to let the bootloader do it - Multiboot2 can pass a
 /// tag with the physical address of it. If this is not possible, a manual scan can be done.
@@ -89,10 +90,7 @@ impl Rsdp {
     }
 
     pub(crate) fn xsdt_address(&self) -> u64 {
-        assert!(
-            self.revision > 0,
-            "Tried to read extended RSDP field with ACPI Version 1.0"
-        );
+        assert!(self.revision > 0, "Tried to read extended RSDP field with ACPI Version 1.0");
         self.xsdt_address
     }
 }

+ 1 - 3
src/rsdp_search.rs → acpi/src/rsdp_search.rs

@@ -1,6 +1,4 @@
-use crate::rsdp::Rsdp;
-use crate::Acpi;
-use crate::{parse_validated_rsdp, AcpiError, AcpiHandler};
+use crate::{parse_validated_rsdp, rsdp::Rsdp, Acpi, AcpiError, AcpiHandler};
 use core::{mem, ops::RangeInclusive};
 
 /// The pointer to the EBDA (Extended Bios Data Area) start segment pointer

+ 8 - 9
src/sdt.rs → acpi/src/sdt.rs

@@ -1,7 +1,4 @@
-use crate::fadt::Fadt;
-use crate::hpet::Hpet;
-use crate::madt::Madt;
-use crate::{Acpi, AcpiError, AcpiHandler};
+use crate::{fadt::Fadt, hpet::HpetTable, madt::Madt, Acpi, AcpiError, AcpiHandler};
 use core::{mem, str};
 
 /// All SDTs share the same header, and are `length` bytes long. The signature tells us which SDT
@@ -140,8 +137,8 @@ where
     H: AcpiHandler,
 {
     let header = peek_at_sdt_header(handler, physical_address);
-    info!(
-        "Dispatching SDT with signature {:?} and length {:?}",
+    trace!(
+        "Found ACPI table with signature {:?} and length {:?}",
         header.signature(),
         header.length()
     );
@@ -159,9 +156,9 @@ where
         }
 
         "HPET" => {
-            let hpet_mapping =
-                handler.map_physical_region::<Hpet>(physical_address, mem::size_of::<Hpet>());
-            crate::hpet::parse_hpet(&hpet_mapping)?;
+            let hpet_mapping = handler
+                .map_physical_region::<HpetTable>(physical_address, mem::size_of::<HpetTable>());
+            crate::hpet::parse_hpet(acpi, &hpet_mapping)?;
             handler.unmap_physical_region(hpet_mapping);
         }
 
@@ -172,6 +169,8 @@ where
             handler.unmap_physical_region(madt_mapping);
         }
 
+        "SSDT" => acpi.ssdt_addresses.push(physical_address),
+
         signature => {
             /*
              * We don't recognise this signature. Early on, this probably just means we don't

+ 12 - 0
aml_parser/Cargo.toml

@@ -0,0 +1,12 @@
+[package]
+name = "aml_parser"
+version = "0.2.0"
+authors = ["Isaac Woods"]
+repository = "https://github.com/rust-osdev/acpi"
+description = "Library for parsing AML"
+categories = ["hardware-support", "no-std"]
+readme = "../README.md"
+license = "MIT/Apache-2.0"
+edition = "2018"
+
+[dependencies]

+ 1 - 0
aml_parser/src/lib.rs

@@ -0,0 +1 @@
+#![no_std]

+ 11 - 0
rustfmt.toml

@@ -0,0 +1,11 @@
+unstable_features = true
+edition = "2018"
+
+merge_imports = true
+imports_layout = "HorizontalVertical"
+use_field_init_shorthand = true
+use_try_shorthand = true
+format_doc_comments = true
+wrap_comments = true
+comment_width = 100
+use_small_heuristics = "max"

+ 0 - 60
src/aml/mod.rs

@@ -1,60 +0,0 @@
-mod opcodes;
-mod parser;
-mod stream;
-mod value;
-
-pub use self::value::AmlValue;
-
-use self::parser::AmlParser;
-use self::stream::AmlStream;
-use crate::sdt::SdtHeader;
-use crate::{Acpi, AcpiError, AcpiHandler, PhysicalMapping};
-use alloc::string::String;
-use core::{mem, slice};
-
-/// Represents a table containing AML. For ACPI Version 2+, this is just the DSDT and SSDTs.
-/// Version 1.0 may also have a PSDT.
-#[repr(C, packed)]
-pub struct AmlTable {
-    header: SdtHeader,
-    // ...
-}
-
-#[derive(Debug)]
-pub enum AmlError {
-    EndOfStream,
-    UnexpectedByte(u8),
-    IncompatibleValueConversion,
-    InvalidPath(String),
-    InvalidFieldFlags,
-    InvalidNameSeg([u8; 4]),
-}
-
-impl AmlTable {
-    /// Get the AML stream encoded in this table so it can be safely accessed
-    pub fn stream<'a>(&'a self) -> AmlStream<'a> {
-        assert!(self.header.length() as usize > mem::size_of::<SdtHeader>());
-        let stream_length = self.header.length() as usize - mem::size_of::<SdtHeader>();
-        let stream_ptr =
-            ((self as *const AmlTable as usize) + mem::size_of::<SdtHeader>()) as *const u8;
-
-        unsafe { AmlStream::new(slice::from_raw_parts(stream_ptr, stream_length)) }
-    }
-}
-
-pub(crate) fn parse_aml_table<H>(
-    acpi: &mut Acpi,
-    handler: &mut H,
-    mapping: &PhysicalMapping<AmlTable>,
-    signature: &[u8; 4],
-) -> Result<(), AcpiError>
-where
-    H: AcpiHandler,
-{
-    (*mapping).header.validate(signature)?;
-
-    match AmlParser::parse(acpi, handler, "\\", (*mapping).stream()) {
-        Ok(_) => Ok(()),
-        Err(error) => Err(AcpiError::InvalidAmlTable(*signature, error)),
-    }
-}

+ 0 - 19
src/aml/opcodes.rs

@@ -1,19 +0,0 @@
-pub const NULL_NAME: u8 = 0x00;
-pub const DUAL_NAME_PREFIX: u8 = 0x2E;
-pub const MULTI_NAME_PREFIX: u8 = 0x2F;
-
-pub const ZERO_OP: u8 = 0x00;
-pub const ONE_OP: u8 = 0x01;
-pub const ONES_OP: u8 = 0xff;
-pub const BYTE_CONST: u8 = 0x0a;
-pub const WORD_CONST: u8 = 0x0b;
-pub const DWORD_CONST: u8 = 0x0c;
-pub const STRING_PREFIX: u8 = 0x0d;
-pub const QWORD_CONST: u8 = 0x0e;
-
-pub const SCOPE_OP: u8 = 0x10;
-pub const EXT_OP_REGION_OP: u8 = 0x80;
-pub const EXT_REVISION_OP: u8 = 0x30;
-pub const EXT_FIELD_OP: u8 = 0x81;
-
-pub const EXT_OPCODE_PREFIX: u8 = 0x5b;

+ 0 - 531
src/aml/parser.rs

@@ -1,531 +0,0 @@
-use super::stream::AmlStream;
-use super::value::{AmlValue, FieldFlags, RegionSpace};
-use super::{opcodes, AmlError};
-use crate::{Acpi, AcpiHandler};
-use alloc::string::String;
-use bit_field::BitField;
-use core::str;
-
-/// This is used internally by the parser to keep track of what we know about a field before we can
-/// add it to the namespace.
-struct FieldInfo {
-    pub name: String,
-    pub length: u64,
-}
-
-/// This is used internally by the parser. Often, we're only interested in offset of the end of the
-/// current explicit-length structure, so we know when to stop parsing it. However, various constants
-/// (e.g. the size of fields) are also encoded as PkgLengths, and so sometimes we want to access
-/// the raw data as well.
-struct PkgLength {
-    pub raw_length: u32,
-    pub end_offset: u32,
-}
-
-pub(crate) struct AmlParser<'s, 'a, 'h, H>
-where
-    H: AcpiHandler + 'h,
-{
-    acpi: &'a mut Acpi,
-    handler: &'h mut H,
-    scope: String,
-    stream: AmlStream<'s>,
-}
-
-/// This macro takes a parser and one or more parsing functions and tries to parse the next part of
-/// the stream with each one. If a parsing function fails, it rolls back the stream and tries the
-/// next one. If none of the functions can parse the next part of the stream, we error on the
-/// unexpected byte.
-macro_rules! try_parse {
-    ($parser: expr, $($function: path),+) => {{
-        $(if let Some(value) = $parser.try_parse($function)? {
-            Ok(value)
-        } else)+ {
-            Err(AmlError::UnexpectedByte($parser.stream.peek()?))
-        }
-    }}
-}
-
-impl<'s, 'a, 'h, H> AmlParser<'s, 'a, 'h, H>
-where
-    H: AcpiHandler,
-{
-    pub(crate) fn parse(
-        acpi: &'a mut Acpi,
-        handler: &'h mut H,
-        scope: &str,
-        stream: AmlStream<'s>,
-    ) -> Result<(), AmlError> {
-        let mut parser = AmlParser {
-            acpi,
-            handler,
-            scope: String::from(scope),
-            stream,
-        };
-
-        let end_offset = parser.stream.len() as u32;
-        parser.parse_term_list(end_offset)
-    }
-
-    /// Consume the next byte in the stream and check if it fulfils the given predicate. If it
-    /// does, returns `Ok(the consumed char)`. If it doesn't, returns
-    /// `Err(AmlError::UnexpectedByte(the consumed char)`. If there's an error consuming the char,
-    /// it will forward the error on from that.
-    fn consume_byte<F>(&mut self, predicate: F) -> Result<u8, AmlError>
-    where
-        F: Fn(u8) -> bool,
-    {
-        let byte = self.stream.next()?;
-
-        match predicate(byte) {
-            true => Ok(byte),
-            false => Err(AmlError::UnexpectedByte(byte)),
-        }
-    }
-
-    fn consume_opcode(&mut self, opcode: u8) -> Result<(), AmlError> {
-        self.consume_byte(matches_byte(opcode))?;
-        Ok(())
-    }
-
-    fn consume_ext_opcode(&mut self, ext_opcode: u8) -> Result<(), AmlError> {
-        self.consume_byte(matches_byte(opcodes::EXT_OPCODE_PREFIX))?;
-        self.consume_byte(matches_byte(ext_opcode))?;
-        Ok(())
-    }
-
-    /// Try to parse the next part of the stream with the given parsing function. This returns any
-    /// `AmlError` as an `Err`, except `AmlError::UnexpectedByte`, to which it will return
-    /// `Ok(None)`. A successful parse gives `Ok(Some(...))`. On failure, this also reverts any
-    /// changes made to the stream, so it's as if the parsing function never run.
-    fn try_parse<T, F>(&mut self, parsing_function: F) -> Result<Option<T>, AmlError>
-    where
-        F: Fn(&mut Self) -> Result<T, AmlError>,
-    {
-        let stream = self.stream.clone();
-
-        match parsing_function(self) {
-            Ok(result) => Ok(Some(result)),
-
-            Err(AmlError::UnexpectedByte(_)) => {
-                self.stream = stream;
-                Ok(None)
-            }
-
-            Err(error) => Err(error),
-        }
-    }
-
-    fn parse_term_list(&mut self, end_offset: u32) -> Result<(), AmlError> {
-        /*
-         * TermList := Nothing | <TermObj TermList>
-         *
-         * Because TermLists don't have PkgLengths, we pass the offset to stop at from whatever
-         * explicit-length object we were parsing before.
-         */
-        while self.stream.offset() <= end_offset {
-            self.parse_term_object()?;
-        }
-
-        Ok(())
-    }
-
-    fn parse_term_object(&mut self) -> Result<(), AmlError> {
-        /*
-         * TermObj := NameSpaceModifierObj | NamedObj | Type1Opcode | Type2Opcode
-         * NameSpaceModifierObj := DefAlias | DefName | DefScope
-         * NamedObj := DefBankField | DefCreateBitField | DefCreateByteField | DefCreateDWordField |
-         *             DefCreateField | DefCreateQWordField | DefCreateWordField | DefDataRegion |
-         *             DefExternal | DefOpRegion | DefPowerRes | DefProcessor | DefThermalZone
-         */
-        try_parse!(
-            self,
-            AmlParser::parse_def_scope,
-            AmlParser::parse_def_op_region,
-            AmlParser::parse_def_field //,
-                                       // AmlParser::parse_type1_opcode    TODO: reenable when we can parse them
-        )
-    }
-
-    fn parse_def_scope(&mut self) -> Result<(), AmlError> {
-        /*
-         * DefScope := 0x10 PkgLength NameString TermList
-         */
-        self.consume_opcode(opcodes::SCOPE_OP)?;
-        trace!("Parsing scope op");
-        let scope_end_offset = self.parse_pkg_length()?.end_offset;
-
-        let name_string = self.parse_name_string()?;
-        let containing_scope = self.scope.clone();
-
-        self.scope = name_string;
-        let _term_list = self.parse_term_list(scope_end_offset)?;
-        self.scope = containing_scope;
-
-        Ok(())
-    }
-
-    fn parse_def_op_region(&mut self) -> Result<(), AmlError> {
-        /*
-         * DefOpRegion := ExtOpPrefix 0x80 NameString RegionSpace RegionOffset RegionLen
-         * RegionSpace := ByteData (where 0x00      = SystemMemory
-         *                                0x01      = SystemIO
-         *                                0x02      = PciConfig
-         *                                0x03      = EmbeddedControl
-         *                                0x04      = SMBus
-         *                                0x05      = SystemCMOS
-         *                                0x06      = PciBarTarget
-         *                                0x07      = IPMI
-         *                                0x08      = GeneralPurposeIO
-         *                                0x09      = GenericSerialBus
-         *                                0x80-0xff = OEM Defined)
-         * ByteData := 0x00 - 0xff
-         * RegionOffset := TermArg => Integer
-         * RegionLen := TermArg => Integer
-         */
-        self.consume_ext_opcode(opcodes::EXT_OP_REGION_OP)?;
-        info!("Parsing op region");
-
-        let name = self.parse_name_string()?;
-        info!("name: {}", name);
-        let region_space = match self.stream.next()? {
-            0x00 => RegionSpace::SystemMemory,
-            0x01 => RegionSpace::SystemIo,
-            0x02 => RegionSpace::PciConfig,
-            0x03 => RegionSpace::EmbeddedControl,
-            0x04 => RegionSpace::SMBus,
-            0x05 => RegionSpace::SystemCmos,
-            0x06 => RegionSpace::PciBarTarget,
-            0x07 => RegionSpace::IPMI,
-            0x08 => RegionSpace::GeneralPurposeIo,
-            0x09 => RegionSpace::GenericSerialBus,
-            space @ 0x80..0xff => RegionSpace::OemDefined(space),
-            byte => return Err(AmlError::UnexpectedByte(byte)),
-        };
-        info!("region space: {:?}", region_space);
-        let offset = self.parse_term_arg()?.as_integer()?;
-        info!("region offset: {}", offset);
-        let length = self.parse_term_arg()?.as_integer()?;
-        info!("region len: {}", length);
-
-        // Insert it into the namespace
-        let namespace_path = self.resolve_path(&name)?;
-        self.acpi.namespace.insert(
-            // self.resolve_path(name)?, TODO: I thought this would work with nll?
-            namespace_path,
-            AmlValue::OpRegion {
-                region: region_space,
-                offset,
-                length,
-            },
-        );
-
-        Ok(())
-    }
-
-    fn parse_def_field(&mut self) -> Result<(), AmlError> {
-        /*
-         * DefField = ExtOpPrefix 0x81 PkgLength NameString FieldFlags FieldList
-         * FieldList := Nothing | <FieldElement FieldList>
-         * FieldElement := NamedField | ReservedField | AccessField | ExtendedAccessField |
-         *                 ConnectField
-         * ReservedField := 0x00 PkgLength
-         * AccessField := 0x01 AccessType AccessAttrib
-         * AccessType := ByteData
-         * AccessAttrib := ByteData
-         * ConnectField := <0x02 NameString> | <0x02 BufferData>
-         */
-        self.consume_ext_opcode(opcodes::EXT_FIELD_OP)?;
-        trace!("Parsing DefField");
-        let end_offset = self.parse_pkg_length()?.end_offset;
-        trace!("end offset: {}", end_offset);
-        let name = self.parse_name_string()?;
-        trace!("name: {}", name);
-        let flags = FieldFlags::new(self.stream.next()?);
-        trace!("Field flags: {:?}", flags);
-
-        while self.stream.offset() < end_offset {
-            // TODO: parse other field types
-            let info = try_parse!(self, AmlParser::parse_named_field)?;
-
-            // TODO: add field name to this (info.name)?
-            let namespace_path = self.resolve_path(&name)?;
-            self.acpi.namespace.insert(
-                namespace_path,
-                AmlValue::Field {
-                    flags,
-                    offset: 0, // TODO: calculate offset
-                    length: info.length,
-                },
-            );
-        }
-
-        Ok(())
-    }
-
-    fn parse_named_field(&mut self) -> Result<FieldInfo, AmlError> {
-        /*
-         * NamedField := NameSeg PkgLength
-         *
-         * This encodes the size of the field using a PkgLength - it doesn't mark the length of an
-         * explicit-length structure!
-         */
-        let name = String::from(name_seg_to_string(&self.parse_name_seg()?)?);
-        let length = self.parse_pkg_length()?.raw_length as u64;
-        info!("Adding named field called {:?} with size {}", name, length);
-
-        Ok(FieldInfo { name, length })
-    }
-
-    fn parse_def_buffer(&mut self) -> Result<AmlValue, AmlError> {
-        unimplemented!(); // TODO
-    }
-
-    fn parse_term_arg(&mut self) -> Result<AmlValue, AmlError> {
-        /*
-         * TermArg := Type2Opcode | DataObject | ArgObj | LocalObj
-         * DataObject := ComputationalData | DefPackage | DefVarPackage
-         */
-        if let Some(result) = self.try_parse(AmlParser::parse_computational_data)? {
-            Ok(result)
-        } else {
-            Err(AmlError::UnexpectedByte(self.stream.next()?))
-        }
-    }
-
-    fn parse_computational_data(&mut self) -> Result<AmlValue, AmlError> {
-        /*
-         * ComputationalData := ByteConst | WordConst | DWordConst | QWordConst | String |
-         *                      ConstObj | RevisionOp | DefBuffer
-         * ByteConst := 0x0a ByteData
-         * WordConst := 0x0b WordData
-         * DWordConst := 0x0c DWordData
-         * QWordConst := 0x0e QWordData
-         * String := 0x0d AsciiCharList NullChar
-         * ConstObj := ZeroOp(0x00) | OneOp(0x01) | OnesOp(0xff)
-         * RevisionOp := ExtOpPrefix(0x5B) 0x30
-         */
-        match self.stream.peek()? {
-            opcodes::BYTE_CONST => {
-                self.consume_opcode(opcodes::BYTE_CONST)?;
-                Ok(AmlValue::Integer(self.stream.next()? as u64))
-            }
-
-            opcodes::WORD_CONST => {
-                self.consume_opcode(opcodes::WORD_CONST)?;
-                Ok(AmlValue::Integer(self.stream.next_u16()? as u64))
-            }
-
-            opcodes::DWORD_CONST => {
-                self.consume_opcode(opcodes::DWORD_CONST)?;
-                Ok(AmlValue::Integer(self.stream.next_u16()? as u64))
-            }
-
-            opcodes::QWORD_CONST => {
-                self.consume_opcode(opcodes::QWORD_CONST)?;
-                Ok(AmlValue::Integer(self.stream.next_u16()? as u64))
-            }
-
-            opcodes::STRING_PREFIX => {
-                self.consume_opcode(opcodes::STRING_PREFIX)?;
-                unimplemented!(); // TODO
-            }
-
-            opcodes::ZERO_OP => {
-                self.consume_opcode(opcodes::ZERO_OP)?;
-                Ok(AmlValue::Integer(0))
-            }
-
-            opcodes::ONE_OP => {
-                self.consume_opcode(opcodes::ONE_OP)?;
-                Ok(AmlValue::Integer(1))
-            }
-
-            opcodes::ONES_OP => {
-                self.consume_opcode(opcodes::ONES_OP)?;
-                Ok(AmlValue::Integer(u64::max_value()))
-            }
-
-            opcodes::EXT_OPCODE_PREFIX if self.stream.lookahead(1)? == opcodes::EXT_REVISION_OP => {
-                unimplemented!(); // TODO
-            }
-
-            _ => self.parse_def_buffer(),
-        }
-    }
-
-    fn parse_type1_opcode(&mut self) -> Result<(), AmlError> {
-        /*
-         * Type1Opcode := DefBreak | DefBreakPoint | DefContinue | DefFatal | DefIfElse | DefLoad |
-         *                DefNoop | DefNotify | DefRelease | DefReset | DefReturn | DefSignal |
-         *                DefSleep | DefStall | DefUnload | DefWhile
-         */
-        unimplemented!(); // TODO
-    }
-
-    /// Parse a PkgLength. Returns the offset into the stream to stop parsing whatever object the
-    /// PkgLength describes at.
-    // TODO: think hard about whether we actually need to minus the length now because we use
-    // `next()`? Isn't this already handled?
-    fn parse_pkg_length(&mut self) -> Result<PkgLength, AmlError> {
-        /*
-         * PkgLength := PkgLeadByte |
-         *              <PkgLeadByte ByteData> |
-         *              <PkgLeadByte ByteData ByteData> |
-         *              <PkgLeadByte ByteData ByteData ByteData>
-         */
-        let lead_byte = self.stream.next()?;
-        let byte_data_count = lead_byte.get_bits(6..8);
-
-        if byte_data_count == 0 {
-            let length = u32::from(lead_byte.get_bits(0..6));
-            let end_offset = self.stream.offset() + length - 1; // Minus 1 to remove the PkgLength byte
-            trace!(
-                "Parsed 1-byte PkgLength with length {}, so ends at {}(current offset={}",
-                length,
-                end_offset,
-                self.stream.offset()
-            );
-            return Ok(PkgLength {
-                raw_length: length,
-                end_offset,
-            });
-        }
-
-        let mut length = u32::from(lead_byte.get_bits(0..4));
-        for i in 0..byte_data_count {
-            length += u32::from(self.stream.next()?) << (4 + i * 8);
-        }
-
-        // Minus `byte_data_count + 1` to not include the PkgLength in the remaining bytes
-        let end_offset = self.stream.offset() + length - byte_data_count as u32 - 1;
-        trace!(
-            "Parsed PkgLength with length {}, so ends at {}(current offset={})",
-            length,
-            end_offset,
-            self.stream.offset()
-        );
-        Ok(PkgLength {
-            raw_length: length,
-            end_offset,
-        })
-    }
-
-    fn parse_name_string(&mut self) -> Result<String, AmlError> {
-        /*
-         * NameString := <RootChar('\') NamePath> | <PrefixPath NamePath>
-         * PrefixPath := Nothing | <'^' PrefixPath>
-         */
-        match self.stream.peek()? {
-            b'\\' => {
-                /*
-                 * NameString := RootChar NamePath
-                 */
-                self.stream.next()?;
-                Ok(String::from("\\") + &self.parse_name_path()?)
-            }
-
-            b'^' => {
-                unimplemented!();
-            }
-
-            _ => self.parse_name_path(),
-        }
-    }
-
-    fn parse_name_path(&mut self) -> Result<String, AmlError> {
-        /*
-         * NamePath := NameSeg | DualNamePath | MultiNamePath | NullPath
-         * DualNamePath := DualNamePrefix NameSeg NameSeg
-         * MultiNamePath := MultiNamePrefix SegCount{ByteData} NameSeg(..SegCount)
-         */
-        match self.stream.peek()? {
-            opcodes::NULL_NAME => {
-                self.stream.next()?;
-                Ok(String::from(""))
-            }
-
-            opcodes::DUAL_NAME_PREFIX => {
-                self.stream.next()?;
-                let first = self.parse_name_seg()?;
-                let second = self.parse_name_seg()?;
-
-                Ok(
-                    String::from(str::from_utf8(&first).unwrap())
-                        + str::from_utf8(&second).unwrap(),
-                )
-            }
-
-            opcodes::MULTI_NAME_PREFIX => {
-                // TODO
-                unimplemented!();
-            }
-
-            _ => Ok(String::from(
-                str::from_utf8(&self.parse_name_seg()?).unwrap(),
-            )),
-        }
-    }
-
-    fn parse_name_seg(&mut self) -> Result<[u8; 4], AmlError> {
-        /*
-         * NameSeg := <LeadNameChar NameChar NameChar NameChar>
-         */
-        Ok([
-            self.consume_byte(is_lead_name_char)?,
-            self.consume_byte(is_name_char)?,
-            self.consume_byte(is_name_char)?,
-            self.consume_byte(is_name_char)?,
-        ])
-    }
-
-    /// Resolve a given path and the current scope to an absolute path in the namespace.
-    fn resolve_path(&mut self, mut path: &str) -> Result<String, AmlError> {
-        /*
-         * TODO: how should we handle '.' as they appear in paths?
-         */
-        let original_path = path.clone();
-
-        // If the scope to resolve is from the root of the namespace, or the current scope is
-        // nothing, just return the given scope
-        if self.scope == "" || path.starts_with("\\") {
-            return Ok(String::from(path));
-        }
-
-        // "^"s at the start of a path specify to go up one level from the current scope, to its
-        // parent object
-        let mut namespace_object = self.scope.clone();
-        while path.starts_with("^") {
-            path = &path[1..];
-
-            if namespace_object.pop() == None {
-                return Err(AmlError::InvalidPath(String::from(original_path)));
-            }
-        }
-
-        Ok(namespace_object + &path)
-    }
-}
-
-fn matches_byte(byte: u8) -> impl Fn(u8) -> bool {
-    move |x| x == byte
-}
-
-fn is_lead_name_char(byte: u8) -> bool {
-    (byte >= b'A' && byte <= b'Z') || byte == b'_'
-}
-
-fn is_digit_char(byte: u8) -> bool {
-    byte >= b'0' && byte <= b'9'
-}
-
-fn is_name_char(byte: u8) -> bool {
-    is_lead_name_char(byte) || is_digit_char(byte)
-}
-
-fn name_seg_to_string<'a>(seg: &'a [u8; 4]) -> Result<&'a str, AmlError> {
-    match str::from_utf8(seg) {
-        Ok(seg_str) => Ok(seg_str),
-        Err(_) => Err(AmlError::InvalidNameSeg(*seg)),
-    }
-}

+ 0 - 67
src/aml/stream.rs

@@ -1,67 +0,0 @@
-use super::AmlError;
-
-#[derive(Clone)]
-pub struct AmlStream<'a> {
-    data: &'a [u8],
-    offset: u32, // TODO: PkgLength can't be longer than u32, but can a whole AML stream?
-}
-
-impl<'a> AmlStream<'a> {
-    pub unsafe fn new(data: &'a [u8]) -> AmlStream<'a> {
-        AmlStream { data, offset: 0 }
-    }
-
-    pub fn peek(&self) -> Result<u8, AmlError> {
-        if (self.offset + 1) >= self.len() {
-            Err(AmlError::EndOfStream)
-        } else {
-            Ok(self.data[self.offset as usize])
-        }
-    }
-
-    pub fn next(&mut self) -> Result<u8, AmlError> {
-        let byte = self.peek()?;
-        self.offset += 1;
-        Ok(byte)
-    }
-
-    pub fn next_u16(&mut self) -> Result<u16, AmlError> {
-        let first_byte = self.next()?;
-        let second_byte = self.next()?;
-        Ok(first_byte as u16 + ((second_byte as u16) << 8))
-    }
-
-    pub fn next_u32(&mut self) -> Result<u32, AmlError> {
-        let first_byte = self.next()?;
-        let second_byte = self.next()?;
-        let third_byte = self.next()?;
-        Ok(first_byte as u32 + ((second_byte as u32) << 8) + ((third_byte as u32) << 16))
-    }
-
-    pub fn next_u64(&mut self) -> Result<u64, AmlError> {
-        let first_byte = self.next()?;
-        let second_byte = self.next()?;
-        let third_byte = self.next()?;
-        let forth_byte = self.next()?;
-        Ok(first_byte as u64
-            + ((second_byte as u64) << 8)
-            + ((third_byte as u64) << 16)
-            + ((forth_byte as u64) << 24))
-    }
-
-    pub fn lookahead(&self, amount: u32) -> Result<u8, AmlError> {
-        match self.offset.checked_add(amount) {
-            Some(offset) => Ok(self.data[offset as usize]),
-            None => Err(AmlError::EndOfStream),
-        }
-    }
-
-    pub fn len(&self) -> u32 {
-        self.data.len() as u32
-    }
-
-    /// This gets the current offset into the stream
-    pub fn offset(&self) -> u32 {
-        self.offset
-    }
-}

+ 0 - 94
src/aml/value.rs

@@ -1,94 +0,0 @@
-use super::AmlError;
-use bit_field::BitField;
-
-#[derive(Debug)]
-pub enum RegionSpace {
-    SystemMemory,
-    SystemIo,
-    PciConfig,
-    EmbeddedControl,
-    SMBus,
-    SystemCmos,
-    PciBarTarget,
-    IPMI,
-    GeneralPurposeIo,
-    GenericSerialBus,
-    OemDefined(u8),
-}
-
-pub enum FieldAccessType {
-    Any,
-    Byte,
-    Word,
-    DWord,
-    QWord,
-    Buffer,
-    Reserved,
-}
-
-pub enum FieldUpdateRule {
-    Preserve,
-    WriteAsOnes,
-    WriteAsZeros,
-}
-
-#[derive(Clone, Copy, Debug)] // TODO: custom debug / get rid of completely
-pub struct FieldFlags(u8);
-
-impl FieldFlags {
-    pub fn new(value: u8) -> FieldFlags {
-        FieldFlags(value)
-    }
-
-    pub fn access_type(&self) -> Result<FieldAccessType, AmlError> {
-        match self.0.get_bits(0..4) {
-            0 => Ok(FieldAccessType::Any),
-            1 => Ok(FieldAccessType::Byte),
-            2 => Ok(FieldAccessType::Word),
-            3 => Ok(FieldAccessType::DWord),
-            4 => Ok(FieldAccessType::QWord),
-            5 => Ok(FieldAccessType::Buffer),
-            _ => Err(AmlError::InvalidFieldFlags),
-        }
-    }
-
-    pub fn lock_rule(&self) -> bool {
-        self.0.get_bit(4)
-    }
-
-    pub fn field_update_rule(&self) -> Result<FieldUpdateRule, AmlError> {
-        match self.0.get_bits(5..7) {
-            0 => Ok(FieldUpdateRule::Preserve),
-            1 => Ok(FieldUpdateRule::WriteAsOnes),
-            2 => Ok(FieldUpdateRule::WriteAsZeros),
-            _ => Err(AmlError::InvalidFieldFlags),
-        }
-    }
-}
-
-#[derive(Debug)]
-pub enum AmlValue {
-    Integer(u64),
-
-    OpRegion {
-        region: RegionSpace,
-        offset: u64,
-        length: u64,
-    },
-
-    Field {
-        flags: FieldFlags,
-        offset: u64,
-        length: u64,
-    },
-}
-
-impl AmlValue {
-    pub fn as_integer(&self) -> Result<u64, AmlError> {
-        match self {
-            AmlValue::Integer(value) => Ok(*value),
-
-            _ => Err(AmlError::IncompatibleValueConversion),
-        }
-    }
-}

+ 0 - 19
src/hpet.rs

@@ -1,19 +0,0 @@
-use crate::sdt::SdtHeader;
-use crate::{AcpiError, GenericAddress, PhysicalMapping};
-
-#[repr(C, packed)]
-pub struct Hpet {
-    header: SdtHeader,
-
-    event_timer_block_id: u32,
-    base_address: GenericAddress,
-    hpet_number: u8,
-    clock_tick_unit: u16,
-    page_protection_oem: u8,
-}
-
-pub fn parse_hpet(mapping: &PhysicalMapping<Hpet>) -> Result<(), AcpiError> {
-    (*mapping).header.validate(b"HPET")?;
-
-    Ok(())
-}