summary refs log tree commit diff
diff options
context:
space:
mode:
authorChuanxiao Dong <chuanxiao.dong@intel.corp-partner.google.com>2020-02-19 14:18:20 +0800
committerCommit Bot <commit-bot@chromium.org>2020-04-25 17:59:57 +0000
commitd5f47a98657034b0ddc332d5e0b700e38155c160 (patch)
tree60f21b4e37305fd61b5f06e3982950db8f3c0e51
parent6031ff4b8196f8e1a7e118b53d2f12f41d509d9b (diff)
downloadcrosvm-d5f47a98657034b0ddc332d5e0b700e38155c160.tar
crosvm-d5f47a98657034b0ddc332d5e0b700e38155c160.tar.gz
crosvm-d5f47a98657034b0ddc332d5e0b700e38155c160.tar.bz2
crosvm-d5f47a98657034b0ddc332d5e0b700e38155c160.tar.lz
crosvm-d5f47a98657034b0ddc332d5e0b700e38155c160.tar.xz
crosvm-d5f47a98657034b0ddc332d5e0b700e38155c160.tar.zst
crosvm-d5f47a98657034b0ddc332d5e0b700e38155c160.zip
acpi: add AML support
This is backported from cloud hypervisor, which can be used to
generate the AML from ASL which is more easily for people to
understand what this AML is doing.

BUG=None
TEST=cargo test -p acpi_tables

