2019-10-16 14:47:10 +00:00
|
|
|
// Copyright © 2019 Intel Corporation
|
|
|
|
//
|
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
//
|
|
|
|
|
|
|
|
pub trait Aml {
|
|
|
|
fn to_bytes(&self) -> Vec<u8>;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Path {
|
|
|
|
root: bool,
|
|
|
|
name_parts: Vec<[u8; 4]>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Aml for Path {
|
|
|
|
fn to_bytes(&self) -> Vec<u8> {
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-16 16:42:31 +00:00
|
|
|
pub type Byte = u8;
|
2019-10-16 16:25:53 +00:00
|
|
|
|
2019-10-16 16:42:31 +00:00
|
|
|
impl Aml for Byte {
|
2019-10-16 16:25:53 +00:00
|
|
|
fn to_bytes(&self) -> Vec<u8> {
|
|
|
|
let mut bytes = Vec::new();
|
|
|
|
bytes.push(0x0a); /* BytePrefix */
|
|
|
|
bytes.push(*self);
|
|
|
|
bytes
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-16 16:42:31 +00:00
|
|
|
pub type Word = u16;
|
2019-10-16 16:25:53 +00:00
|
|
|
|
2019-10-16 16:42:31 +00:00
|
|
|
impl Aml for Word {
|
2019-10-16 16:25:53 +00:00
|
|
|
fn to_bytes(&self) -> Vec<u8> {
|
|
|
|
let mut bytes = Vec::new();
|
|
|
|
bytes.push(0x0bu8); /* WordPrefix */
|
|
|
|
bytes.append(&mut self.to_le_bytes().to_vec());
|
|
|
|
bytes
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-16 16:42:31 +00:00
|
|
|
pub type DWord = u32;
|
2019-10-16 16:25:53 +00:00
|
|
|
|
2019-10-16 16:42:31 +00:00
|
|
|
impl Aml for DWord {
|
2019-10-16 16:25:53 +00:00
|
|
|
fn to_bytes(&self) -> Vec<u8> {
|
|
|
|
let mut bytes = Vec::new();
|
|
|
|
bytes.push(0x0c); /* DWordPrefix */
|
|
|
|
bytes.append(&mut self.to_le_bytes().to_vec());
|
|
|
|
bytes
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-16 16:42:31 +00:00
|
|
|
pub type QWord = u64;
|
2019-10-16 16:25:53 +00:00
|
|
|
|
2019-10-16 16:42:31 +00:00
|
|
|
impl Aml for QWord {
|
2019-10-16 16:25:53 +00:00
|
|
|
fn to_bytes(&self) -> Vec<u8> {
|
|
|
|
let mut bytes = Vec::new();
|
|
|
|
bytes.push(0x0e); /* QWordPrefix */
|
|
|
|
bytes.append(&mut self.to_le_bytes().to_vec());
|
|
|
|
bytes
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-16 16:42:31 +00:00
|
|
|
pub struct Name {
|
|
|
|
bytes: Vec<u8>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Aml for Name {
|
|
|
|
fn to_bytes(&self) -> Vec<u8> {
|
|
|
|
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 }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-18 14:27:33 +00:00
|
|
|
pub struct Package<'a> {
|
|
|
|
children: Vec<&'a dyn Aml>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Aml for Package<'a> {
|
|
|
|
fn to_bytes(&self) -> Vec<u8> {
|
|
|
|
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<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() + 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
|
|
|
|
}
|
|
|
|
|
2019-10-18 16:26:56 +00:00
|
|
|
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<u8> {
|
|
|
|
self.value.to_bytes()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-18 17:12:53 +00:00
|
|
|
fn create_integer(v: usize) -> Vec<u8> {
|
|
|
|
if v <= u8::max_value().into() {
|
|
|
|
(v as u8).to_bytes()
|
|
|
|
} else if v <= u16::max_value().into() {
|
|
|
|
(v as u16).to_bytes()
|
|
|
|
} else if v <= u32::max_value() as usize {
|
|
|
|
(v as u32).to_bytes()
|
|
|
|
} else {
|
|
|
|
(v as u64).to_bytes()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub type Usize = usize;
|
|
|
|
|
|
|
|
impl Aml for Usize {
|
|
|
|
fn to_bytes(&self) -> Vec<u8> {
|
|
|
|
create_integer(*self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct ResourceTemplate<'a> {
|
|
|
|
children: Vec<&'a dyn Aml>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Aml for ResourceTemplate<'a> {
|
|
|
|
fn to_bytes(&self) -> Vec<u8> {
|
|
|
|
let mut bytes = Vec::new();
|
|
|
|
|
|
|
|
// Add buffer data
|
|
|
|
for child in &self.children {
|
|
|
|
bytes.append(&mut child.to_bytes());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Mark with end and mark checksum as as always valid
|
|
|
|
bytes.push(0x79); /* 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 = bytes.len().to_bytes();
|
|
|
|
buffer_length.reverse();
|
|
|
|
for byte in buffer_length {
|
|
|
|
bytes.insert(0, byte);
|
|
|
|
}
|
|
|
|
|
|
|
|
// PkgLength is everything else
|
|
|
|
let mut pkg_length = create_pkg_length(&bytes);
|
|
|
|
pkg_length.reverse();
|
|
|
|
for byte in pkg_length {
|
|
|
|
bytes.insert(0, byte);
|
|
|
|
}
|
|
|
|
|
|
|
|
bytes.insert(0, 0x11); /* BufferOp */
|
|
|
|
|
|
|
|
bytes
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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 to_bytes(&self) -> Vec<u8> {
|
|
|
|
let mut bytes = Vec::new();
|
|
|
|
|
|
|
|
bytes.push(0x86); /* Memory32Fixed */
|
|
|
|
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());
|
|
|
|
bytes
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-16 14:47:10 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
|
2019-10-18 17:12:53 +00:00
|
|
|
#[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_bytes(),
|
|
|
|
crs_memory_32_fixed
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-10-18 14:27:33 +00:00
|
|
|
#[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());
|
|
|
|
}
|
|
|
|
|
2019-10-18 16:26:56 +00:00
|
|
|
#[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],
|
|
|
|
)
|
|
|
|
}
|
2019-10-16 14:47:10 +00:00
|
|
|
#[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]
|
|
|
|
);
|
|
|
|
}
|
2019-10-16 16:25:53 +00:00
|
|
|
|
|
|
|
#[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]
|
|
|
|
);
|
|
|
|
}
|
2019-10-16 16:42:31 +00:00
|
|
|
|
|
|
|
#[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
|
|
|
|
]
|
|
|
|
);
|
|
|
|
}
|
2019-10-16 14:47:10 +00:00
|
|
|
}
|