// Copyright © 2019 Intel Corporation // // SPDX-License-Identifier: Apache-2.0 // pub trait Aml { fn to_bytes(&self) -> Vec; } pub struct Path { root: bool, name_parts: Vec<[u8; 4]>, } impl Aml for Path { fn to_bytes(&self) -> Vec { let mut bytes = Vec::new(); 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.append(&mut part.to_vec()); } bytes } } 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_bytes(&self) -> Vec { let mut bytes = Vec::new(); bytes.push(0x0a); /* BytePrefix */ bytes.push(*self); bytes } } pub type Word = u16; impl Aml for Word { fn to_bytes(&self) -> Vec { let mut bytes = Vec::new(); bytes.push(0x0bu8); /* WordPrefix */ bytes.append(&mut self.to_le_bytes().to_vec()); bytes } } pub type DWord = u32; impl Aml for DWord { fn to_bytes(&self) -> Vec { let mut bytes = Vec::new(); bytes.push(0x0c); /* DWordPrefix */ bytes.append(&mut self.to_le_bytes().to_vec()); bytes } } pub type QWord = u64; impl Aml for QWord { fn to_bytes(&self) -> Vec { let mut bytes = Vec::new(); bytes.push(0x0e); /* QWordPrefix */ bytes.append(&mut self.to_le_bytes().to_vec()); bytes } } pub struct Name { bytes: Vec, } impl Aml for Name { fn to_bytes(&self) -> Vec { self.bytes.clone() } } impl Name { pub fn new(path: Path, inner: &dyn Aml) -> Self { let mut bytes = Vec::new(); bytes.push(0x08); /* NameOp */ bytes.append(&mut path.to_bytes()); bytes.append(&mut inner.to_bytes()); Name { bytes } } } pub struct Package<'a> { children: Vec<&'a dyn Aml>, } impl<'a> Aml for Package<'a> { fn to_bytes(&self) -> Vec { let mut bytes = Vec::new(); bytes.push(self.children.len() as u8); for child in &self.children { bytes.append(&mut child.to_bytes()); } let mut pkg_length = create_pkg_length(&bytes); pkg_length.reverse(); for byte in pkg_length { bytes.insert(0, byte); } bytes.insert(0, 0x12); /* PackageOp */ bytes } } 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." */ fn create_pkg_length(data: &[u8]) -> 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() + length_length; 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 to_bytes(&self) -> Vec { self.value.to_bytes() } } #[cfg(test)] mod tests { use super::*; #[test] fn test_pkg_length() { assert_eq!(create_pkg_length(&[0u8; 62].to_vec()), vec![63]); assert_eq!( create_pkg_length(&[0u8; 64].to_vec()), vec![1 << 6 | (66 & 0xf), 66 >> 4] ); assert_eq!( create_pkg_length(&[0u8; 4096].to_vec()), 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_bytes()); } #[test] fn test_eisa_name() { assert_eq!( Name::new("_HID".into(), &EISAName::new("PNP0501")).to_bytes(), [0x08, 0x5F, 0x48, 0x49, 0x44, 0x0C, 0x41, 0xD0, 0x05, 0x01], ) } #[test] fn test_name_path() { assert_eq!( (&"_SB_".into() as &Path).to_bytes(), [0x5Fu8, 0x53, 0x42, 0x5F] ); assert_eq!( (&"\\_SB_".into() as &Path).to_bytes(), [0x5C, 0x5F, 0x53, 0x42, 0x5F] ); assert_eq!( (&"_SB_.COM1".into() as &Path).to_bytes(), [0x2E, 0x5F, 0x53, 0x42, 0x5F, 0x43, 0x4F, 0x4D, 0x31] ); assert_eq!( (&"_SB_.PCI0._HID".into() as &Path).to_bytes(), [0x2F, 0x03, 0x5F, 0x53, 0x42, 0x5F, 0x50, 0x43, 0x49, 0x30, 0x5F, 0x48, 0x49, 0x44] ); } #[test] fn test_numbers() { assert_eq!(128u8.to_bytes(), [0x0a, 0x80]); assert_eq!(1024u16.to_bytes(), [0x0b, 0x0, 0x04]); assert_eq!((16u32 << 20).to_bytes(), [0x0c, 0x00, 0x00, 0x0, 0x01]); assert_eq!( 0xdeca_fbad_deca_fbadu64.to_bytes(), [0x0e, 0xad, 0xfb, 0xca, 0xde, 0xad, 0xfb, 0xca, 0xde] ); } #[test] fn test_name() { assert_eq!( Name::new("_SB_.PCI0._UID".into(), &0x1234u16).to_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 ] ); } }