Change-Id: Ib7c60caca92fd6ca7ab6800ddf36b2135fbcfc88
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2119570
Reviewed-by: Zach Reizner <zachr@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Commit-Queue: Chuanxiao Dong <chuanxiao.dong@intel.corp-partner.google.com>
-rw-r--r--acpi_tables/src/aml.rs1966
-rw-r--r--acpi_tables/src/lib.rs1
2 files changed, 1967 insertions, 0 deletions
diff --git a/acpi_tables/src/aml.rs b/acpi_tables/src/aml.rs
new file mode 100644
index 0000000..7d16153
--- /dev/null
+++ b/acpi_tables/src/aml.rs
@@ -0,0 +1,1966 @@
+// Copyright 2020 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/// The trait Aml can be implemented by the ACPI objects to translate itself
+/// into the AML raw data. So that these AML raw data can be added into the
+/// ACPI DSDT for guest.
+pub trait Aml {
+    /// Translate an ACPI object into AML code and append to the vector
+    /// buffer.
+    /// * `bytes` - The vector used to append the AML code.
+    fn to_aml_bytes(&self, bytes: &mut Vec<u8>);
+}
+
+// AML byte stream defines
+const ZEROOP: u8 = 0x00;
+const ONEOP: u8 = 0x01;
+const NAMEOP: u8 = 0x08;
+const BYTEPREFIX: u8 = 0x0a;
+const WORDPREFIX: u8 = 0x0b;
+const DWORDPREFIX: u8 = 0x0c;
+const STRINGOP: u8 = 0x0d;
+const QWORDPREFIX: u8 = 0x0e;
+const SCOPEOP: u8 = 0x10;
+const BUFFEROP: u8 = 0x11;
+const PACKAGEOP: u8 = 0x12;
+const METHODOP: u8 = 0x14;
+const DUALNAMEPREFIX: u8 = 0x2e;
+const MULTINAMEPREFIX: u8 = 0x2f;
+const NAMECHARBASE: u8 = 0x40;
+
+const EXTOPPREFIX: u8 = 0x5b;
+const MUTEXOP: u8 = 0x01;
+const ACQUIREOP: u8 = 0x23;
+const RELEASEOP: u8 = 0x27;
+const OPREGIONOP: u8 = 0x80;
+const FIELDOP: u8 = 0x81;
+const DEVICEOP: u8 = 0x82;
+
+const LOCAL0OP: u8 = 0x60;
+const ARG0OP: u8 = 0x68;
+const STOREOP: u8 = 0x70;
+const ADDOP: u8 = 0x72;
+const CONCATOP: u8 = 0x73;
+const SUBTRACTOP: u8 = 0x74;
+const MULTIPLYOP: u8 = 0x77;
+const SHIFTLEFTOP: u8 = 0x79;
+const SHIFTRIGHTOP: u8 = 0x7a;
+const ANDOP: u8 = 0x7b;
+const NANDOP: u8 = 0x7c;
+const OROP: u8 = 0x7d;
+const NOROP: u8 = 0x7e;
+const XOROP: u8 = 0x7f;
+const CONCATRESOP: u8 = 0x84;
+const MODOP: u8 = 0x85;
+const NOTIFYOP: u8 = 0x86;
+const INDEXOP: u8 = 0x88;
+const LEQUALOP: u8 = 0x93;
+const LLESSOP: u8 = 0x95;
+const TOSTRINGOP: u8 = 0x9c;
+const IFOP: u8 = 0xa0;
+const WHILEOP: u8 = 0xa2;
+const RETURNOP: u8 = 0xa4;
+const ONESOP: u8 = 0xff;
+
+// AML resouce data fields
+const IOPORTDESC: u8 = 0x47;
+const ENDTAG: u8 = 0x79;
+const MEMORY32FIXEDDESC: u8 = 0x86;
+const DWORDADDRSPACEDESC: u8 = 0x87;
+const WORDADDRSPACEDESC: u8 = 0x88;
+const EXTIRQDESC: u8 = 0x89;
+const QWORDADDRSPACEDESC: u8 = 0x8A;
+
+/// Zero object in ASL.
+pub const ZERO: Zero = Zero {};
+pub struct Zero {}
+
+impl Aml for Zero {
+    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+        bytes.append(&mut vec![ZEROOP]);
+    }
+}
+
+/// One object in ASL.
+pub const ONE: One = One {};
+pub struct One {}
+
+impl Aml for One {
+    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+        bytes.append(&mut vec![ONEOP]);
+    }
+}
+
+/// Ones object represents all bits 1.
+pub const ONES: Ones = Ones {};
+pub struct Ones {}
+
+impl Aml for Ones {
+    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+        bytes.append(&mut vec![ONESOP]);
+    }
+}
+
+/// Represents Namestring to construct ACPI objects like
+/// Name/Device/Method/Scope and so on...
+pub struct Path {
+    root: bool,
+    name_parts: Vec<[u8; 4]>,
+}
+
+impl Aml for Path {
+    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+        if self.root {
+            bytes.push(b'\\');
+        }
+
+        match self.name_parts.len() {
+            0 => panic!("Name cannot be empty"),
+            1 => {}
+            2 => {
+                bytes.push(DUALNAMEPREFIX);
+            }
+            n => {
+                bytes.push(MULTINAMEPREFIX);
+                bytes.push(n as u8);
+            }
+        };
+
+        for part in self.name_parts.clone().iter_mut() {
+            bytes.append(&mut part.to_vec());
+        }
+    }
+}
+
+impl Path {
+    /// Per ACPI Spec, the Namestring split by "." has 4 bytes long. So any name
+    /// not has 4 bytes will not be accepted.
+    pub fn new(name: &str) -> Self {
+        let root = name.starts_with('\\');
+        let offset = root as usize;
+        let mut name_parts = Vec::new();
+        for part in name[offset..].split('.') {
+            assert_eq!(part.len(), 4);
+            let mut name_part = [0u8; 4];
+            name_part.copy_from_slice(part.as_bytes());
+            name_parts.push(name_part);
+        }
+
+        Path { root, name_parts }
+    }
+}
+
+impl From<&str> for Path {
+    fn from(s: &str) -> Self {
+        Path::new(s)
+    }
+}
+
+pub type Byte = u8;
+
+impl Aml for Byte {
+    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+        bytes.push(BYTEPREFIX);
+        bytes.push(*self);
+    }
+}
+
+pub type Word = u16;
+
+impl Aml for Word {
+    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+        bytes.push(WORDPREFIX);
+        bytes.append(&mut self.to_le_bytes().to_vec());
+    }
+}
+
+pub type DWord = u32;
+
+impl Aml for DWord {
+    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+        bytes.push(DWORDPREFIX);
+        bytes.append(&mut self.to_le_bytes().to_vec());
+    }
+}
+
+pub type QWord = u64;
+
+impl Aml for QWord {
+    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+        bytes.push(QWORDPREFIX);
+        bytes.append(&mut self.to_le_bytes().to_vec());
+    }
+}
+
+/// Name object. bytes represents the raw AML data for it.
+pub struct Name {
+    bytes: Vec<u8>,
+}
+
+impl Aml for Name {
+    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+        bytes.append(&mut self.bytes.clone());
+    }
+}
+
+impl Name {
+    /// Create Name object:
+    ///
+    /// * `path` - The namestring.
+    /// * `inner` - AML objects contained in this namespace.
+    pub fn new(path: Path, inner: &dyn Aml) -> Self {
+        let mut bytes = Vec::new();
+        bytes.push(NAMEOP);
+        path.to_aml_bytes(&mut bytes);
+        inner.to_aml_bytes(&mut bytes);
+        Name { bytes }
+    }
+}
+
+/// Package object. 'children' represents the ACPI objects contained in this package.
+pub struct Package<'a> {
+    children: Vec<&'a dyn Aml>,
+}
+
+impl<'a> Aml for Package<'a> {
+    fn to_aml_bytes(&self, aml: &mut Vec<u8>) {
+        let mut bytes = Vec::new();
+        bytes.push(self.children.len() as u8);
+        for child in &self.children {
+            child.to_aml_bytes(&mut bytes);
+        }
+
+        let mut pkg_length = create_pkg_length(&bytes, true);
+        pkg_length.reverse();
+        for byte in pkg_length {
+            bytes.insert(0, byte);
+        }
+
+        bytes.insert(0, PACKAGEOP);
+
+        aml.append(&mut bytes);
+    }
+}
+
+impl<'a> Package<'a> {
+    /// Create Package object:
+    pub fn new(children: Vec<&'a dyn Aml>) -> Self {
+        Package { children }
+    }
+}
+
+/*
+
+From the ACPI spec for PkgLength:
+
+"The high 2 bits of the first byte reveal how many follow bytes are in the PkgLength. If the
+PkgLength has only one byte, bit 0 through 5 are used to encode the package length (in other
+words, values 0-63). If the package length value is more than 63, more than one byte must be
+used for the encoding in which case bit 4 and 5 of the PkgLeadByte are reserved and must be zero.
+If the multiple bytes encoding is used, bits 0-3 of the PkgLeadByte become the least significant 4
+bits of the resulting package length value. The next ByteData will become the next least
+significant 8 bits of the resulting value and so on, up to 3 ByteData bytes. Thus, the maximum
+package length is 2**28."
+
+*/
+
+/* Also used for NamedField but in that case the length is not included in itself */
+fn create_pkg_length(data: &[u8], include_self: bool) -> Vec<u8> {
+    let mut result = Vec::new();
+
+    /* PkgLength is inclusive and includes the length bytes */
+    let length_length = if data.len() < (2usize.pow(6) - 1) {
+        1
+    } else if data.len() < (2usize.pow(12) - 2) {
+        2
+    } else if data.len() < (2usize.pow(20) - 3) {
+        3
+    } else {
+        4
+    };
+
+    let length = data.len() + if include_self { length_length } else { 0 };
+
+    match length_length {
+        1 => result.push(length as u8),
+        2 => {
+            result.push((1u8 << 6) | (length & 0xf) as u8);
+            result.push((length >> 4) as u8)
+        }
+        3 => {
+            result.push((2u8 << 6) | (length & 0xf) as u8);
+            result.push((length >> 4) as u8);
+            result.push((length >> 12) as u8);
+        }
+        _ => {
+            result.push((3u8 << 6) | (length & 0xf) as u8);
+            result.push((length >> 4) as u8);
+            result.push((length >> 12) as u8);
+            result.push((length >> 20) as u8);
+        }
+    }
+
+    result
+}
+
+/// EISAName object. 'value' means the encoded u32 EisaIdString.
+pub struct EISAName {
+    value: DWord,
+}
+
+impl EISAName {
+    /// Per ACPI Spec, the EisaIdString must be a String
+    /// object of the form UUUNNNN, where U is an uppercase letter
+    /// and N is a hexadecimal digit. No asterisks or other characters
+    /// are allowed in the string.
+    pub fn new(name: &str) -> Self {
+        assert_eq!(name.len(), 7);
+
+        let data = name.as_bytes();
+
+        let value: u32 = (u32::from(data[0].checked_sub(NAMECHARBASE).unwrap()) << 26
+            | u32::from(data[1].checked_sub(NAMECHARBASE).unwrap()) << 21
+            | u32::from(data[2].checked_sub(NAMECHARBASE).unwrap()) << 16
+            | name.chars().nth(3).unwrap().to_digit(16).unwrap() << 12
+            | name.chars().nth(4).unwrap().to_digit(16).unwrap() << 8
+            | name.chars().nth(5).unwrap().to_digit(16).unwrap() << 4
+            | name.chars().nth(6).unwrap().to_digit(16).unwrap())
+        .swap_bytes();
+
+        EISAName { value }
+    }
+}
+
+impl Aml for EISAName {
+    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+        self.value.to_aml_bytes(bytes);
+    }
+}
+
+fn create_integer(v: usize, bytes: &mut Vec<u8>) {
+    if v <= u8::max_value().into() {
+        (v as u8).to_aml_bytes(bytes);
+    } else if v <= u16::max_value().into() {
+        (v as u16).to_aml_bytes(bytes);
+    } else if v <= u32::max_value() as usize {
+        (v as u32).to_aml_bytes(bytes);
+    } else {
+        (v as u64).to_aml_bytes(bytes);
+    }
+}
+
+pub type Usize = usize;
+
+impl Aml for Usize {
+    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+        create_integer(*self, bytes);
+    }
+}
+
+fn create_aml_string(v: &str) -> Vec<u8> {
+    let mut data = Vec::new();
+    data.push(STRINGOP);
+    data.extend_from_slice(v.as_bytes());
+    data.push(0x0); /* NullChar */
+    data
+}
+
+/// implement Aml trait for 'str' so that 'str' can be directly append to the aml vector
+pub type AmlStr = &'static str;
+
+impl Aml for AmlStr {
+    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+        bytes.append(&mut create_aml_string(self));
+    }
+}
+
+/// implement Aml trait for 'String'. So purpose with str.
+pub type AmlString = String;
+
+impl Aml for AmlString {
+    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+        bytes.append(&mut create_aml_string(self));
+    }
+}
+
+/// ResouceTemplate object. 'children' represents the ACPI objects in it.
+pub struct ResourceTemplate<'a> {
+    children: Vec<&'a dyn Aml>,
+}
+
+impl<'a> Aml for ResourceTemplate<'a> {
+    fn to_aml_bytes(&self, aml: &mut Vec<u8>) {
+        let mut bytes = Vec::new();
+
+        // Add buffer data
+        for child in &self.children {
+            child.to_aml_bytes(&mut bytes);
+        }
+
+        // Mark with end and mark checksum as as always valid
+        bytes.push(ENDTAG);
+        bytes.push(0); /* zero checksum byte */
+
+        // Buffer length is an encoded integer including buffer data
+        // and EndTag and checksum byte
+        let mut buffer_length = Vec::new();
+        bytes.len().to_aml_bytes(&mut buffer_length);
+        buffer_length.reverse();
+        for byte in buffer_length {
+            bytes.insert(0, byte);
+        }
+
+        // PkgLength is everything else
+        let mut pkg_length = create_pkg_length(&bytes, true);
+        pkg_length.reverse();
+        for byte in pkg_length {
+            bytes.insert(0, byte);
+        }
+
+        bytes.insert(0, BUFFEROP);
+
+        aml.append(&mut bytes);
+    }
+}
+
+impl<'a> ResourceTemplate<'a> {
+    /// Create ResouceTemplate object
+    pub fn new(children: Vec<&'a dyn Aml>) -> Self {
+        ResourceTemplate { children }
+    }
+}
+
+/// Memory32Fixed object with read_write accessing type, and the base address/length.
+pub struct Memory32Fixed {
+    read_write: bool, /* true for read & write, false for read only */
+    base: u32,
+    length: u32,
+}
+
+impl Memory32Fixed {
+    /// Create Memory32Fixed object.
+    pub fn new(read_write: bool, base: u32, length: u32) -> Self {
+        Memory32Fixed {
+            read_write,
+            base,
+            length,
+        }
+    }
+}
+
+impl Aml for Memory32Fixed {
+    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+        bytes.push(MEMORY32FIXEDDESC); /* 32bit Fixed Memory Range Descriptor */
+        bytes.append(&mut 9u16.to_le_bytes().to_vec());
+
+        // 9 bytes of payload
+        bytes.push(self.read_write as u8);
+        bytes.append(&mut self.base.to_le_bytes().to_vec());
+        bytes.append(&mut self.length.to_le_bytes().to_vec());
+    }
+}
+
+#[derive(Copy, Clone)]
+enum AddressSpaceType {
+    Memory,
+    IO,
+    BusNumber,
+}
+
+/// AddressSpaceCachable represent cache types for AddressSpace object
+#[derive(Copy, Clone)]
+pub enum AddressSpaceCachable {
+    NotCacheable,
+    Cacheable,
+    WriteCombining,
+    PreFetchable,
+}
+
+/// AddressSpace structure with type, resouce range and flags to
+/// construct Memory/IO/BusNumber objects
+pub struct AddressSpace<T> {
+    type_: AddressSpaceType,
+    min: T,
+    max: T,
+    type_flags: u8,
+}
+
+impl<T> AddressSpace<T> {
+    /// Create DWordMemory/QWordMemory object
+    pub fn new_memory(cacheable: AddressSpaceCachable, read_write: bool, min: T, max: T) -> Self {
+        AddressSpace {
+            type_: AddressSpaceType::Memory,
+            min,
+            max,
+            type_flags: (cacheable as u8) << 1 | read_write as u8,
+        }
+    }
+
+    /// Create WordIO/DWordIO/QWordIO object
+    pub fn new_io(min: T, max: T) -> Self {
+        AddressSpace {
+            type_: AddressSpaceType::IO,
+            min,
+            max,
+            type_flags: 3, /* EntireRange */
+        }
+    }
+
+    /// Create WordBusNumber object
+    pub fn new_bus_number(min: T, max: T) -> Self {
+        AddressSpace {
+            type_: AddressSpaceType::BusNumber,
+            min,
+            max,
+            type_flags: 0,
+        }
+    }
+
+    fn push_header(&self, bytes: &mut Vec<u8>, descriptor: u8, length: usize) {
+        bytes.push(descriptor); /* Word Address Space Descriptor */
+        bytes.append(&mut (length as u16).to_le_bytes().to_vec());
+        bytes.push(self.type_ as u8); /* type */
+        let generic_flags = 1 << 2 /* Min Fixed */ | 1 << 3; /* Max Fixed */
+        bytes.push(generic_flags);
+        bytes.push(self.type_flags);
+    }
+}
+
+impl Aml for AddressSpace<u16> {
+    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+        self.push_header(
+            bytes,
+            WORDADDRSPACEDESC,                  /* Word Address Space Descriptor */
+            3 + 5 * std::mem::size_of::<u16>(), /* 3 bytes of header + 5 u16 fields */
+        );
+
+        bytes.append(&mut 0u16.to_le_bytes().to_vec()); /* Granularity */
+        bytes.append(&mut self.min.to_le_bytes().to_vec()); /* Min */
+        bytes.append(&mut self.max.to_le_bytes().to_vec()); /* Max */
+        bytes.append(&mut 0u16.to_le_bytes().to_vec()); /* Translation */
+        let len = self.max - self.min + 1;
+        bytes.append(&mut len.to_le_bytes().to_vec()); /* Length */
+    }
+}
+
+impl Aml for AddressSpace<u32> {
+    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+        self.push_header(
+            bytes,
+            DWORDADDRSPACEDESC, /* DWord Address Space Descriptor */
+            3 + 5 * std::mem::size_of::<u32>(), /* 3 bytes of header + 5 u32 fields */
+        );
+
+        bytes.append(&mut 0u32.to_le_bytes().to_vec()); /* Granularity */
+        bytes.append(&mut self.min.to_le_bytes().to_vec()); /* Min */
+        bytes.append(&mut self.max.to_le_bytes().to_vec()); /* Max */
+        bytes.append(&mut 0u32.to_le_bytes().to_vec()); /* Translation */
+        let len = self.max - self.min + 1;
+        bytes.append(&mut len.to_le_bytes().to_vec()); /* Length */
+    }
+}
+
+impl Aml for AddressSpace<u64> {
+    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+        self.push_header(
+            bytes,
+            QWORDADDRSPACEDESC, /* QWord Address Space Descriptor */
+            3 + 5 * std::mem::size_of::<u64>(), /* 3 bytes of header + 5 u64 fields */
+        );
+
+        bytes.append(&mut 0u64.to_le_bytes().to_vec()); /* Granularity */
+        bytes.append(&mut self.min.to_le_bytes().to_vec()); /* Min */
+        bytes.append(&mut self.max.to_le_bytes().to_vec()); /* Max */
+        bytes.append(&mut 0u64.to_le_bytes().to_vec()); /* Translation */
+        let len = self.max - self.min + 1;
+        bytes.append(&mut len.to_le_bytes().to_vec()); /* Length */
+    }
+}
+
+/// IO resouce object with the IO range, alignment and length
+pub struct IO {
+    min: u16,
+    max: u16,
+    alignment: u8,
+    length: u8,
+}
+
+impl IO {
+    /// Create IO object
+    pub fn new(min: u16, max: u16, alignment: u8, length: u8) -> Self {
+        IO {
+            min,
+            max,
+            alignment,
+            length,
+        }
+    }
+}
+
+impl Aml for IO {
+    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+        bytes.push(IOPORTDESC); /* IO Port Descriptor */
+        bytes.push(1); /* IODecode16 */
+        bytes.append(&mut self.min.to_le_bytes().to_vec());
+        bytes.append(&mut self.max.to_le_bytes().to_vec());
+        bytes.push(self.alignment);
+        bytes.push(self.length);
+    }
+}
+
+/// Interrupt resouce object with the interrupt characters.
+pub struct Interrupt {
+    consumer: bool,
+    edge_triggered: bool,
+    active_low: bool,
+    shared: bool,
+    number: u32,
+}
+
+impl Interrupt {
+    /// Create Interrupt object
+    pub fn new(
+        consumer: bool,
+        edge_triggered: bool,
+        active_low: bool,
+        shared: bool,
+        number: u32,
+    ) -> Self {
+        Interrupt {
+            consumer,
+            edge_triggered,
+            active_low,
+            shared,
+            number,
+        }
+    }
+}
+
+impl Aml for Interrupt {
+    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+        bytes.push(EXTIRQDESC); /* Extended IRQ Descriptor */
+        bytes.append(&mut 6u16.to_le_bytes().to_vec());
+        let flags = (self.shared as u8) << 3
+            | (self.active_low as u8) << 2
+            | (self.edge_triggered as u8) << 1
+            | self.consumer as u8;
+        bytes.push(flags);
+        bytes.push(1u8); /* count */
+        bytes.append(&mut self.number.to_le_bytes().to_vec());
+    }
+}
+
+/// Device object with its device name and children objects in it.
+pub struct Device<'a> {
+    path: Path,
+    children: Vec<&'a dyn Aml>,
+}
+
+impl<'a> Aml for Device<'a> {
+    fn to_aml_bytes(&self, aml: &mut Vec<u8>) {
+        let mut bytes = Vec::new();
+        self.path.to_aml_bytes(&mut bytes);
+        for child in &self.children {
+            child.to_aml_bytes(&mut bytes);
+        }
+
+        let mut pkg_length = create_pkg_length(&bytes, true);
+        pkg_length.reverse();
+        for byte in pkg_length {
+            bytes.insert(0, byte);
+        }
+
+        bytes.insert(0, DEVICEOP); /* DeviceOp */
+        bytes.insert(0, EXTOPPREFIX); /* ExtOpPrefix */
+        aml.append(&mut bytes)
+    }
+}
+
+impl<'a> Device<'a> {
+    /// Create Device object
+    pub fn new(path: Path, children: Vec<&'a dyn Aml>) -> Self {
+        Device { path, children }
+    }
+}
+
+/// Scope object with its name and children objects in it.
+pub struct Scope<'a> {
+    path: Path,
+    children: Vec<&'a dyn Aml>,
+}
+
+impl<'a> Aml for Scope<'a> {
+    fn to_aml_bytes(&self, aml: &mut Vec<u8>) {
+        let mut bytes = Vec::new();
+        self.path.to_aml_bytes(&mut bytes);
+        for child in &self.children {
+            child.to_aml_bytes(&mut bytes);
+        }
+
+        let mut pkg_length = create_pkg_length(&bytes, true);
+        pkg_length.reverse();
+        for byte in pkg_length {
+            bytes.insert(0, byte);
+        }
+
+        bytes.insert(0, SCOPEOP);
+        aml.append(&mut bytes)
+    }
+}
+
+impl<'a> Scope<'a> {
+    /// Create Scope object
+    pub fn new(path: Path, children: Vec<&'a dyn Aml>) -> Self {
+        Scope { path, children }
+    }
+}
+
+/// Method object with its name, children objects, arguments and serialized character.
+pub struct Method<'a> {
+    path: Path,
+    children: Vec<&'a dyn Aml>,
+    args: u8,
+    serialized: bool,
+}
+
+impl<'a> Method<'a> {
+    /// Create Method object.
+    pub fn new(path: Path, args: u8, serialized: bool, children: Vec<&'a dyn Aml>) -> Self {
+        Method {
+            path,
+            children,
+            args,
+            serialized,
+        }
+    }
+}
+
+impl<'a> Aml for Method<'a> {
+    fn to_aml_bytes(&self, aml: &mut Vec<u8>) {
+        let mut bytes = Vec::new();
+        self.path.to_aml_bytes(&mut bytes);
+        let flags: u8 = (self.args & 0x7) | (self.serialized as u8) << 3;
+        bytes.push(flags);
+        for child in &self.children {
+            child.to_aml_bytes(&mut bytes);
+        }
+
+        let mut pkg_length = create_pkg_length(&bytes, true);
+        pkg_length.reverse();
+        for byte in pkg_length {
+            bytes.insert(0, byte);
+        }
+
+        bytes.insert(0, METHODOP);
+        aml.append(&mut bytes)
+    }
+}
+
+/// Return object with its return value.
+pub struct Return<'a> {
+    value: &'a dyn Aml,
+}
+
+impl<'a> Return<'a> {
+    /// Create Return object
+    pub fn new(value: &'a dyn Aml) -> Self {
+        Return { value }
+    }
+}
+
+impl<'a> Aml for Return<'a> {
+    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+        bytes.push(RETURNOP);
+        self.value.to_aml_bytes(bytes);
+    }
+}
+
+/// FiledAccessType defines the filed accessing types.
+#[derive(Clone, Copy)]
+pub enum FieldAccessType {
+    Any,
+    Byte,
+    Word,
+    DWord,
+    QWord,
+    Buffer,
+}
+
+/// FiledUpdateRule defines the rules to update the filed.
+#[derive(Clone, Copy)]
+pub enum FieldUpdateRule {
+    Preserve = 0,
+    WriteAsOnes = 1,
+    WriteAsZeroes = 2,
+}
+
+/// FiledEntry defines the filed entry.
+pub enum FieldEntry {
+    Named([u8; 4], usize),
+    Reserved(usize),
+}
+
+/// Field object with the region name, filed entries, access type and update rules.
+pub struct Field {
+    path: Path,
+
+    fields: Vec<FieldEntry>,
+    access_type: FieldAccessType,
+    update_rule: FieldUpdateRule,
+}
+
+impl Field {
+    /// Create Field object
+    pub fn new(
+        path: Path,
+        access_type: FieldAccessType,
+        update_rule: FieldUpdateRule,
+        fields: Vec<FieldEntry>,
+    ) -> Self {
+        Field {
+            path,
+            access_type,
+            update_rule,
+            fields,
+        }
+    }
+}
+
+impl Aml for Field {
+    fn to_aml_bytes(&self, aml: &mut Vec<u8>) {
+        let mut bytes = Vec::new();
+        self.path.to_aml_bytes(&mut bytes);
+
+        let flags: u8 = self.access_type as u8 | (self.update_rule as u8) << 5;
+        bytes.push(flags);
+
+        for field in self.fields.iter() {
+            match field {
+                FieldEntry::Named(name, length) => {
+                    bytes.extend_from_slice(name);
+                    bytes.append(&mut create_pkg_length(&vec![0; *length], false));
+                }
+                FieldEntry::Reserved(length) => {
+                    bytes.push(0x0);
+                    bytes.append(&mut create_pkg_length(&vec![0; *length], false));
+                }
+            }
+        }
+
+        let mut pkg_length = create_pkg_length(&bytes, true);
+        pkg_length.reverse();
+        for byte in pkg_length {
+            bytes.insert(0, byte);
+        }
+
+        bytes.insert(0, FIELDOP);
+        bytes.insert(0, EXTOPPREFIX);
+        aml.append(&mut bytes)
+    }
+}
+
+/// The space type for OperationRegion object
+#[derive(Clone, Copy)]
+pub enum OpRegionSpace {
+    SystemMemory,
+    SystemIO,
+    PCIConfig,
+    EmbeddedControl,
+    SMBus,
+    SystemCMOS,
+    PciBarTarget,
+    IPMI,
+    GeneralPurposeIO,
+    GenericSerialBus,
+}
+
+/// OperationRegion object with region name, region space type, its offset and length.
+pub struct OpRegion {
+    path: Path,
+    space: OpRegionSpace,
+    offset: usize,
+    length: usize,
+}
+
+impl OpRegion {
+    /// Create OperationRegion object.
+    pub fn new(path: Path, space: OpRegionSpace, offset: usize, length: usize) -> Self {
+        OpRegion {
+            path,
+            space,
+            offset,
+            length,
+        }
+    }
+}
+
+impl Aml for OpRegion {
+    fn to_aml_bytes(&self, aml: &mut Vec<u8>) {
+        let mut bytes = Vec::new();
+        self.path.to_aml_bytes(&mut bytes);
+        bytes.push(self.space as u8);
+        self.offset.to_aml_bytes(&mut bytes); /* RegionOffset */
+        self.length.to_aml_bytes(&mut bytes); /* RegionLen */
+        bytes.insert(0, OPREGIONOP);
+        bytes.insert(0, EXTOPPREFIX);
+        aml.append(&mut bytes)
+    }
+}
+
+/// If object with the if condition(predicate) and the body presented by the if_children objects.
+pub struct If<'a> {
+    predicate: &'a dyn Aml,
+    if_children: Vec<&'a dyn Aml>,
+}
+
+impl<'a> If<'a> {
+    /// Create If object.
+    pub fn new(predicate: &'a dyn Aml, if_children: Vec<&'a dyn Aml>) -> Self {
+        If {
+            predicate,
+            if_children,
+        }
+    }
+}
+
+impl<'a> Aml for If<'a> {
+    fn to_aml_bytes(&self, aml: &mut Vec<u8>) {
+        let mut bytes = Vec::new();
+        self.predicate.to_aml_bytes(&mut bytes);
+        for child in self.if_children.iter() {
+            child.to_aml_bytes(&mut bytes);
+        }
+
+        let mut pkg_length = create_pkg_length(&bytes, true);
+        pkg_length.reverse();
+        for byte in pkg_length {
+            bytes.insert(0, byte);
+        }
+
+        bytes.insert(0, IFOP);
+        aml.append(&mut bytes)
+    }
+}
+
+/// Equal object with its right part and left part, which are both ACPI objects.
+pub struct Equal<'a> {
+    right: &'a dyn Aml,
+    left: &'a dyn Aml,
+}
+
+impl<'a> Equal<'a> {
+    /// Create Equal object.
+    pub fn new(left: &'a dyn Aml, right: &'a dyn Aml) -> Self {
+        Equal { left, right }
+    }
+}
+
+impl<'a> Aml for Equal<'a> {
+    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+        bytes.push(LEQUALOP);
+        self.left.to_aml_bytes(bytes);
+        self.right.to_aml_bytes(bytes);
+    }
+}
+
+/// LessThan object with its right part and left part, which are both ACPI objects.
+pub struct LessThan<'a> {
+    right: &'a dyn Aml,
+    left: &'a dyn Aml,
+}
+
+impl<'a> LessThan<'a> {
+    /// Create LessThan object.
+    pub fn new(left: &'a dyn Aml, right: &'a dyn Aml) -> Self {
+        LessThan { left, right }
+    }
+}
+
+impl<'a> Aml for LessThan<'a> {
+    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+        bytes.push(LLESSOP);
+        self.left.to_aml_bytes(bytes);
+        self.right.to_aml_bytes(bytes);
+    }
+}
+
+/// Argx object.
+pub struct Arg(pub u8);
+
+impl Aml for Arg {
+    /// Per ACPI spec, there is maximum 7 Argx objects from
+    /// Arg0 ~ Arg6. Any other Arg object will not be accepted.
+    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+        assert!(self.0 <= 6);
+        bytes.push(ARG0OP + self.0);
+    }
+}
+
+/// Localx object.
+pub struct Local(pub u8);
+
+impl Aml for Local {
+    /// Per ACPI spec, there is maximum 8 Localx objects from
+    /// Local0 ~ Local7. Any other Local object will not be accepted.
+    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+        assert!(self.0 <= 7);
+        bytes.push(LOCAL0OP + self.0);
+    }
+}
+
+/// Store object with the ACPI object name which can be stored to and
+/// the ACPI object value which is to store.
+pub struct Store<'a> {
+    name: &'a dyn Aml,
+    value: &'a dyn Aml,
+}
+
+impl<'a> Store<'a> {
+    /// Create Store object.
+    pub fn new(name: &'a dyn Aml, value: &'a dyn Aml) -> Self {
+        Store { name, value }
+    }
+}
+
+impl<'a> Aml for Store<'a> {
+    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+        bytes.push(STOREOP);
+        self.value.to_aml_bytes(bytes);
+        self.name.to_aml_bytes(bytes);
+    }
+}
+
+/// Mutex object with a mutex name and a synchronization level.
+pub struct Mutex {
+    path: Path,
+    sync_level: u8,
+}
+
+impl Mutex {
+    /// Create Mutex object.
+    pub fn new(path: Path, sync_level: u8) -> Self {
+        Self { path, sync_level }
+    }
+}
+
+impl Aml for Mutex {
+    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+        bytes.push(EXTOPPREFIX);
+        bytes.push(MUTEXOP);
+        self.path.to_aml_bytes(bytes);
+        bytes.push(self.sync_level);
+    }
+}
+
+/// Acquire object with a Mutex object and timeout value.
+pub struct Acquire {
+    mutex: Path,
+    timeout: u16,
+}
+
+impl Acquire {
+    /// Create Acquire object.
+    pub fn new(mutex: Path, timeout: u16) -> Self {
+        Acquire { mutex, timeout }
+    }
+}
+
+impl Aml for Acquire {
+    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+        bytes.push(EXTOPPREFIX);
+        bytes.push(ACQUIREOP);
+        self.mutex.to_aml_bytes(bytes);
+        bytes.extend_from_slice(&self.timeout.to_le_bytes());
+    }
+}
+
+/// Release object with a Mutex object to release.
+pub struct Release {
+    mutex: Path,
+}
+
+impl Release {
+    /// Create Release object.
+    pub fn new(mutex: Path) -> Self {
+        Release { mutex }
+    }
+}
+
+impl Aml for Release {
+    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+        bytes.push(EXTOPPREFIX);
+        bytes.push(RELEASEOP);
+        self.mutex.to_aml_bytes(bytes);
+    }
+}
+
+/// Notify object with an object which is to be notified with the value.
+pub struct Notify<'a> {
+    object: &'a dyn Aml,
+    value: &'a dyn Aml,
+}
+
+impl<'a> Notify<'a> {
+    /// Create Notify object.
+    pub fn new(object: &'a dyn Aml, value: &'a dyn Aml) -> Self {
+        Notify { object, value }
+    }
+}
+
+impl<'a> Aml for Notify<'a> {
+    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+        bytes.push(NOTIFYOP);
+        self.object.to_aml_bytes(bytes);
+        self.value.to_aml_bytes(bytes);
+    }
+}
+
+/// While object with the while condition objects(predicate) and
+/// the while body objects(while_children).
+pub struct While<'a> {
+    predicate: &'a dyn Aml,
+    while_children: Vec<&'a dyn Aml>,
+}
+
+impl<'a> While<'a> {
+    /// Create While object.
+    pub fn new(predicate: &'a dyn Aml, while_children: Vec<&'a dyn Aml>) -> Self {
+        While {
+            predicate,
+            while_children,
+        }
+    }
+}
+
+impl<'a> Aml for While<'a> {
+    fn to_aml_bytes(&self, aml: &mut Vec<u8>) {
+        let mut bytes = Vec::new();
+        self.predicate.to_aml_bytes(&mut bytes);
+        for child in self.while_children.iter() {
+            child.to_aml_bytes(&mut bytes);
+        }
+
+        let mut pkg_length = create_pkg_length(&bytes, true);
+        pkg_length.reverse();
+        for byte in pkg_length {
+            bytes.insert(0, byte);
+        }
+
+        bytes.insert(0, WHILEOP);
+        aml.append(&mut bytes)
+    }
+}
+
+macro_rules! binary_op {
+    ($name:ident, $opcode:expr) => {
+        /// General operation object with the operator a/b and a target.
+        pub struct $name<'a> {
+            a: &'a dyn Aml,
+            b: &'a dyn Aml,
+            target: &'a dyn Aml,
+        }
+
+        impl<'a> $name<'a> {
+            /// Create the object.
+            pub fn new(target: &'a dyn Aml, a: &'a dyn Aml, b: &'a dyn Aml) -> Self {
+                $name { target, a, b }
+            }
+        }
+
+        impl<'a> Aml for $name<'a> {
+            fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+                bytes.push($opcode); /* Op for the binary operator */
+                self.a.to_aml_bytes(bytes);
+                self.b.to_aml_bytes(bytes);
+                self.target.to_aml_bytes(bytes);
+            }
+        }
+    };
+}
+
+binary_op!(Add, ADDOP);
+binary_op!(Concat, CONCATOP);
+binary_op!(Subtract, SUBTRACTOP);
+binary_op!(Multiply, MULTIPLYOP);
+binary_op!(ShiftLeft, SHIFTLEFTOP);
+binary_op!(ShiftRight, SHIFTRIGHTOP);
+binary_op!(And, ANDOP);
+binary_op!(Nand, NANDOP);
+binary_op!(Or, OROP);
+binary_op!(Nor, NOROP);
+binary_op!(Xor, XOROP);
+binary_op!(ConcatRes, CONCATRESOP);
+binary_op!(Mod, MODOP);
+binary_op!(Index, INDEXOP);
+binary_op!(ToString, TOSTRINGOP);
+
+/// MethodCall object with the method name and parameter objects.
+pub struct MethodCall<'a> {
+    name: Path,
+    args: Vec<&'a dyn Aml>,
+}
+
+impl<'a> MethodCall<'a> {
+    /// Create MethodCall object.
+    pub fn new(name: Path, args: Vec<&'a dyn Aml>) -> Self {
+        MethodCall { name, args }
+    }
+}
+
+impl<'a> Aml for MethodCall<'a> {
+    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+        self.name.to_aml_bytes(bytes);
+        for arg in self.args.iter() {
+            arg.to_aml_bytes(bytes);
+        }
+    }
+}
+
+/// Buffer object with the data in it.
+pub struct Buffer {
+    data: Vec<u8>,
+}
+
+impl Buffer {
+    /// Create Buffer object.
+    pub fn new(data: Vec<u8>) -> Self {
+        Buffer { data }
+    }
+}
+
+impl Aml for Buffer {
+    fn to_aml_bytes(&self, aml: &mut Vec<u8>) {
+        let mut bytes = Vec::new();
+        self.data.len().to_aml_bytes(&mut bytes);
+        bytes.extend_from_slice(&self.data);
+
+        let mut pkg_length = create_pkg_length(&bytes, true);
+        pkg_length.reverse();
+        for byte in pkg_length {
+            bytes.insert(0, byte);
+        }
+
+        bytes.insert(0, BUFFEROP);
+
+        aml.append(&mut bytes)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_device() {
+        /*
+        Device (_SB.COM1)
+        {
+            Name (_HID, EisaId ("PNP0501") /* 16550A-compatible COM Serial Port */) // _HID: Hardware ID
+            Name (_CRS, ResourceTemplate ()  // _CRS: Current Resource Settings
+            {
+                Interrupt (ResourceConsumer, Edge, ActiveHigh, Exclusive, ,, )
+                {
+                    0x00000004,
+                }
+                IO (Decode16,
+                    0x03F8,             // Range Minimum
+                    0x03F8,             // Range Maximum
+                    0x00,               // Alignment
+                    0x08,               // Length
+                    )
+            }
+        }
+            */
+        let com1_device = [
+            0x5B, 0x82, 0x30, 0x2E, 0x5F, 0x53, 0x42, 0x5F, 0x43, 0x4F, 0x4D, 0x31, 0x08, 0x5F,
+            0x48, 0x49, 0x44, 0x0C, 0x41, 0xD0, 0x05, 0x01, 0x08, 0x5F, 0x43, 0x52, 0x53, 0x11,
+            0x16, 0x0A, 0x13, 0x89, 0x06, 0x00, 0x03, 0x01, 0x04, 0x00, 0x00, 0x00, 0x47, 0x01,
+            0xF8, 0x03, 0xF8, 0x03, 0x00, 0x08, 0x79, 0x00,
+        ];
+        let mut aml = Vec::new();
+
+        Device::new(
+            "_SB_.COM1".into(),
+            vec![
+                &Name::new("_HID".into(), &EISAName::new("PNP0501")),
+                &Name::new(
+                    "_CRS".into(),
+                    &ResourceTemplate::new(vec![
+                        &Interrupt::new(true, true, false, false, 4),
+                        &IO::new(0x3f8, 0x3f8, 0, 0x8),
+                    ]),
+                ),
+            ],
+        )
+        .to_aml_bytes(&mut aml);
+        assert_eq!(aml, &com1_device[..]);
+    }
+
+    #[test]
+    fn test_scope() {
+        /*
+        Scope (_SB.MBRD)
+        {
+            Name (_CRS, ResourceTemplate ()  // _CRS: Current Resource Settings
+            {
+                Memory32Fixed (ReadWrite,
+                    0xE8000000,         // Address Base
+                    0x10000000,         // Address Length
+                    )
+            })
+        }
+        */
+
+        let mbrd_scope = [
+            0x10, 0x21, 0x2E, 0x5F, 0x53, 0x42, 0x5F, 0x4D, 0x42, 0x52, 0x44, 0x08, 0x5F, 0x43,
+            0x52, 0x53, 0x11, 0x11, 0x0A, 0x0E, 0x86, 0x09, 0x00, 0x01, 0x00, 0x00, 0x00, 0xE8,
+            0x00, 0x00, 0x00, 0x10, 0x79, 0x00,
+        ];
+        let mut aml = Vec::new();
+
+        Scope::new(
+            "_SB_.MBRD".into(),
+            vec![&Name::new(
+                "_CRS".into(),
+                &ResourceTemplate::new(vec![&Memory32Fixed::new(true, 0xE800_0000, 0x1000_0000)]),
+            )],
+        )
+        .to_aml_bytes(&mut aml);
+        assert_eq!(aml, &mbrd_scope[..]);
+    }
+
+    #[test]
+    fn test_resource_template() {
+        /*
+        Name (_CRS, ResourceTemplate ()  // _CRS: Current Resource Settings
+        {
+            Memory32Fixed (ReadWrite,
+                0xE8000000,         // Address Base
+                0x10000000,         // Address Length
+                )
+        })
+        */
+        let crs_memory_32_fixed = [
+            0x08, 0x5F, 0x43, 0x52, 0x53, 0x11, 0x11, 0x0A, 0x0E, 0x86, 0x09, 0x00, 0x01, 0x00,
+            0x00, 0x00, 0xE8, 0x00, 0x00, 0x00, 0x10, 0x79, 0x00,
+        ];
+        let mut aml = Vec::new();
+
+        Name::new(
+            "_CRS".into(),
+            &ResourceTemplate::new(vec![&Memory32Fixed::new(true, 0xE800_0000, 0x1000_0000)]),
+        )
+        .to_aml_bytes(&mut aml);
+        assert_eq!(aml, crs_memory_32_fixed);
+
+        /*
+            Name (_CRS, ResourceTemplate ()  // _CRS: Current Resource Settings
+            {
+                WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode,
+                    0x0000,             // Granularity
+                    0x0000,             // Range Minimum
+                    0x00FF,             // Range Maximum
+                    0x0000,             // Translation Offset
+                    0x0100,             // Length
+                    ,, )
+                WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
+                    0x0000,             // Granularity
+                    0x0000,             // Range Minimum
+                    0x0CF7,             // Range Maximum
+                    0x0000,             // Translation Offset
+                    0x0CF8,             // Length
+                    ,, , TypeStatic, DenseTranslation)
+                WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
+                    0x0000,             // Granularity
+                    0x0D00,             // Range Minimum
+                    0xFFFF,             // Range Maximum
+                    0x0000,             // Translation Offset
+                    0xF300,             // Length
+                    ,, , TypeStatic, DenseTranslation)
+                DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
+                    0x00000000,         // Granularity
+                    0x000A0000,         // Range Minimum
+                    0x000BFFFF,         // Range Maximum
+                    0x00000000,         // Translation Offset
+                    0x00020000,         // Length
+                    ,, , AddressRangeMemory, TypeStatic)
+                DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite,
+                    0x00000000,         // Granularity
+                    0xC0000000,         // Range Minimum
+                    0xFEBFFFFF,         // Range Maximum
+                    0x00000000,         // Translation Offset
+                    0x3EC00000,         // Length
+                    ,, , AddressRangeMemory, TypeStatic)
+                QWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
+                    0x0000000000000000, // Granularity
+                    0x0000000800000000, // Range Minimum
+                    0x0000000FFFFFFFFF, // Range Maximum
+                    0x0000000000000000, // Translation Offset
+                    0x0000000800000000, // Length
+                    ,, , AddressRangeMemory, TypeStatic)
+            })
+        */
+
+        // WordBusNumber from above
+        let crs_word_bus_number = [
+            0x08, 0x5F, 0x43, 0x52, 0x53, 0x11, 0x15, 0x0A, 0x12, 0x88, 0x0D, 0x00, 0x02, 0x0C,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x79, 0x00,
+        ];
+        aml.clear();
+
+        Name::new(
+            "_CRS".into(),
+            &ResourceTemplate::new(vec![&AddressSpace::new_bus_number(0x0u16, 0xffu16)]),
+        )
+        .to_aml_bytes(&mut aml);
+        assert_eq!(aml, &crs_word_bus_number);
+
+        // WordIO blocks (x 2) from above
+        let crs_word_io = [
+            0x08, 0x5F, 0x43, 0x52, 0x53, 0x11, 0x25, 0x0A, 0x22, 0x88, 0x0D, 0x00, 0x01, 0x0C,
+            0x03, 0x00, 0x00, 0x00, 0x00, 0xF7, 0x0C, 0x00, 0x00, 0xF8, 0x0C, 0x88, 0x0D, 0x00,
+            0x01, 0x0C, 0x03, 0x00, 0x00, 0x00, 0x0D, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xF3, 0x79,
+            0x00,
+        ];
+        aml.clear();
+
+        Name::new(
+            "_CRS".into(),
+            &ResourceTemplate::new(vec![
+                &AddressSpace::new_io(0x0u16, 0xcf7u16),
+                &AddressSpace::new_io(0xd00u16, 0xffffu16),
+            ]),
+        )
+        .to_aml_bytes(&mut aml);
+        assert_eq!(aml, &crs_word_io[..]);
+
+        // DWordMemory blocks (x 2) from above
+        let crs_dword_memory = [
+            0x08, 0x5F, 0x43, 0x52, 0x53, 0x11, 0x39, 0x0A, 0x36, 0x87, 0x17, 0x00, 0x00, 0x0C,
+            0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0xFF, 0xFF, 0x0B, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x87, 0x17, 0x00, 0x00, 0x0C, 0x01, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xBF, 0xFE, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0xC0, 0x3E, 0x79, 0x00,
+        ];
+        aml.clear();
+
+        Name::new(
+            "_CRS".into(),
+            &ResourceTemplate::new(vec![
+                &AddressSpace::new_memory(
+                    AddressSpaceCachable::Cacheable,
+                    true,
+                    0xa_0000u32,
+                    0xb_ffffu32,
+                ),
+                &AddressSpace::new_memory(
+                    AddressSpaceCachable::NotCacheable,
+                    true,
+                    0xc000_0000u32,
+                    0xfebf_ffffu32,
+                ),
+            ]),
+        )
+        .to_aml_bytes(&mut aml);
+        assert_eq!(aml, &crs_dword_memory[..]);
+
+        // QWordMemory from above
+        let crs_qword_memory = [
+            0x08, 0x5F, 0x43, 0x52, 0x53, 0x11, 0x33, 0x0A, 0x30, 0x8A, 0x2B, 0x00, 0x00, 0x0C,
+            0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+            0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x79,
+            0x00,
+        ];
+        aml.clear();
+        Name::new(
+            "_CRS".into(),
+            &ResourceTemplate::new(vec![&AddressSpace::new_memory(
+                AddressSpaceCachable::Cacheable,
+                true,
+                0x8_0000_0000u64,
+                0xf_ffff_ffffu64,
+            )]),
+        )
+        .to_aml_bytes(&mut aml);
+
+        assert_eq!(aml, &crs_qword_memory[..]);
+
+        /*
+            Name (_CRS, ResourceTemplate ()  // _CRS: Current Resource Settings
+            {
+                Interrupt (ResourceConsumer, Edge, ActiveHigh, Exclusive, ,, )
+                {
+                    0x00000004,
+                }
+                IO (Decode16,
+                    0x03F8,             // Range Minimum
+                    0x03F8,             // Range Maximum
+                    0x00,               // Alignment
+                    0x08,               // Length
+                    )
+            })
+
+        */
+        let interrupt_io_data = [
+            0x08, 0x5F, 0x43, 0x52, 0x53, 0x11, 0x16, 0x0A, 0x13, 0x89, 0x06, 0x00, 0x03, 0x01,
+            0x04, 0x00, 0x00, 0x00, 0x47, 0x01, 0xF8, 0x03, 0xF8, 0x03, 0x00, 0x08, 0x79, 0x00,
+        ];
+        aml.clear();
+        Name::new(
+            "_CRS".into(),
+            &ResourceTemplate::new(vec![
+                &Interrupt::new(true, true, false, false, 4),
+                &IO::new(0x3f8, 0x3f8, 0, 0x8),
+            ]),
+        )
+        .to_aml_bytes(&mut aml);
+
+        assert_eq!(aml, &interrupt_io_data[..]);
+    }
+
+    #[test]
+    fn test_pkg_length() {
+        assert_eq!(create_pkg_length(&[0u8; 62].to_vec(), true), vec![63]);
+        assert_eq!(
+            create_pkg_length(&[0u8; 64].to_vec(), true),
+            vec![1 << 6 | (66 & 0xf), 66 >> 4]
+        );
+        assert_eq!(
+            create_pkg_length(&[0u8; 4096].to_vec(), true),
+            vec![
+                2 << 6 | (4099 & 0xf) as u8,
+                (4099 >> 4) as u8,
+                (4099 >> 12) as u8
+            ]
+        );
+    }
+
+    #[test]
+    fn test_package() {
+        /*
+        Name (_S5, Package (0x01)  // _S5_: S5 System State
+        {
+            0x05
+        })
+        */
+        let s5_sleep_data = [0x08, 0x5F, 0x53, 0x35, 0x5F, 0x12, 0x04, 0x01, 0x0A, 0x05];
+        let mut aml = Vec::new();
+
+        Name::new("_S5_".into(), &Package::new(vec![&5u8])).to_aml_bytes(&mut aml);
+
+        assert_eq!(s5_sleep_data.to_vec(), aml);
+    }
+
+    #[test]
+    fn test_eisa_name() {
+        let mut aml = Vec::new();
+        Name::new("_HID".into(), &EISAName::new("PNP0501")).to_aml_bytes(&mut aml);
+        assert_eq!(
+            aml,
+            [0x08, 0x5F, 0x48, 0x49, 0x44, 0x0C, 0x41, 0xD0, 0x05, 0x01],
+        )
+    }
+    #[test]
+    fn test_name_path() {
+        let mut aml = Vec::new();
+        (&"_SB_".into() as &Path).to_aml_bytes(&mut aml);
+        assert_eq!(aml, [0x5Fu8, 0x53, 0x42, 0x5F]);
+        aml.clear();
+        (&"\\_SB_".into() as &Path).to_aml_bytes(&mut aml);
+        assert_eq!(aml, [0x5C, 0x5F, 0x53, 0x42, 0x5F]);
+        aml.clear();
+        (&"_SB_.COM1".into() as &Path).to_aml_bytes(&mut aml);
+        assert_eq!(aml, [0x2E, 0x5F, 0x53, 0x42, 0x5F, 0x43, 0x4F, 0x4D, 0x31]);
+        aml.clear();
+        (&"_SB_.PCI0._HID".into() as &Path).to_aml_bytes(&mut aml);
+        assert_eq!(
+            aml,
+            [0x2F, 0x03, 0x5F, 0x53, 0x42, 0x5F, 0x50, 0x43, 0x49, 0x30, 0x5F, 0x48, 0x49, 0x44]
+        );
+    }
+
+    #[test]
+    fn test_numbers() {
+        let mut aml = Vec::new();
+        128u8.to_aml_bytes(&mut aml);
+        assert_eq!(aml, [0x0a, 0x80]);
+        aml.clear();
+        1024u16.to_aml_bytes(&mut aml);
+        assert_eq!(aml, [0x0b, 0x0, 0x04]);
+        aml.clear();
+        (16u32 << 20).to_aml_bytes(&mut aml);
+        assert_eq!(aml, [0x0c, 0x00, 0x00, 0x0, 0x01]);
+        aml.clear();
+        0xdeca_fbad_deca_fbadu64.to_aml_bytes(&mut aml);
+        assert_eq!(aml, [0x0e, 0xad, 0xfb, 0xca, 0xde, 0xad, 0xfb, 0xca, 0xde]);
+    }
+
+    #[test]
+    fn test_name() {
+        let mut aml = Vec::new();
+        Name::new("_SB_.PCI0._UID".into(), &0x1234u16).to_aml_bytes(&mut aml);
+        assert_eq!(
+            aml,
+            [
+                0x08, /* NameOp */
+                0x2F, /* MultiNamePrefix */
+                0x03, /* 3 name parts */
+                0x5F, 0x53, 0x42, 0x5F, /* _SB_ */
+                0x50, 0x43, 0x49, 0x30, /* PCI0 */
+                0x5F, 0x55, 0x49, 0x44, /* _UID  */
+                0x0b, /* WordPrefix */
+                0x34, 0x12
+            ]
+        );
+    }
+
+    #[test]
+    fn test_string() {
+        let mut aml = Vec::new();
+        (&"ACPI" as &dyn Aml).to_aml_bytes(&mut aml);
+        assert_eq!(aml, [0x0d, b'A', b'C', b'P', b'I', 0]);
+        aml.clear();
+        "ACPI".to_owned().to_aml_bytes(&mut aml);
+        assert_eq!(aml, [0x0d, b'A', b'C', b'P', b'I', 0]);
+    }
+
+    #[test]
+    fn test_method() {
+        let mut aml = Vec::new();
+        Method::new("_STA".into(), 0, false, vec![&Return::new(&0xfu8)]).to_aml_bytes(&mut aml);
+        assert_eq!(
+            aml,
+            [0x14, 0x09, 0x5F, 0x53, 0x54, 0x41, 0x00, 0xA4, 0x0A, 0x0F]
+        );
+    }
+
+    #[test]
+    fn test_field() {
+        /*
+            Field (PRST, ByteAcc, NoLock, WriteAsZeros)
+            {
+                Offset (0x04),
+                CPEN,   1,
+                CINS,   1,
+                CRMV,   1,
+                CEJ0,   1,
+                Offset (0x05),
+                CCMD,   8
+            }
+
+        */
+
+        let field_data = [
+            0x5Bu8, 0x81, 0x23, 0x50, 0x52, 0x53, 0x54, 0x41, 0x00, 0x20, 0x43, 0x50, 0x45, 0x4E,
+            0x01, 0x43, 0x49, 0x4E, 0x53, 0x01, 0x43, 0x52, 0x4D, 0x56, 0x01, 0x43, 0x45, 0x4A,
+            0x30, 0x01, 0x00, 0x04, 0x43, 0x43, 0x4D, 0x44, 0x08,
+        ];
+        let mut aml = Vec::new();
+
+        Field::new(
+            "PRST".into(),
+            FieldAccessType::Byte,
+            FieldUpdateRule::WriteAsZeroes,
+            vec![
+                FieldEntry::Reserved(32),
+                FieldEntry::Named(*b"CPEN", 1),
+                FieldEntry::Named(*b"CINS", 1),
+                FieldEntry::Named(*b"CRMV", 1),
+                FieldEntry::Named(*b"CEJ0", 1),
+                FieldEntry::Reserved(4),
+                FieldEntry::Named(*b"CCMD", 8),
+            ],
+        )
+        .to_aml_bytes(&mut aml);
+        assert_eq!(aml, &field_data[..]);
+
+        /*
+            Field (PRST, DWordAcc, NoLock, Preserve)
+            {
+                CSEL,   32,
+                Offset (0x08),
+                CDAT,   32
+            }
+        */
+
+        let field_data = [
+            0x5Bu8, 0x81, 0x12, 0x50, 0x52, 0x53, 0x54, 0x03, 0x43, 0x53, 0x45, 0x4C, 0x20, 0x00,
+            0x20, 0x43, 0x44, 0x41, 0x54, 0x20,
+        ];
+        aml.clear();
+
+        Field::new(
+            "PRST".into(),
+            FieldAccessType::DWord,
+            FieldUpdateRule::Preserve,
+            vec![
+                FieldEntry::Named(*b"CSEL", 32),
+                FieldEntry::Reserved(32),
+                FieldEntry::Named(*b"CDAT", 32),
+            ],
+        )
+        .to_aml_bytes(&mut aml);
+        assert_eq!(aml, &field_data[..]);
+    }
+
+    #[test]
+    fn test_op_region() {
+        /*
+            OperationRegion (PRST, SystemIO, 0x0CD8, 0x0C)
+        */
+        let op_region_data = [
+            0x5Bu8, 0x80, 0x50, 0x52, 0x53, 0x54, 0x01, 0x0B, 0xD8, 0x0C, 0x0A, 0x0C,
+        ];
+        let mut aml = Vec::new();
+
+        OpRegion::new("PRST".into(), OpRegionSpace::SystemIO, 0xcd8, 0xc).to_aml_bytes(&mut aml);
+        assert_eq!(aml, &op_region_data[..]);
+    }
+
+    #[test]
+    fn test_arg_if() {
+        /*
+            Method(TEST, 1, NotSerialized) {
+                If (Arg0 == Zero) {
+                        Return(One)
+                }
+                Return(Zero)
+            }
+        */
+        let arg_if_data = [
+            0x14, 0x0F, 0x54, 0x45, 0x53, 0x54, 0x01, 0xA0, 0x06, 0x93, 0x68, 0x00, 0xA4, 0x01,
+            0xA4, 0x00,
+        ];
+        let mut aml = Vec::new();
+
+        Method::new(
+            "TEST".into(),
+            1,
+            false,
+            vec![
+                &If::new(&Equal::new(&Arg(0), &ZERO), vec![&Return::new(&ONE)]),
+                &Return::new(&ZERO),
+            ],
+        )
+        .to_aml_bytes(&mut aml);
+        assert_eq!(aml, &arg_if_data);
+    }
+
+    #[test]
+    fn test_local_if() {
+        /*
+            Method(TEST, 0, NotSerialized) {
+                Local0 = One
+                If (Local0 == Zero) {
+                        Return(One)
+                }
+                Return(Zero)
+            }
+        */
+        let local_if_data = [
+            0x14, 0x12, 0x54, 0x45, 0x53, 0x54, 0x00, 0x70, 0x01, 0x60, 0xA0, 0x06, 0x93, 0x60,
+            0x00, 0xA4, 0x01, 0xA4, 0x00,
+        ];
+        let mut aml = Vec::new();
+
+        Method::new(
+            "TEST".into(),
+            0,
+            false,
+            vec![
+                &Store::new(&Local(0), &ONE),
+                &If::new(&Equal::new(&Local(0), &ZERO), vec![&Return::new(&ONE)]),
+                &Return::new(&ZERO),
+            ],
+        )
+        .to_aml_bytes(&mut aml);
+        assert_eq!(aml, &local_if_data);
+    }
+
+    #[test]
+    fn test_mutex() {
+        /*
+        Device (_SB_.MHPC)
+        {
+                Name (_HID, EisaId("PNP0A06") /* Generic Container Device */)  // _HID: Hardware ID
+                Mutex (MLCK, 0x00)
+                Method (TEST, 0, NotSerialized)
+                {
+                    Acquire (MLCK, 0xFFFF)
+                    Local0 = One
+                    Release (MLCK)
+                }
+        }
+        */
+
+        let mutex_data = [
+            0x5B, 0x82, 0x33, 0x2E, 0x5F, 0x53, 0x42, 0x5F, 0x4D, 0x48, 0x50, 0x43, 0x08, 0x5F,
+            0x48, 0x49, 0x44, 0x0C, 0x41, 0xD0, 0x0A, 0x06, 0x5B, 0x01, 0x4D, 0x4C, 0x43, 0x4B,
+            0x00, 0x14, 0x17, 0x54, 0x45, 0x53, 0x54, 0x00, 0x5B, 0x23, 0x4D, 0x4C, 0x43, 0x4B,
+            0xFF, 0xFF, 0x70, 0x01, 0x60, 0x5B, 0x27, 0x4D, 0x4C, 0x43, 0x4B,
+        ];
+        let mut aml = Vec::new();
+
+        let mutex = Mutex::new("MLCK".into(), 0);
+        Device::new(
+            "_SB_.MHPC".into(),
+            vec![
+                &Name::new("_HID".into(), &EISAName::new("PNP0A06")),
+                &mutex,
+                &Method::new(
+                    "TEST".into(),
+                    0,
+                    false,
+                    vec![
+                        &Acquire::new("MLCK".into(), 0xffff),
+                        &Store::new(&Local(0), &ONE),
+                        &Release::new("MLCK".into()),
+                    ],
+                ),
+            ],
+        )
+        .to_aml_bytes(&mut aml);
+        assert_eq!(aml, &mutex_data[..]);
+    }
+
+    #[test]
+    fn test_notify() {
+        /*
+        Device (_SB.MHPC)
+        {
+            Name (_HID, EisaId ("PNP0A06") /* Generic Container Device */)  // _HID: Hardware ID
+            Method (TEST, 0, NotSerialized)
+            {
+                Notify (MHPC, One) // Device Check
+            }
+        }
+        */
+        let notify_data = [
+            0x5B, 0x82, 0x21, 0x2E, 0x5F, 0x53, 0x42, 0x5F, 0x4D, 0x48, 0x50, 0x43, 0x08, 0x5F,
+            0x48, 0x49, 0x44, 0x0C, 0x41, 0xD0, 0x0A, 0x06, 0x14, 0x0C, 0x54, 0x45, 0x53, 0x54,
+            0x00, 0x86, 0x4D, 0x48, 0x50, 0x43, 0x01,
+        ];
+        let mut aml = Vec::new();
+
+        Device::new(
+            "_SB_.MHPC".into(),
+            vec![
+                &Name::new("_HID".into(), &EISAName::new("PNP0A06")),
+                &Method::new(
+                    "TEST".into(),
+                    0,
+                    false,
+                    vec![&Notify::new(&Path::new("MHPC"), &ONE)],
+                ),
+            ],
+        )
+        .to_aml_bytes(&mut aml);
+        assert_eq!(aml, &notify_data[..]);
+    }
+
+    #[test]
+    fn test_while() {
+        /*
+        Device (_SB.MHPC)
+        {
+            Name (_HID, EisaId ("PNP0A06") /* Generic Container Device */)  // _HID: Hardware ID
+            Method (TEST, 0, NotSerialized)
+            {
+                Local0 = Zero
+                While ((Local0 < 0x04))
+                {
+                    Local0 += One
+                }
+            }
+        }
+        */
+
+        let while_data = [
+            0x5B, 0x82, 0x28, 0x2E, 0x5F, 0x53, 0x42, 0x5F, 0x4D, 0x48, 0x50, 0x43, 0x08, 0x5F,
+            0x48, 0x49, 0x44, 0x0C, 0x41, 0xD0, 0x0A, 0x06, 0x14, 0x13, 0x54, 0x45, 0x53, 0x54,
+            0x00, 0x70, 0x00, 0x60, 0xA2, 0x09, 0x95, 0x60, 0x0A, 0x04, 0x72, 0x60, 0x01, 0x60,
+        ];
+        let mut aml = Vec::new();
+
+        Device::new(
+            "_SB_.MHPC".into(),
+            vec![
+                &Name::new("_HID".into(), &EISAName::new("PNP0A06")),
+                &Method::new(
+                    "TEST".into(),
+                    0,
+                    false,
+                    vec![
+                        &Store::new(&Local(0), &ZERO),
+                        &While::new(
+                            &LessThan::new(&Local(0), &4usize),
+                            vec![&Add::new(&Local(0), &Local(0), &ONE)],
+                        ),
+                    ],
+                ),
+            ],
+        )
+        .to_aml_bytes(&mut aml);
+        assert_eq!(aml, &while_data[..])
+    }
+
+    #[test]
+    fn test_method_call() {
+        /*
+            Method (TST1, 1, NotSerialized)
+            {
+                TST2 (One, One)
+            }
+
+            Method (TST2, 2, NotSerialized)
+            {
+                TST1 (One)
+            }
+        */
+        let test_data = [
+            0x14, 0x0C, 0x54, 0x53, 0x54, 0x31, 0x01, 0x54, 0x53, 0x54, 0x32, 0x01, 0x01, 0x14,
+            0x0B, 0x54, 0x53, 0x54, 0x32, 0x02, 0x54, 0x53, 0x54, 0x31, 0x01,
+        ];
+
+        let mut methods = Vec::new();
+        Method::new(
+            "TST1".into(),
+            1,
+            false,
+            vec![&MethodCall::new("TST2".into(), vec![&ONE, &ONE])],
+        )
+        .to_aml_bytes(&mut methods);
+        Method::new(
+            "TST2".into(),
+            2,
+            false,
+            vec![&MethodCall::new("TST1".into(), vec![&ONE])],
+        )
+        .to_aml_bytes(&mut methods);
+        assert_eq!(&methods[..], &test_data[..])
+    }
+
+    #[test]
+    fn test_buffer() {
+        /*
+        Name (_MAT, Buffer (0x08)  // _MAT: Multiple APIC Table Entry
+        {
+            0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00   /* ........ */
+        })
+        */
+        let buffer_data = [
+            0x08, 0x5F, 0x4D, 0x41, 0x54, 0x11, 0x0B, 0x0A, 0x08, 0x00, 0x08, 0x00, 0x00, 0x01,
+            0x00, 0x00, 0x00,
+        ];
+        let mut aml = Vec::new();
+
+        Name::new(
+            "_MAT".into(),
+            &Buffer::new(vec![0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00]),
+        )
+        .to_aml_bytes(&mut aml);
+        assert_eq!(aml, &buffer_data[..])
+    }
+}
diff --git a/acpi_tables/src/lib.rs b/acpi_tables/src/lib.rs
index 49cf760..e45aa40 100644
--- a/acpi_tables/src/lib.rs
+++ b/acpi_tables/src/lib.rs
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+pub mod aml;
 pub mod rsdp;
 pub mod sdt;