pub trait Aml {
fn to_aml_bytes(&self, bytes: &mut Vec<u8>);
}
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 VARPACKAGEOP: u8 = 0x13;
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 CREATEFIELDOP: u8 = 0x13;
const ACQUIREOP: u8 = 0x23;
const RELEASEOP: u8 = 0x27;
const OPREGIONOP: u8 = 0x80;
const FIELDOP: u8 = 0x81;
const DEVICEOP: u8 = 0x82;
const POWERRESOURCEOP: u8 = 0x84;
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 DEREFOFOP: u8 = 0x83;
const CONCATRESOP: u8 = 0x84;
const MODOP: u8 = 0x85;
const NOTIFYOP: u8 = 0x86;
const SIZEOFOP: u8 = 0x87;
const INDEXOP: u8 = 0x88;
const CREATEDWFIELDOP: u8 = 0x8a;
const OBJECTTYPEOP: u8 = 0x8e;
const CREATEQWFIELDOP: u8 = 0x8f;
const LNOTOP: u8 = 0x92;
const LEQUALOP: u8 = 0x93;
const LGREATEROP: u8 = 0x94;
const LLESSOP: u8 = 0x95;
const TOBUFFEROP: u8 = 0x96;
const TOINTEGEROP: u8 = 0x99;
const TOSTRINGOP: u8 = 0x9c;
const MIDOP: u8 = 0x9e;
const IFOP: u8 = 0xa0;
const ELSEOP: u8 = 0xa1;
const WHILEOP: u8 = 0xa2;
const RETURNOP: u8 = 0xa4;
const ONESOP: u8 = 0xff;
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;
pub const ZERO: Zero = Zero {};
pub struct Zero {}
impl Aml for Zero {
fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
bytes.push(ZEROOP);
}
}
pub const ONE: One = One {};
pub struct One {}
impl Aml for One {
fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
bytes.push(ONEOP);
}
}
pub const ONES: Ones = Ones {};
pub struct Ones {}
impl Aml for Ones {
fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
bytes.push(ONESOP);
}
}
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 {
bytes.extend_from_slice(part);
}
}
}
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 to_aml_bytes(&self, bytes: &mut Vec<u8>) {
match *self {
0 => ZERO.to_aml_bytes(bytes),
1 => ONE.to_aml_bytes(bytes),
_ => {
bytes.push(BYTEPREFIX);
bytes.push(*self);
}
}
}
}
pub type Word = u16;
impl Aml for Word {
fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
if *self <= Byte::MAX.into() {
(*self as Byte).to_aml_bytes(bytes);
} else {
bytes.push(WORDPREFIX);
bytes.extend_from_slice(&self.to_le_bytes());
}
}
}
pub type DWord = u32;
impl Aml for DWord {
fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
if *self <= Word::MAX.into() {
(*self as Word).to_aml_bytes(bytes);
} else {
bytes.push(DWORDPREFIX);
bytes.extend_from_slice(&self.to_le_bytes());
}
}
}
pub type QWord = u64;
impl Aml for QWord {
fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
if *self <= DWord::MAX.into() {
(*self as DWord).to_aml_bytes(bytes);
} else {
bytes.push(QWORDPREFIX);
bytes.extend_from_slice(&self.to_le_bytes());
}
}
}
pub struct Name {
bytes: Vec<u8>,
}
impl Aml for Name {
fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
bytes.extend_from_slice(&self.bytes);
}
}
impl Name {
pub fn new(path: Path, inner: &dyn Aml) -> Self {
let mut bytes = vec![NAMEOP];
path.to_aml_bytes(&mut bytes);
inner.to_aml_bytes(&mut bytes);
Name { bytes }
}
pub fn new_field_name(field_name: &str) -> Self {
let bytes = field_name.as_bytes().to_vec();
Name { bytes }
}
}
pub struct Package {
children_bytes: Vec<u8>,
}
impl Aml for Package {
fn to_aml_bytes(&self, aml: &mut Vec<u8>) {
aml.push(PACKAGEOP);
append_pkg_length(aml, self.children_bytes.len());
aml.extend_from_slice(&self.children_bytes);
}
}
impl Package {
pub fn new(children: Vec<&dyn Aml>) -> Package {
let mut bytes = vec![children.len() as u8];
for child in &children {
child.to_aml_bytes(&mut bytes);
}
Package {
children_bytes: bytes,
}
}
}
pub struct VarPackageTerm<'a> {
data: &'a dyn Aml,
}
impl<'a> Aml for VarPackageTerm<'a> {
fn to_aml_bytes(&self, aml: &mut Vec<u8>) {
aml.push(VARPACKAGEOP);
let start = aml.len();
self.data.to_aml_bytes(aml);
let data_len = aml.len() - start;
insert_pkg_length(aml, start, data_len);
}
}
impl<'a> VarPackageTerm<'a> {
pub fn new(data: &'a dyn Aml) -> Self {
VarPackageTerm { data }
}
}
fn insert_length(aml: &mut Vec<u8>, position: usize, len: usize, include_self: bool) {
let length_length = if len < (2usize.pow(6) - 1) {
1
} else if len < (2usize.pow(12) - 2) {
2
} else if len < (2usize.pow(20) - 3) {
3
} else {
4
};
let length = len + if include_self { length_length } else { 0 };
match length_length {
1 => aml.insert(position, length as u8),
2 => {
aml.splice(
position..position,
[(1u8 << 6) | (length & 0xf) as u8, (length >> 4) as u8],
);
}
3 => {
aml.splice(
position..position,
[
(2u8 << 6) | (length & 0xf) as u8,
(length >> 4) as u8,
(length >> 12) as u8,
],
);
}
_ => {
aml.splice(
position..position,
[
(3u8 << 6) | (length & 0xf) as u8,
(length >> 4) as u8,
(length >> 12) as u8,
(length >> 20) as u8,
],
);
}
}
}
fn insert_pkg_length(aml: &mut Vec<u8>, position: usize, len: usize) {
insert_length(aml, position, len, true);
}
fn append_pkg_length(aml: &mut Vec<u8>, len: usize) {
insert_length(aml, aml.len(), len, true);
}
fn append_named_field_length(aml: &mut Vec<u8>, len: usize) {
insert_length(aml, aml.len(), len, false);
}
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].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);
}
}
pub type Usize = usize;
impl Aml for Usize {
fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
#[cfg(target_pointer_width = "16")]
(*self as u16).to_aml_bytes(bytes);
#[cfg(target_pointer_width = "32")]
(*self as u32).to_aml_bytes(bytes);
#[cfg(target_pointer_width = "64")]
(*self as u64).to_aml_bytes(bytes);
}
}
fn append_aml_string(data: &mut Vec<u8>, v: &str) {
data.push(STRINGOP);
data.extend_from_slice(v.as_bytes());
data.push(0x0); }
pub type AmlStr = &'static str;
impl Aml for AmlStr {
fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
append_aml_string(bytes, self);
}
}
pub type AmlString = String;
impl Aml for AmlString {
fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
append_aml_string(bytes, self);
}
}
pub struct ResourceTemplate<'a> {
children: Vec<&'a dyn Aml>,
}
impl<'a> Aml for ResourceTemplate<'a> {
fn to_aml_bytes(&self, aml: &mut Vec<u8>) {
aml.push(BUFFEROP);
let pos = aml.len();
for child in &self.children {
child.to_aml_bytes(aml);
}
aml.push(ENDTAG);
aml.push(0); let buffer_length = aml.len() - pos;
let mut buffer_length_bytes = Vec::new();
buffer_length.to_aml_bytes(&mut buffer_length_bytes);
aml.splice(pos..pos, buffer_length_bytes);
let len = aml.len() - pos;
insert_pkg_length(aml, pos, len);
}
}
impl<'a> ResourceTemplate<'a> {
pub fn new(children: Vec<&'a dyn Aml>) -> Self {
ResourceTemplate { children }
}
}
pub struct Memory32Fixed {
read_write: bool, 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 to_aml_bytes(&self, bytes: &mut Vec<u8>) {
bytes.push(MEMORY32FIXEDDESC); bytes.extend_from_slice(&9u16.to_le_bytes());
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<T> {
type_: AddressSpaceType,
min: T,
max: T,
type_flags: u8,
}
impl<T> AddressSpace<T> {
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,
}
}
pub fn new_io(min: T, max: T) -> Self {
AddressSpace {
type_: AddressSpaceType::IO,
min,
max,
type_flags: 3, }
}
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); bytes.extend_from_slice(&(length as u16).to_le_bytes());
bytes.push(self.type_ as u8); let generic_flags = 1 << 2 | 1 << 3; 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, 3 + 5 * std::mem::size_of::<u16>(), );
bytes.extend_from_slice(&0u16.to_le_bytes()); bytes.extend_from_slice(&self.min.to_le_bytes()); bytes.extend_from_slice(&self.max.to_le_bytes()); bytes.extend_from_slice(&0u16.to_le_bytes()); let len = self.max - self.min + 1;
bytes.extend_from_slice(&len.to_le_bytes()); }
}
impl Aml for AddressSpace<u32> {
fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
self.push_header(
bytes,
DWORDADDRSPACEDESC, 3 + 5 * std::mem::size_of::<u32>(), );
bytes.extend_from_slice(&0u32.to_le_bytes()); bytes.extend_from_slice(&self.min.to_le_bytes()); bytes.extend_from_slice(&self.max.to_le_bytes()); bytes.extend_from_slice(&0u32.to_le_bytes()); let len = self.max - self.min + 1;
bytes.extend_from_slice(&len.to_le_bytes()); }
}
impl Aml for AddressSpace<u64> {
fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
self.push_header(
bytes,
QWORDADDRSPACEDESC, 3 + 5 * std::mem::size_of::<u64>(), );
bytes.extend_from_slice(&0u64.to_le_bytes()); bytes.extend_from_slice(&self.min.to_le_bytes()); bytes.extend_from_slice(&self.max.to_le_bytes()); bytes.extend_from_slice(&0u64.to_le_bytes()); let len = self.max - self.min + 1;
bytes.extend_from_slice(&len.to_le_bytes()); }
}
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 to_aml_bytes(&self, bytes: &mut Vec<u8>) {
bytes.push(IOPORTDESC); bytes.push(1); 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 to_aml_bytes(&self, bytes: &mut Vec<u8>) {
bytes.push(EXTIRQDESC); 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); 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 to_aml_bytes(&self, aml: &mut Vec<u8>) {
aml.push(EXTOPPREFIX); aml.push(DEVICEOP); let start = aml.len();
self.path.to_aml_bytes(aml);
for child in &self.children {
child.to_aml_bytes(aml);
}
let len = aml.len() - start;
insert_pkg_length(aml, start, len);
}
}
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 to_aml_bytes(&self, aml: &mut Vec<u8>) {
aml.push(SCOPEOP);
let start = aml.len();
self.path.to_aml_bytes(aml);
for child in &self.children {
child.to_aml_bytes(aml);
}
let len = aml.len() - start;
insert_pkg_length(aml, start, len);
}
}
impl<'a> Scope<'a> {
pub fn new(path: Path, children: Vec<&'a dyn Aml>) -> Self {
Scope { path, children }
}
pub fn raw(path: Path, mut children: Vec<u8>) -> Vec<u8> {
let mut bytes = Vec::new();
bytes.push(SCOPEOP);
let start = bytes.len();
path.to_aml_bytes(&mut bytes);
bytes.append(&mut children);
let len = bytes.len() - start;
insert_pkg_length(&mut bytes, start, len);
bytes
}
}
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 to_aml_bytes(&self, aml: &mut Vec<u8>) {
aml.push(METHODOP);
let start = aml.len();
self.path.to_aml_bytes(aml);
let flags: u8 = (self.args & 0x7) | (self.serialized as u8) << 3;
aml.push(flags);
for child in &self.children {
child.to_aml_bytes(aml);
}
let len = aml.len() - start;
insert_pkg_length(aml, start, len);
}
}
#[derive(Clone, Copy)]
pub enum FieldAccessType {
Any,
Byte,
Word,
DWord,
QWord,
Buffer,
}
#[derive(Clone, Copy)]
pub enum FieldLockRule {
NoLock = 0,
Lock = 1,
}
#[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<FieldEntry>,
access_type: FieldAccessType,
lock_rule: FieldLockRule,
update_rule: FieldUpdateRule,
}
impl Field {
pub fn new(
path: Path,
access_type: FieldAccessType,
lock_rule: FieldLockRule,
update_rule: FieldUpdateRule,
fields: Vec<FieldEntry>,
) -> Self {
Field {
path,
access_type,
lock_rule,
update_rule,
fields,
}
}
}
impl Aml for Field {
fn to_aml_bytes(&self, aml: &mut Vec<u8>) {
aml.push(EXTOPPREFIX);
aml.push(FIELDOP);
let start = aml.len();
self.path.to_aml_bytes(aml);
let flags: u8 =
self.access_type as u8 | (self.lock_rule as u8) << 4 | (self.update_rule as u8) << 5;
aml.push(flags);
for field in self.fields.iter() {
match field {
FieldEntry::Named(name, length) => {
aml.extend_from_slice(name);
append_named_field_length(aml, *length);
}
FieldEntry::Reserved(length) => {
aml.push(0x0);
append_named_field_length(aml, *length);
}
}
}
let len = aml.len() - start;
insert_pkg_length(aml, start, len);
}
}
#[derive(Clone, Copy)]
pub enum OpRegionSpace {
SystemMemory,
SystemIO,
PCIConfig,
EmbeddedControl,
SMBus,
SystemCMOS,
PciBarTarget,
IPMI,
GeneralPurposeIO,
GenericSerialBus,
}
pub struct OpRegion<'a> {
path: Path,
space: OpRegionSpace,
offset: &'a dyn Aml,
length: &'a dyn Aml,
}
impl<'a> OpRegion<'a> {
pub fn new(path: Path, space: OpRegionSpace, offset: &'a dyn Aml, length: &'a dyn Aml) -> Self {
OpRegion {
path,
space,
offset,
length,
}
}
}
impl<'a> Aml for OpRegion<'a> {
fn to_aml_bytes(&self, aml: &mut Vec<u8>) {
aml.push(EXTOPPREFIX);
aml.push(OPREGIONOP);
self.path.to_aml_bytes(aml);
aml.push(self.space as u8);
self.offset.to_aml_bytes(aml); self.length.to_aml_bytes(aml); }
}
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 to_aml_bytes(&self, aml: &mut Vec<u8>) {
aml.push(IFOP);
let start = aml.len();
self.predicate.to_aml_bytes(aml);
for child in self.if_children.iter() {
child.to_aml_bytes(aml);
}
let len = aml.len() - start;
insert_pkg_length(aml, start, len);
}
}
pub struct Else<'a> {
body: Vec<&'a dyn Aml>,
}
impl<'a> Else<'a> {
pub fn new(body: Vec<&'a dyn Aml>) -> Self {
Else { body }
}
}
impl<'a> Aml for Else<'a> {
fn to_aml_bytes(&self, aml: &mut Vec<u8>) {
aml.push(ELSEOP);
let start = aml.len();
for child in self.body.iter() {
child.to_aml_bytes(aml);
}
let len = aml.len() - start;
insert_pkg_length(aml, start, len);
}
}
macro_rules! compare_op {
($name:ident, $opcode:expr, $invert:expr) => {
pub struct $name<'a> {
right: &'a dyn Aml,
left: &'a dyn Aml,
}
impl<'a> $name<'a> {
pub fn new(left: &'a dyn Aml, right: &'a dyn Aml) -> Self {
$name { left, right }
}
}
impl<'a> Aml for $name<'a> {
fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
if $invert {
bytes.push(LNOTOP);
}
bytes.push($opcode);
self.left.to_aml_bytes(bytes);
self.right.to_aml_bytes(bytes);
}
}
};
}
compare_op!(Equal, LEQUALOP, false);
compare_op!(LessThan, LLESSOP, false);
compare_op!(GreaterThan, LGREATEROP, false);
compare_op!(NotEqual, LEQUALOP, true);
compare_op!(GreaterEqual, LLESSOP, true);
compare_op!(LessEqual, LGREATEROP, true);
pub struct Arg(pub u8);
impl Aml for Arg {
fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
assert!(self.0 <= 6);
bytes.push(ARG0OP + self.0);
}
}
pub struct Local(pub u8);
impl Aml for Local {
fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
assert!(self.0 <= 7);
bytes.push(LOCAL0OP + self.0);
}
}
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 to_aml_bytes(&self, bytes: &mut Vec<u8>) {
bytes.push(STOREOP);
self.value.to_aml_bytes(bytes);
self.name.to_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 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);
}
}
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 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());
}
}
pub struct Release {
mutex: Path,
}
impl Release {
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);
}
}
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 to_aml_bytes(&self, bytes: &mut Vec<u8>) {
bytes.push(NOTIFYOP);
self.object.to_aml_bytes(bytes);
self.value.to_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 to_aml_bytes(&self, aml: &mut Vec<u8>) {
aml.push(WHILEOP);
let start = aml.len();
self.predicate.to_aml_bytes(aml);
for child in self.while_children.iter() {
child.to_aml_bytes(aml);
}
let len = aml.len() - start;
insert_pkg_length(aml, start, len);
}
}
macro_rules! object_op {
($name:ident, $opcode:expr) => {
pub struct $name<'a> {
a: &'a dyn Aml,
}
impl<'a> $name<'a> {
pub fn new(a: &'a dyn Aml) -> Self {
$name { a }
}
}
impl<'a> Aml for $name<'a> {
fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
bytes.push($opcode);
self.a.to_aml_bytes(bytes);
}
}
};
}
object_op!(ObjectType, OBJECTTYPEOP);
object_op!(SizeOf, SIZEOFOP);
object_op!(Return, RETURNOP);
object_op!(DeRefOf, DEREFOFOP);
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 { target, a, b }
}
}
impl<'a> Aml for $name<'a> {
fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
bytes.push($opcode); 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);
binary_op!(CreateDWordField, CREATEDWFIELDOP);
binary_op!(CreateQWordField, CREATEQWFIELDOP);
macro_rules! convert_op {
($name:ident, $opcode:expr) => {
pub struct $name<'a> {
a: &'a dyn Aml,
target: &'a dyn Aml,
}
impl<'a> $name<'a> {
pub fn new(target: &'a dyn Aml, a: &'a dyn Aml) -> Self {
$name { target, a }
}
}
impl<'a> Aml for $name<'a> {
fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
bytes.push($opcode); self.a.to_aml_bytes(bytes);
self.target.to_aml_bytes(bytes);
}
}
};
}
convert_op!(ToBuffer, TOBUFFEROP);
convert_op!(ToInteger, TOINTEGEROP);
pub struct CreateField<'a> {
name_string: &'a dyn Aml,
source: &'a dyn Aml,
bit_index: &'a dyn Aml,
bit_num: &'a dyn Aml,
}
impl<'a> CreateField<'a> {
pub fn new(
name_string: &'a dyn Aml,
source: &'a dyn Aml,
bit_index: &'a dyn Aml,
bit_num: &'a dyn Aml,
) -> Self {
CreateField {
name_string,
source,
bit_index,
bit_num,
}
}
}
impl<'a> Aml for CreateField<'a> {
fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
bytes.push(EXTOPPREFIX);
bytes.push(CREATEFIELDOP);
self.source.to_aml_bytes(bytes);
self.bit_index.to_aml_bytes(bytes);
self.bit_num.to_aml_bytes(bytes);
self.name_string.to_aml_bytes(bytes);
}
}
pub struct Mid<'a> {
source: &'a dyn Aml,
index: &'a dyn Aml,
length: &'a dyn Aml,
result: &'a dyn Aml,
}
impl<'a> Mid<'a> {
pub fn new(
source: &'a dyn Aml,
index: &'a dyn Aml,
length: &'a dyn Aml,
result: &'a dyn Aml,
) -> Self {
Mid {
source,
index,
length,
result,
}
}
}
impl<'a> Aml for Mid<'a> {
fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
bytes.push(MIDOP);
self.source.to_aml_bytes(bytes);
self.index.to_aml_bytes(bytes);
self.length.to_aml_bytes(bytes);
self.result.to_aml_bytes(bytes);
}
}
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 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);
}
}
}
pub struct BufferTerm<'a> {
data: &'a dyn Aml,
}
impl<'a> BufferTerm<'a> {
pub fn new(data: &'a dyn Aml) -> Self {
BufferTerm { data }
}
}
impl<'a> Aml for BufferTerm<'a> {
fn to_aml_bytes(&self, aml: &mut Vec<u8>) {
aml.push(BUFFEROP);
let start = aml.len();
self.data.to_aml_bytes(aml);
let len = aml.len() - start;
insert_pkg_length(aml, start, len);
}
}
pub struct BufferData {
data: Vec<u8>,
}
impl BufferData {
pub fn new(data: Vec<u8>) -> Self {
BufferData { data }
}
}
impl Aml for BufferData {
fn to_aml_bytes(&self, aml: &mut Vec<u8>) {
aml.push(BUFFEROP);
let start = aml.len();
self.data.len().to_aml_bytes(aml);
aml.extend_from_slice(&self.data);
let len = aml.len() - start;
insert_pkg_length(aml, start, len);
}
}
pub struct Uuid {
name: BufferData,
}
fn hex2byte(v1: char, v2: char) -> u8 {
let hi = v1.to_digit(16).unwrap() as u8;
assert!(hi <= 15);
let lo = v2.to_digit(16).unwrap() as u8;
assert!(lo <= 15);
(hi << 4) | lo
}
impl Uuid {
pub fn new(name: &str) -> Self {
let name_vec: Vec<char> = name.chars().collect();
let mut data = Vec::new();
assert_eq!(name_vec.len(), 36);
assert_eq!(name_vec[8], '-');
assert_eq!(name_vec[13], '-');
assert_eq!(name_vec[18], '-');
assert_eq!(name_vec[23], '-');
data.push(hex2byte(name_vec[6], name_vec[7]));
data.push(hex2byte(name_vec[4], name_vec[5]));
data.push(hex2byte(name_vec[2], name_vec[3]));
data.push(hex2byte(name_vec[0], name_vec[1]));
data.push(hex2byte(name_vec[11], name_vec[12]));
data.push(hex2byte(name_vec[9], name_vec[10]));
data.push(hex2byte(name_vec[16], name_vec[17]));
data.push(hex2byte(name_vec[14], name_vec[15]));
data.push(hex2byte(name_vec[19], name_vec[20]));
data.push(hex2byte(name_vec[21], name_vec[22]));
data.push(hex2byte(name_vec[24], name_vec[25]));
data.push(hex2byte(name_vec[26], name_vec[27]));
data.push(hex2byte(name_vec[28], name_vec[29]));
data.push(hex2byte(name_vec[30], name_vec[31]));
data.push(hex2byte(name_vec[32], name_vec[33]));
data.push(hex2byte(name_vec[34], name_vec[35]));
Uuid {
name: BufferData::new(data),
}
}
}
impl Aml for Uuid {
fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
self.name.to_aml_bytes(bytes)
}
}
pub struct PowerResource<'a> {
name: Path,
level: u8,
order: u16,
children: Vec<&'a dyn Aml>,
}
impl<'a> PowerResource<'a> {
pub fn new(name: Path, level: u8, order: u16, children: Vec<&'a dyn Aml>) -> Self {
PowerResource {
name,
level,
order,
children,
}
}
}
impl<'a> Aml for PowerResource<'a> {
fn to_aml_bytes(&self, aml: &mut Vec<u8>) {
aml.push(EXTOPPREFIX);
aml.push(POWERRESOURCEOP);
let start = aml.len();
self.name.to_aml_bytes(aml);
aml.push(self.level);
let orders = self.order.to_le_bytes();
aml.push(orders[0]);
aml.push(orders[1]);
for child in &self.children {
child.to_aml_bytes(aml);
}
let len = aml.len() - start;
insert_pkg_length(aml, start, len);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_device() {
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() {
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() {
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);
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);
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[..]);
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[..]);
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[..]);
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() {
let mut pkg_len_62 = Vec::new();
insert_pkg_length(&mut pkg_len_62, 0, 62);
assert_eq!(pkg_len_62, [63]);
let mut pkg_len_64 = Vec::new();
insert_pkg_length(&mut pkg_len_64, 0, 64);
assert_eq!(pkg_len_64, [1 << 6 | (66 & 0xf), 66 >> 4]);
let mut pkg_len_4096 = Vec::new();
insert_pkg_length(&mut pkg_len_4096, 0, 4096);
assert_eq!(
pkg_len_4096,
[
2 << 6 | (4099 & 0xf) as u8,
(4099 >> 4) as u8,
(4099 >> 12) as u8
]
);
}
#[test]
fn test_package() {
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]);
aml.clear();
0x00_u8.to_aml_bytes(&mut aml);
assert_eq!(aml, [0x00]);
aml.clear();
0x01_u8.to_aml_bytes(&mut aml);
assert_eq!(aml, [0x01]);
aml.clear();
0x86_u8.to_aml_bytes(&mut aml);
assert_eq!(aml, [0x0a, 0x86]);
aml.clear();
0x00_u16.to_aml_bytes(&mut aml);
assert_eq!(aml, [0x00]);
aml.clear();
0x01_u16.to_aml_bytes(&mut aml);
assert_eq!(aml, [0x01]);
aml.clear();
0x86_u16.to_aml_bytes(&mut aml);
assert_eq!(aml, [0x0a, 0x86]);
aml.clear();
0xF00D_u16.to_aml_bytes(&mut aml);
assert_eq!(aml, [0x0b, 0x0d, 0xf0]);
aml.clear();
0x00_u32.to_aml_bytes(&mut aml);
assert_eq!(aml, [0x00]);
aml.clear();
0x01_u32.to_aml_bytes(&mut aml);
assert_eq!(aml, [0x01]);
aml.clear();
0x86_u32.to_aml_bytes(&mut aml);
assert_eq!(aml, [0x0a, 0x86]);
aml.clear();
0xF00D_u32.to_aml_bytes(&mut aml);
assert_eq!(aml, [0x0b, 0x0d, 0xf0]);
aml.clear();
0xDECAF_u32.to_aml_bytes(&mut aml);
assert_eq!(aml, [0x0c, 0xaf, 0xec, 0x0d, 0x00]);
aml.clear();
0x00_u64.to_aml_bytes(&mut aml);
assert_eq!(aml, [0x00]);
aml.clear();
0x01_u64.to_aml_bytes(&mut aml);
assert_eq!(aml, [0x01]);
aml.clear();
0x86_u64.to_aml_bytes(&mut aml);
assert_eq!(aml, [0x0a, 0x86]);
aml.clear();
0xF00D_u64.to_aml_bytes(&mut aml);
assert_eq!(aml, [0x0b, 0x0d, 0xf0]);
aml.clear();
0xDECAF_u64.to_aml_bytes(&mut aml);
assert_eq!(aml, [0x0c, 0xaf, 0xec, 0x0d, 0x00]);
aml.clear();
0xDECAFC0FFEE_u64.to_aml_bytes(&mut aml);
assert_eq!(aml, [0x0e, 0xee, 0xff, 0xc0, 0xaf, 0xec, 0x0d, 0x00, 0x00]);
aml.clear();
0x00_usize.to_aml_bytes(&mut aml);
assert_eq!(aml, [0x00]);
aml.clear();
0x01_usize.to_aml_bytes(&mut aml);
assert_eq!(aml, [0x01]);
aml.clear();
0x86_usize.to_aml_bytes(&mut aml);
assert_eq!(aml, [0x0a, 0x86]);
aml.clear();
0xF00D_usize.to_aml_bytes(&mut aml);
assert_eq!(aml, [0x0b, 0x0d, 0xf0]);
aml.clear();
0xDECAF_usize.to_aml_bytes(&mut aml);
assert_eq!(aml, [0x0c, 0xaf, 0xec, 0x0d, 0x00]);
aml.clear();
#[cfg(target_pointer_width = "64")]
{
0xDECAFC0FFEE_usize.to_aml_bytes(&mut aml);
assert_eq!(aml, [0x0e, 0xee, 0xff, 0xc0, 0xaf, 0xec, 0x0d, 0x00, 0x00]);
aml.clear();
}
}
#[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, 0x2F, 0x03, 0x5F, 0x53, 0x42, 0x5F, 0x50, 0x43, 0x49, 0x30, 0x5F, 0x55, 0x49, 0x44, 0x0b, 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() {
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,
FieldLockRule::NoLock,
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[..]);
let field_data = [
0x5Bu8, 0x81, 0x12, 0x50, 0x52, 0x53, 0x54, 0x13, 0x43, 0x53, 0x45, 0x4C, 0x20, 0x00,
0x20, 0x43, 0x44, 0x41, 0x54, 0x20,
];
aml.clear();
Field::new(
"PRST".into(),
FieldAccessType::DWord,
FieldLockRule::Lock,
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() {
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_usize,
&0xc_usize,
)
.to_aml_bytes(&mut aml);
assert_eq!(aml, &op_region_data[..]);
}
#[test]
fn test_arg_if() {
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() {
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() {
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() {
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, ¬ify_data[..]);
}
#[test]
fn test_while() {
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() {
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() {
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(),
&BufferData::new(vec![0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00]),
)
.to_aml_bytes(&mut aml);
assert_eq!(aml, &buffer_data[..])
}
}