use crate::{name_object::AmlName, AmlError}; use alloc::{boxed::Box, string::String, vec::Vec}; use bit_field::BitField; #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum RegionSpace { SystemMemory, SystemIo, PciConfig, EmbeddedControl, SMBus, SystemCmos, PciBarTarget, IPMI, GeneralPurposeIo, GenericSerialBus, OemDefined(u8), } #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum FieldAccessType { Any, Byte, Word, DWord, QWord, Buffer, Reserved, } #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum FieldUpdateRule { Preserve, WriteAsOnes, WriteAsZeros, } // TODO: custom debug impl #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub struct FieldFlags(u8); impl FieldFlags { pub fn new(value: u8) -> FieldFlags { FieldFlags(value) } pub fn access_type(&self) -> Result { match self.0.get_bits(0..4) { 0 => Ok(FieldAccessType::Any), 1 => Ok(FieldAccessType::Byte), 2 => Ok(FieldAccessType::Word), 3 => Ok(FieldAccessType::DWord), 4 => Ok(FieldAccessType::QWord), 5 => Ok(FieldAccessType::Buffer), _ => Err(AmlError::InvalidFieldFlags), } } pub fn lock_rule(&self) -> bool { self.0.get_bit(4) } pub fn field_update_rule(&self) -> Result { match self.0.get_bits(5..7) { 0 => Ok(FieldUpdateRule::Preserve), 1 => Ok(FieldUpdateRule::WriteAsOnes), 2 => Ok(FieldUpdateRule::WriteAsZeros), _ => Err(AmlError::InvalidFieldFlags), } } } #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub struct MethodFlags(u8); impl MethodFlags { pub fn new(value: u8) -> MethodFlags { MethodFlags(value) } pub fn arg_count(&self) -> u8 { self.0.get_bits(0..3) } pub fn serialize(&self) -> bool { self.0.get_bit(3) } pub fn sync_level(&self) -> u8 { self.0.get_bits(4..8) } } #[derive(Clone, PartialEq, Eq, Debug)] pub enum AmlValue { Integer(u64), String(String), Name(Box), OpRegion { region: RegionSpace, offset: u64, length: u64 }, Field { region: AmlName, flags: FieldFlags, offset: u64, length: u64 }, Device, Method { flags: MethodFlags, code: Vec }, Buffer { bytes: Vec, size: u64 }, Processor { id: u8, pblk_address: u32, pblk_len: u8 }, Mutex { sync_level: u8 }, Package(Vec), } impl AmlValue { pub fn as_integer(&self) -> Result { match self { AmlValue::Integer(value) => Ok(*value), AmlValue::Buffer { size, ref bytes } => { /* * "The first 8 bytes of the buffer are converted to an integer, taking the first * byte as the least significant byte of the integer. A zero-length buffer is * illegal." - ยง19.6.140 * * XXX: We return `0` for zero-length buffers because they literally occur in * the reference implementation. */ let bytes = if bytes.len() > 8 { &bytes[0..8] } else { bytes }; Ok(bytes.iter().rev().fold(0: u64, |mut i, &popped| { i <<= 8; i += popped as u64; i })) } _ => Err(AmlError::IncompatibleValueConversion), } } }