// Copyright © 2019 Intel Corporation // // SPDX-License-Identifier: Apache-2.0 // use std::marker::PhantomData; pub trait Aml { fn append_aml_bytes(&self, _v: &mut Vec) { unimplemented!() } fn to_aml_bytes(&self) -> Vec { let mut v = Vec::new(); self.append_aml_bytes(&mut v); v } } pub const ZERO: Zero = Zero {}; pub struct Zero {} impl Aml for Zero { fn append_aml_bytes(&self, v: &mut Vec) { v.push(0u8) } } pub const ONE: One = One {}; pub struct One {} impl Aml for One { fn append_aml_bytes(&self, v: &mut Vec) { v.push(1u8) } } pub const ONES: Ones = Ones {}; pub struct Ones {} impl Aml for Ones { fn append_aml_bytes(&self, v: &mut Vec) { v.push(0xffu8) } } pub struct Path { root: bool, name_parts: Vec<[u8; 4]>, } impl Aml for Path { fn append_aml_bytes(&self, bytes: &mut Vec) { if self.root { bytes.push(b'\\'); } match self.name_parts.len() { 0 => panic!("Name cannot be empty"), 1 => {} 2 => { bytes.push(0x2e); /* DualNamePrefix */ } n => { bytes.push(0x2f); /* MultiNamePrefix */ bytes.push(n as u8); } }; for part in self.name_parts.clone().iter_mut() { bytes.extend_from_slice(&part.to_vec()); } } } impl Path { 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 append_aml_bytes(&self, bytes: &mut Vec) { bytes.push(0x0a); /* BytePrefix */ bytes.push(*self); } } pub type Word = u16; impl Aml for Word { fn append_aml_bytes(&self, bytes: &mut Vec) { bytes.push(0x0b); /* WordPrefix */ bytes.extend_from_slice(&self.to_le_bytes()) } } pub type DWord = u32; impl Aml for DWord { fn append_aml_bytes(&self, bytes: &mut Vec) { bytes.push(0x0c); /* DWordPrefix */ bytes.extend_from_slice(&self.to_le_bytes()) } } pub type QWord = u64; impl Aml for QWord { fn append_aml_bytes(&self, bytes: &mut Vec) { bytes.push(0x0e); /* QWordPrefix */ bytes.extend_from_slice(&self.to_le_bytes()) } } pub struct Name { bytes: Vec, } impl Aml for Name { fn append_aml_bytes(&self, bytes: &mut Vec) { // TODO: Refactor this to make more efficient but there are // lifetime/ownership challenges. bytes.extend_from_slice(&self.bytes.clone()) } } impl Name { pub fn new(path: Path, inner: &dyn Aml) -> Self { let mut bytes = vec![0x08]; /* NameOp */ path.append_aml_bytes(&mut bytes); inner.append_aml_bytes(&mut bytes); Name { bytes } } } pub struct Package<'a> { children: Vec<&'a dyn Aml>, } impl<'a> Aml for Package<'a> { fn append_aml_bytes(&self, bytes: &mut Vec) { let mut tmp = vec![self.children.len() as u8]; for child in &self.children { child.append_aml_bytes(&mut tmp); } let pkg_length = create_pkg_length(&tmp, true); bytes.push(0x12); /* PackageOp */ bytes.extend_from_slice(&pkg_length); bytes.extend_from_slice(&tmp); } } impl<'a> Package<'a> { 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 { 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 } pub struct EisaName { value: DWord, } impl EisaName { pub fn new(name: &str) -> Self { assert_eq!(name.len(), 7); let data = name.as_bytes(); let value: u32 = (u32::from(data[0] - 0x40) << 26 | u32::from(data[1] - 0x40) << 21 | u32::from(data[2] - 0x40) << 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 append_aml_bytes(&self, bytes: &mut Vec) { self.value.append_aml_bytes(bytes) } } pub type Usize = usize; impl Aml for Usize { fn append_aml_bytes(&self, bytes: &mut Vec) { if *self <= u8::max_value().into() { (*self as u8).append_aml_bytes(bytes) } else if *self <= u16::max_value().into() { (*self as u16).append_aml_bytes(bytes) } else if *self <= u32::max_value() as usize { (*self as u32).append_aml_bytes(bytes) } else { (*self as u64).append_aml_bytes(bytes) } } } fn append_aml_string(v: &str, bytes: &mut Vec) { bytes.push(0x0D); /* String Op */ bytes.extend_from_slice(v.as_bytes()); bytes.push(0x0); /* NullChar */ } pub type AmlStr = &'static str; impl Aml for AmlStr { fn append_aml_bytes(&self, bytes: &mut Vec) { append_aml_string(self, bytes) } } pub type AmlString = String; impl Aml for AmlString { fn append_aml_bytes(&self, bytes: &mut Vec) { append_aml_string(self, bytes) } } pub struct ResourceTemplate<'a> { children: Vec<&'a dyn Aml>, } impl<'a> Aml for ResourceTemplate<'a> { fn append_aml_bytes(&self, bytes: &mut Vec) { let mut tmp = Vec::new(); // Add buffer data for child in &self.children { child.append_aml_bytes(&mut tmp); } // Mark with end and mark checksum as as always valid tmp.push(0x79); /* EndTag */ tmp.push(0); /* zero checksum byte */ // Buffer length is an encoded integer including buffer data // and EndTag and checksum byte let mut buffer_length = tmp.len().to_aml_bytes(); buffer_length.reverse(); for byte in buffer_length { tmp.insert(0, byte); } // PkgLength is everything else let pkg_length = create_pkg_length(&tmp, true); bytes.push(0x11); /* BufferOp */ bytes.extend_from_slice(&pkg_length); bytes.extend_from_slice(&tmp); } } impl<'a> ResourceTemplate<'a> { pub fn new(children: Vec<&'a dyn Aml>) -> Self { ResourceTemplate { children } } } pub struct Memory32Fixed { read_write: bool, /* true for read & write, false for read only */ base: u32, length: u32, } impl Memory32Fixed { pub fn new(read_write: bool, base: u32, length: u32) -> Self { Memory32Fixed { read_write, base, length, } } } impl Aml for Memory32Fixed { fn append_aml_bytes(&self, bytes: &mut Vec) { bytes.push(0x86); /* Memory32Fixed */ bytes.extend_from_slice(&9u16.to_le_bytes()); // 9 bytes of payload bytes.push(self.read_write as u8); bytes.extend_from_slice(&self.base.to_le_bytes()); bytes.extend_from_slice(&self.length.to_le_bytes()); } } #[derive(Copy, Clone)] enum AddressSpaceType { Memory, Io, BusNumber, } #[derive(Copy, Clone)] pub enum AddressSpaceCachable { NotCacheable, Cacheable, WriteCombining, PreFetchable, } pub struct AddressSpace { r#type: AddressSpaceType, min: T, max: T, type_flags: u8, } impl AddressSpace { pub fn new_memory(cacheable: AddressSpaceCachable, read_write: bool, min: T, max: T) -> Self { AddressSpace { r#type: AddressSpaceType::Memory, min, max, type_flags: (cacheable as u8) << 1 | read_write as u8, } } pub fn new_io(min: T, max: T) -> Self { AddressSpace { r#type: AddressSpaceType::Io, min, max, type_flags: 3, /* EntireRange */ } } pub fn new_bus_number(min: T, max: T) -> Self { AddressSpace { r#type: AddressSpaceType::BusNumber, min, max, type_flags: 0, } } fn push_header(&self, bytes: &mut Vec, descriptor: u8, length: usize) { bytes.push(descriptor); /* Word Address Space Descriptor */ bytes.extend_from_slice(&(length as u16).to_le_bytes()); bytes.push(self.r#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 { fn append_aml_bytes(&self, bytes: &mut Vec) { self.push_header( bytes, 0x88, /* Word Address Space Descriptor */ 3 + 5 * std::mem::size_of::(), /* 3 bytes of header + 5 u16 fields */ ); bytes.extend_from_slice(&0u16.to_le_bytes()); /* Granularity */ bytes.extend_from_slice(&self.min.to_le_bytes()); /* Min */ bytes.extend_from_slice(&self.max.to_le_bytes()); /* Max */ bytes.extend_from_slice(&0u16.to_le_bytes()); /* Translation */ let len = self.max - self.min + 1; bytes.extend_from_slice(&len.to_le_bytes()); /* Length */ } } impl Aml for AddressSpace { fn append_aml_bytes(&self, bytes: &mut Vec) { self.push_header( bytes, 0x87, /* DWord Address Space Descriptor */ 3 + 5 * std::mem::size_of::(), /* 3 bytes of header + 5 u32 fields */ ); bytes.extend_from_slice(&0u32.to_le_bytes()); /* Granularity */ bytes.extend_from_slice(&self.min.to_le_bytes()); /* Min */ bytes.extend_from_slice(&self.max.to_le_bytes()); /* Max */ bytes.extend_from_slice(&0u32.to_le_bytes()); /* Translation */ let len = self.max - self.min + 1; bytes.extend_from_slice(&len.to_le_bytes()); /* Length */ } } impl Aml for AddressSpace { fn append_aml_bytes(&self, bytes: &mut Vec) { self.push_header( bytes, 0x8A, /* QWord Address Space Descriptor */ 3 + 5 * std::mem::size_of::(), /* 3 bytes of header + 5 u64 fields */ ); bytes.extend_from_slice(&0u64.to_le_bytes()); /* Granularity */ bytes.extend_from_slice(&self.min.to_le_bytes()); /* Min */ bytes.extend_from_slice(&self.max.to_le_bytes()); /* Max */ bytes.extend_from_slice(&0u64.to_le_bytes()); /* Translation */ let len = self.max - self.min + 1; bytes.extend_from_slice(&len.to_le_bytes()); /* Length */ } } pub struct Io { min: u16, max: u16, alignment: u8, length: u8, } impl Io { pub fn new(min: u16, max: u16, alignment: u8, length: u8) -> Self { Io { min, max, alignment, length, } } } impl Aml for Io { fn append_aml_bytes(&self, bytes: &mut Vec) { bytes.push(0x47); /* Io Port Descriptor */ bytes.push(1); /* IODecode16 */ bytes.extend_from_slice(&self.min.to_le_bytes()); bytes.extend_from_slice(&self.max.to_le_bytes()); bytes.push(self.alignment); bytes.push(self.length); } } pub struct Interrupt { consumer: bool, edge_triggered: bool, active_low: bool, shared: bool, number: u32, } impl Interrupt { 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 append_aml_bytes(&self, bytes: &mut Vec) { bytes.push(0x89); /* Extended IRQ Descriptor */ bytes.extend_from_slice(&6u16.to_le_bytes()); 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.extend_from_slice(&self.number.to_le_bytes()); } } pub struct Device<'a> { path: Path, children: Vec<&'a dyn Aml>, } impl<'a> Aml for Device<'a> { fn append_aml_bytes(&self, bytes: &mut Vec) { let mut tmp = Vec::new(); self.path.append_aml_bytes(&mut tmp); for child in &self.children { child.append_aml_bytes(&mut tmp); } let pkg_length = create_pkg_length(&tmp, true); bytes.push(0x5b); /* ExtOpPrefix */ bytes.push(0x82); /* DeviceOp */ bytes.extend_from_slice(&pkg_length); bytes.extend_from_slice(&tmp); } } impl<'a> Device<'a> { pub fn new(path: Path, children: Vec<&'a dyn Aml>) -> Self { Device { path, children } } } pub struct Scope<'a> { path: Path, children: Vec<&'a dyn Aml>, } impl<'a> Aml for Scope<'a> { fn append_aml_bytes(&self, bytes: &mut Vec) { let mut tmp = Vec::new(); self.path.append_aml_bytes(&mut tmp); for child in &self.children { child.append_aml_bytes(&mut tmp); } let pkg_length = create_pkg_length(&tmp, true); bytes.push(0x10); /* ScopeOp */ bytes.extend_from_slice(&pkg_length); bytes.extend_from_slice(&tmp) } } impl<'a> Scope<'a> { pub fn new(path: Path, children: Vec<&'a dyn Aml>) -> Self { Scope { path, children } } } pub struct Method<'a> { path: Path, children: Vec<&'a dyn Aml>, args: u8, serialized: bool, } impl<'a> Method<'a> { 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 append_aml_bytes(&self, bytes: &mut Vec) { let mut tmp = Vec::new(); self.path.append_aml_bytes(&mut tmp); let flags: u8 = (self.args & 0x7) | (self.serialized as u8) << 3; tmp.push(flags); for child in &self.children { child.append_aml_bytes(&mut tmp); } let pkg_length = create_pkg_length(&tmp, true); bytes.push(0x14); /* MethodOp */ bytes.extend_from_slice(&pkg_length); bytes.extend_from_slice(&tmp) } } pub struct Return<'a> { value: &'a dyn Aml, } impl<'a> Return<'a> { pub fn new(value: &'a dyn Aml) -> Self { Return { value } } } impl<'a> Aml for Return<'a> { fn append_aml_bytes(&self, bytes: &mut Vec) { bytes.push(0xa4); /* ReturnOp */ self.value.append_aml_bytes(bytes); } } #[derive(Clone, Copy)] pub enum FieldAccessType { Any, Byte, Word, DWord, QWord, Buffer, } #[derive(Clone, Copy)] pub enum FieldUpdateRule { Preserve = 0, WriteAsOnes = 1, WriteAsZeroes = 2, } pub enum FieldEntry { Named([u8; 4], usize), Reserved(usize), } pub struct Field { path: Path, fields: Vec, access_type: FieldAccessType, update_rule: FieldUpdateRule, } impl Field { pub fn new( path: Path, access_type: FieldAccessType, update_rule: FieldUpdateRule, fields: Vec, ) -> Self { Field { path, fields, access_type, update_rule, } } } impl Aml for Field { fn append_aml_bytes(&self, bytes: &mut Vec) { let mut tmp = Vec::new(); self.path.append_aml_bytes(&mut tmp); let flags: u8 = self.access_type as u8 | (self.update_rule as u8) << 5; tmp.push(flags); for field in self.fields.iter() { match field { FieldEntry::Named(name, length) => { tmp.extend_from_slice(name); tmp.extend_from_slice(&create_pkg_length(&vec![0; *length], false)); } FieldEntry::Reserved(length) => { tmp.push(0x0); tmp.extend_from_slice(&create_pkg_length(&vec![0; *length], false)); } } } let pkg_length = create_pkg_length(&tmp, true); bytes.push(0x5b); /* ExtOpPrefix */ bytes.push(0x81); /* FieldOp */ bytes.extend_from_slice(&pkg_length); bytes.extend_from_slice(&tmp) } } #[derive(Clone, Copy)] pub enum OpRegionSpace { SystemMemory, SystemIo, PConfig, EmbeddedControl, Smbus, SystemCmos, PciBarTarget, Ipmi, GeneralPurposeIo, GenericSerialBus, } pub struct OpRegion { path: Path, space: OpRegionSpace, offset: usize, length: usize, } impl OpRegion { pub fn new(path: Path, space: OpRegionSpace, offset: usize, length: usize) -> Self { OpRegion { path, space, offset, length, } } } impl Aml for OpRegion { fn append_aml_bytes(&self, bytes: &mut Vec) { bytes.push(0x5b); /* ExtOpPrefix */ bytes.push(0x80); /* OpRegionOp */ self.path.append_aml_bytes(bytes); bytes.push(self.space as u8); self.offset.append_aml_bytes(bytes); /* RegionOffset */ self.length.append_aml_bytes(bytes); /* RegionLen */ } } pub struct If<'a> { predicate: &'a dyn Aml, if_children: Vec<&'a dyn Aml>, } impl<'a> If<'a> { 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 append_aml_bytes(&self, bytes: &mut Vec) { let mut tmp = Vec::new(); self.predicate.append_aml_bytes(&mut tmp); for child in self.if_children.iter() { child.append_aml_bytes(&mut tmp); } let pkg_length = create_pkg_length(&tmp, true); bytes.push(0xa0); /* IfOp */ bytes.extend_from_slice(&pkg_length); bytes.extend_from_slice(&tmp); } } pub struct Equal<'a> { left: &'a dyn Aml, right: &'a dyn Aml, } impl<'a> Equal<'a> { pub fn new(left: &'a dyn Aml, right: &'a dyn Aml) -> Self { Equal { left, right } } } impl<'a> Aml for Equal<'a> { fn append_aml_bytes(&self, bytes: &mut Vec) { bytes.push(0x93); /* LEqualOp */ self.left.append_aml_bytes(bytes); self.right.append_aml_bytes(bytes); } } pub struct LessThan<'a> { left: &'a dyn Aml, right: &'a dyn Aml, } impl<'a> LessThan<'a> { pub fn new(left: &'a dyn Aml, right: &'a dyn Aml) -> Self { LessThan { left, right } } } impl<'a> Aml for LessThan<'a> { fn append_aml_bytes(&self, bytes: &mut Vec) { bytes.push(0x95); /* LLessOp */ self.left.append_aml_bytes(bytes); self.right.append_aml_bytes(bytes); } } pub struct Arg(pub u8); impl Aml for Arg { fn append_aml_bytes(&self, bytes: &mut Vec) { assert!(self.0 <= 6); bytes.push(0x68 + self.0); /* Arg0Op */ } } pub struct Local(pub u8); impl Aml for Local { fn append_aml_bytes(&self, bytes: &mut Vec) { assert!(self.0 <= 7); bytes.push(0x60 + self.0); /* Local0Op */ } } pub struct Store<'a> { name: &'a dyn Aml, value: &'a dyn Aml, } impl<'a> Store<'a> { pub fn new(name: &'a dyn Aml, value: &'a dyn Aml) -> Self { Store { name, value } } } impl<'a> Aml for Store<'a> { fn append_aml_bytes(&self, bytes: &mut Vec) { bytes.push(0x70); /* StoreOp */ self.value.append_aml_bytes(bytes); self.name.append_aml_bytes(bytes); } } pub struct Mutex { path: Path, sync_level: u8, } impl Mutex { pub fn new(path: Path, sync_level: u8) -> Self { Self { path, sync_level } } } impl Aml for Mutex { fn append_aml_bytes(&self, bytes: &mut Vec) { bytes.push(0x5b); /* ExtOpPrefix */ bytes.push(0x01); /* MutexOp */ self.path.append_aml_bytes(bytes); bytes.push(self.sync_level); } } pub struct Acquire { mutex: Path, timeout: u16, } impl Acquire { pub fn new(mutex: Path, timeout: u16) -> Self { Acquire { mutex, timeout } } } impl Aml for Acquire { fn append_aml_bytes(&self, bytes: &mut Vec) { bytes.push(0x5b); /* ExtOpPrefix */ bytes.push(0x23); /* AcquireOp */ self.mutex.append_aml_bytes(bytes); bytes.extend_from_slice(&self.timeout.to_le_bytes()); } } pub struct Release { mutex: Path, } impl Release { pub fn new(mutex: Path) -> Self { Release { mutex } } } impl Aml for Release { fn append_aml_bytes(&self, bytes: &mut Vec) { bytes.push(0x5b); /* ExtOpPrefix */ bytes.push(0x27); /* ReleaseOp */ self.mutex.append_aml_bytes(bytes); } } pub struct Notify<'a> { object: &'a dyn Aml, value: &'a dyn Aml, } impl<'a> Notify<'a> { pub fn new(object: &'a dyn Aml, value: &'a dyn Aml) -> Self { Notify { object, value } } } impl<'a> Aml for Notify<'a> { fn append_aml_bytes(&self, bytes: &mut Vec) { bytes.push(0x86); /* NotifyOp */ self.object.append_aml_bytes(bytes); self.value.append_aml_bytes(bytes); } } pub struct While<'a> { predicate: &'a dyn Aml, while_children: Vec<&'a dyn Aml>, } impl<'a> While<'a> { 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 append_aml_bytes(&self, bytes: &mut Vec) { let mut tmp = Vec::new(); self.predicate.append_aml_bytes(&mut tmp); for child in self.while_children.iter() { child.append_aml_bytes(&mut tmp) } let pkg_length = create_pkg_length(&tmp, true); bytes.push(0xa2); /* WhileOp */ bytes.extend_from_slice(&pkg_length); bytes.extend_from_slice(&tmp); } } macro_rules! binary_op { ($name:ident, $opcode:expr) => { pub struct $name<'a> { a: &'a dyn Aml, b: &'a dyn Aml, target: &'a dyn Aml, } impl<'a> $name<'a> { pub fn new(target: &'a dyn Aml, a: &'a dyn Aml, b: &'a dyn Aml) -> Self { $name { a, b, target } } } impl<'a> Aml for $name<'a> { fn append_aml_bytes(&self, bytes: &mut Vec) { bytes.push($opcode); /* Op for the binary operator */ self.a.append_aml_bytes(bytes); self.b.append_aml_bytes(bytes); self.target.append_aml_bytes(bytes); } } }; } /* binary operators: TermArg TermArg Target */ binary_op!(Add, 0x72); binary_op!(Concat, 0x73); binary_op!(Subtract, 0x74); binary_op!(Multiply, 0x77); binary_op!(ShiftLeft, 0x79); binary_op!(ShiftRight, 0x7A); binary_op!(And, 0x7B); binary_op!(Nand, 0x7C); binary_op!(Or, 0x7D); binary_op!(Nor, 0x7E); binary_op!(Xor, 0x7F); binary_op!(ConateRes, 0x84); binary_op!(Mod, 0x85); binary_op!(Index, 0x88); binary_op!(ToString, 0x9C); pub struct MethodCall<'a> { name: Path, args: Vec<&'a dyn Aml>, } impl<'a> MethodCall<'a> { pub fn new(name: Path, args: Vec<&'a dyn Aml>) -> Self { MethodCall { name, args } } } impl<'a> Aml for MethodCall<'a> { fn append_aml_bytes(&self, bytes: &mut Vec) { self.name.append_aml_bytes(bytes); for arg in self.args.iter() { arg.append_aml_bytes(bytes); } } } pub struct Buffer { data: Vec, } impl Buffer { pub fn new(data: Vec) -> Self { Buffer { data } } } impl Aml for Buffer { fn append_aml_bytes(&self, bytes: &mut Vec) { let mut tmp = Vec::new(); self.data.len().append_aml_bytes(&mut tmp); tmp.extend_from_slice(&self.data); let pkg_length = create_pkg_length(&tmp, true); bytes.push(0x11); /* BufferOp */ bytes.extend_from_slice(&pkg_length); bytes.extend_from_slice(&tmp); } } pub struct CreateField<'a, T> { buffer: &'a dyn Aml, offset: &'a dyn Aml, field: Path, phantom: PhantomData<&'a T>, } impl<'a, T> CreateField<'a, T> { pub fn new(buffer: &'a dyn Aml, offset: &'a dyn Aml, field: Path) -> Self { CreateField:: { buffer, offset, field, phantom: PhantomData::default(), } } } impl<'a> Aml for CreateField<'a, u64> { fn append_aml_bytes(&self, bytes: &mut Vec) { bytes.push(0x8f); /* CreateQWordFieldOp */ self.buffer.append_aml_bytes(bytes); self.offset.append_aml_bytes(bytes); self.field.append_aml_bytes(bytes); } } impl<'a> Aml for CreateField<'a, u32> { fn append_aml_bytes(&self, bytes: &mut Vec) { bytes.push(0x8a); /* CreateDWordFieldOp */ self.buffer.append_aml_bytes(bytes); self.offset.append_aml_bytes(bytes); self.field.append_aml_bytes(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, ]; assert_eq!( 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(), &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, ]; assert_eq!( Scope::new( "_SB_.MBRD".into(), vec![&Name::new( "_CRS".into(), &ResourceTemplate::new(vec![&Memory32Fixed::new( true, 0xE800_0000, 0x1000_0000 )]) )] ) .to_aml_bytes(), &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, ]; assert_eq!( Name::new( "_CRS".into(), &ResourceTemplate::new(vec![&Memory32Fixed::new(true, 0xE800_0000, 0x1000_0000)]) ) .to_aml_bytes(), 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, ]; assert_eq!( Name::new( "_CRS".into(), &ResourceTemplate::new(vec![&AddressSpace::new_bus_number(0x0u16, 0xffu16),]) ) .to_aml_bytes(), &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, ]; assert_eq!( Name::new( "_CRS".into(), &ResourceTemplate::new(vec![ &AddressSpace::new_io(0x0u16, 0xcf7u16), &AddressSpace::new_io(0xd00u16, 0xffffu16), ]) ) .to_aml_bytes(), &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, ]; assert_eq!( 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(), &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, ]; assert_eq!( Name::new( "_CRS".into(), &ResourceTemplate::new(vec![&AddressSpace::new_memory( AddressSpaceCachable::Cacheable, true, 0x8_0000_0000u64, 0xf_ffff_ffffu64 )]) ) .to_aml_bytes(), &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, ]; assert_eq!( Name::new( "_CRS".into(), &ResourceTemplate::new(vec![ &Interrupt::new(true, true, false, false, 4), &Io::new(0x3f8, 0x3f8, 0, 0x8) ]) ) .to_aml_bytes(), &interrupt_io_data[..] ); } #[test] fn test_pkg_length() { assert_eq!(create_pkg_length(&[0u8; 62], true), vec![63]); assert_eq!( create_pkg_length(&[0u8; 64], true), vec![1 << 6 | (66 & 0xf), 66 >> 4] ); assert_eq!( create_pkg_length(&[0u8; 4096], 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 s5 = Name::new("_S5_".into(), &Package::new(vec![&5u8])); assert_eq!(s5_sleep_data.to_vec(), s5.to_aml_bytes()); } #[test] fn test_eisa_name() { assert_eq!( Name::new("_HID".into(), &EisaName::new("PNP0501")).to_aml_bytes(), [0x08, 0x5F, 0x48, 0x49, 0x44, 0x0C, 0x41, 0xD0, 0x05, 0x01], ) } #[test] fn test_name_path() { assert_eq!( (&"_SB_".into() as &Path).to_aml_bytes(), [0x5Fu8, 0x53, 0x42, 0x5F] ); assert_eq!( (&"\\_SB_".into() as &Path).to_aml_bytes(), [0x5C, 0x5F, 0x53, 0x42, 0x5F] ); assert_eq!( (&"_SB_.COM1".into() as &Path).to_aml_bytes(), [0x2E, 0x5F, 0x53, 0x42, 0x5F, 0x43, 0x4F, 0x4D, 0x31] ); assert_eq!( (&"_SB_.PCI0._HID".into() as &Path).to_aml_bytes(), [0x2F, 0x03, 0x5F, 0x53, 0x42, 0x5F, 0x50, 0x43, 0x49, 0x30, 0x5F, 0x48, 0x49, 0x44] ); } #[test] fn test_numbers() { assert_eq!(128u8.to_aml_bytes(), [0x0a, 0x80]); assert_eq!(1024u16.to_aml_bytes(), [0x0b, 0x0, 0x04]); assert_eq!((16u32 << 20).to_aml_bytes(), [0x0c, 0x00, 0x00, 0x0, 0x01]); assert_eq!( 0xdeca_fbad_deca_fbadu64.to_aml_bytes(), [0x0e, 0xad, 0xfb, 0xca, 0xde, 0xad, 0xfb, 0xca, 0xde] ); } #[test] fn test_name() { assert_eq!( Name::new("_SB_.PCI0._UID".into(), &0x1234u16).to_aml_bytes(), [ 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() { assert_eq!( (&"ACPI" as &dyn Aml).to_aml_bytes(), [0x0d, b'A', b'C', b'P', b'I', 0] ); assert_eq!( "ACPI".to_owned().to_aml_bytes(), [0x0d, b'A', b'C', b'P', b'I', 0] ); } #[test] fn test_method() { assert_eq!( Method::new("_STA".into(), 0, false, vec![&Return::new(&0xfu8)]).to_aml_bytes(), [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, ]; assert_eq!( 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(), &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, ]; assert_eq!( 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(), &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, ]; assert_eq!( OpRegion::new("PRST".into(), OpRegionSpace::SystemIo, 0xcd8, 0xc).to_aml_bytes(), &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, ]; assert_eq!( Method::new( "TEST".into(), 1, false, vec![ &If::new(&Equal::new(&Arg(0), &ZERO), vec![&Return::new(&ONE)]), &Return::new(&ZERO) ] ) .to_aml_bytes(), &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, ]; assert_eq!( 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(), &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 mutex = Mutex::new("MLCK".into(), 0); assert_eq!( 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(), &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, ]; assert_eq!( 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(), ¬ify_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, ]; assert_eq!( 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(), &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(); methods.extend_from_slice( &Method::new( "TST1".into(), 1, false, vec![&MethodCall::new("TST2".into(), vec![&ONE, &ONE])], ) .to_aml_bytes(), ); methods.extend_from_slice( &Method::new( "TST2".into(), 2, false, vec![&MethodCall::new("TST1".into(), vec![&ONE])], ) .to_aml_bytes(), ); 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, ]; assert_eq!( Name::new( "_MAT".into(), &Buffer::new(vec![0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00]) ) .to_aml_bytes(), &buffer_data[..] ) } #[test] fn test_create_field() { /* Method (MCRS, 0, Serialized) { Name (MR64, ResourceTemplate () { QWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite, 0x0000000000000000, // Granularity 0x0000000000000000, // Range Minimum 0xFFFFFFFFFFFFFFFE, // Range Maximum 0x0000000000000000, // Translation Offset 0xFFFFFFFFFFFFFFFF, // Length ,, _Y00, AddressRangeMemory, TypeStatic) }) CreateQWordField (MR64, \_SB.MHPC.MCRS._Y00._MIN, MIN) // _MIN: Minimum Base Address CreateQWordField (MR64, \_SB.MHPC.MCRS._Y00._MAX, MAX) // _MAX: Maximum Base Address CreateQWordField (MR64, \_SB.MHPC.MCRS._Y00._LEN, LEN) // _LEN: Length } */ let data = [ 0x14, 0x41, 0x06, 0x4D, 0x43, 0x52, 0x53, 0x08, 0x08, 0x4D, 0x52, 0x36, 0x34, 0x11, 0x33, 0x0A, 0x30, 0x8A, 0x2B, 0x00, 0x00, 0x0C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x79, 0x00, 0x8F, 0x4D, 0x52, 0x36, 0x34, 0x0A, 0x0E, 0x4D, 0x49, 0x4E, 0x5F, 0x8F, 0x4D, 0x52, 0x36, 0x34, 0x0A, 0x16, 0x4D, 0x41, 0x58, 0x5F, 0x8F, 0x4D, 0x52, 0x36, 0x34, 0x0A, 0x26, 0x4C, 0x45, 0x4E, 0x5F, ]; assert_eq!( Method::new( "MCRS".into(), 0, true, vec![ &Name::new( "MR64".into(), &ResourceTemplate::new(vec![&AddressSpace::new_memory( AddressSpaceCachable::Cacheable, true, 0x0000_0000_0000_0000u64, 0xFFFF_FFFF_FFFF_FFFEu64 )]) ), &CreateField::::new(&Path::new("MR64"), &14usize, "MIN_".into()), &CreateField::::new(&Path::new("MR64"), &22usize, "MAX_".into()), &CreateField::::new(&Path::new("MR64"), &38usize, "LEN_".into()), ] ) .to_aml_bytes(), &data[..] ); } }