use std::collections::BTreeMap; use core::fmt::Debug; use core::str::FromStr; use super::termlist::parse_term_list; use super::namedobj::{ RegionSpace, FieldFlags }; use super::parser::{AmlExecutionContext, ExecutionState}; use super::AmlError; use crate::acpi::{AcpiContext, SdtSignature}; #[derive(Clone, Debug)] pub enum FieldSelector { Region(String), Bank { region: String, bank_register: String, bank_selector: Box }, Index { index_selector: String, data_selector: String } } #[derive(Clone, Debug)] pub enum ObjectReference { ArgObj(u8), LocalObj(u8), Object(String), Index(Box, Box) } #[derive(Clone, Debug)] pub struct Method { pub arg_count: u8, pub serialized: bool, pub sync_level: u8, pub term_list: Vec } #[derive(Clone, Debug)] pub struct BufferField { pub source_buf: Box, pub index: Box, pub length: Box } #[derive(Clone, Debug)] pub struct FieldUnit { pub selector: FieldSelector, pub connection: Box, pub flags: FieldFlags, pub offset: usize, pub length: usize } #[derive(Clone, Debug)] pub struct Device { pub obj_list: Vec, pub notify_methods: BTreeMap> } #[derive(Clone, Debug)] pub struct ThermalZone { pub obj_list: Vec, pub notify_methods: BTreeMap> } #[derive(Clone, Debug)] pub struct Processor { pub proc_id: u8, pub p_blk: Option, pub obj_list: Vec, pub notify_methods: BTreeMap> } #[derive(Clone, Debug)] pub struct OperationRegion { pub region: RegionSpace, pub offset: Box, pub len: Box, pub accessor: Accessor, pub accessed_by: Option } #[derive(Clone, Debug)] pub struct PowerResource { pub system_level: u8, pub resource_order: u16, pub obj_list: Vec } #[derive(Debug)] pub struct Accessor { pub read: fn(usize) -> u64, pub write: fn(usize, u64) } impl Clone for Accessor { fn clone(&self) -> Accessor { Accessor { read: (*self).read, write: (*self).write } } } #[derive(Clone, Debug)] pub enum AmlValue { None, Uninitialized, Alias(String), Buffer(Vec), BufferField(BufferField), DDBHandle((Vec, SdtSignature)), DebugObject, Device(Device), Event(u64), FieldUnit(FieldUnit), Integer(u64), IntegerConstant(u64), Method(Method), Mutex((u8, Option)), ObjectReference(ObjectReference), OperationRegion(OperationRegion), Package(Vec), String(String), PowerResource(PowerResource), Processor(Processor), RawDataBuffer(Vec), ThermalZone(ThermalZone) } impl AmlValue { pub fn get_type_string(&self) -> String { match *self { AmlValue::Uninitialized => String::from_str("[Uninitialized Object]").unwrap(), AmlValue::Integer(_) => String::from_str("[Integer]").unwrap(), AmlValue::String(_) => String::from_str("[String]").unwrap(), AmlValue::Buffer(_) => String::from_str("[Buffer]").unwrap(), AmlValue::Package(_) => String::from_str("[Package]").unwrap(), AmlValue::FieldUnit(_) => String::from_str("[Field]").unwrap(), AmlValue::Device(_) => String::from_str("[Device]").unwrap(), AmlValue::Event(_) => String::from_str("[Event]").unwrap(), AmlValue::Method(_) => String::from_str("[Control Method]").unwrap(), AmlValue::Mutex(_) => String::from_str("[Mutex]").unwrap(), AmlValue::OperationRegion(_) => String::from_str("[Operation Region]").unwrap(), AmlValue::PowerResource(_) => String::from_str("[Power Resource]").unwrap(), AmlValue::Processor(_) => String::from_str("[Processor]").unwrap(), AmlValue::ThermalZone(_) => String::from_str("[Thermal Zone]").unwrap(), AmlValue::BufferField(_) => String::from_str("[Buffer Field]").unwrap(), AmlValue::DDBHandle(_) => String::from_str("[DDB Handle]").unwrap(), AmlValue::DebugObject => String::from_str("[Debug Object]").unwrap(), _ => String::new() } } pub fn get_as_type(&self, ctx: &AcpiContext, t: AmlValue) -> Result { match t { AmlValue::None => Ok(AmlValue::None), AmlValue::Uninitialized => Ok(self.clone()), AmlValue::Alias(_) => match *self { AmlValue::Alias(_) => Ok(self.clone()), _ => Err(AmlError::AmlValueError) }, AmlValue::Buffer(_) => Ok(AmlValue::Buffer(self.get_as_buffer(ctx)?)), AmlValue::BufferField(_) => Ok(AmlValue::BufferField(self.get_as_buffer_field(ctx)?)), AmlValue::DDBHandle(_) => Ok(AmlValue::DDBHandle(self.get_as_ddb_handle(ctx)?)), AmlValue::DebugObject => match *self { AmlValue::DebugObject => Ok(self.clone()), _ => Err(AmlError::AmlValueError) }, AmlValue::Device(_) => Ok(AmlValue::Device(self.get_as_device()?)), AmlValue::Event(_) => Ok(AmlValue::Event(self.get_as_event()?)), AmlValue::FieldUnit(_) => Ok(AmlValue::FieldUnit(self.get_as_field_unit()?)), AmlValue::Integer(_) => Ok(AmlValue::Integer(self.get_as_integer(ctx)?)), AmlValue::IntegerConstant(_) => Ok(AmlValue::IntegerConstant(self.get_as_integer_constant()?)), AmlValue::Method(_) => Ok(AmlValue::Method(self.get_as_method()?)), AmlValue::Mutex(_) => Ok(AmlValue::Mutex(self.get_as_mutex()?)), AmlValue::ObjectReference(_) => Ok(AmlValue::ObjectReference(self.get_as_object_reference()?)), AmlValue::OperationRegion(_) => match *self { AmlValue::OperationRegion(_) => Ok(self.clone()), _ => Err(AmlError::AmlValueError) }, AmlValue::Package(_) => Ok(AmlValue::Package(self.get_as_package()?)), AmlValue::String(_) => Ok(AmlValue::String(self.get_as_string(ctx)?)), AmlValue::PowerResource(_) => Ok(AmlValue::PowerResource(self.get_as_power_resource()?)), AmlValue::Processor(_) => Ok(AmlValue::Processor(self.get_as_processor()?)), AmlValue::RawDataBuffer(_) => Ok(AmlValue::RawDataBuffer(self.get_as_raw_data_buffer()?)), AmlValue::ThermalZone(_) => Ok(AmlValue::ThermalZone(self.get_as_thermal_zone()?)) } } pub fn get_as_buffer(&self, ctx: &AcpiContext) -> Result, AmlError> { match *self { AmlValue::Buffer(ref b) => Ok(b.clone()), AmlValue::Integer(ref i) => { let mut v: Vec = vec!(); let mut i = i.clone(); while i != 0 { v.push((i & 0xFF) as u8); i >>= 8; } while v.len() < 8 { v.push(0); } Ok(v) }, AmlValue::String(ref s) => { Ok(s.clone().into_bytes()) }, AmlValue::BufferField(ref b) => { let buf = b.source_buf.get_as_buffer(ctx)?; let idx = b.index.get_as_integer(ctx)? as usize; let len = b.length.get_as_integer(ctx)? as usize; if idx + len > buf.len() { return Err(AmlError::AmlValueError); } Ok(buf[idx .. idx + len].to_vec()) }, _ => Err(AmlError::AmlValueError) } } pub fn get_as_buffer_field(&self, acpi_ctx: &AcpiContext) -> Result { match *self { AmlValue::BufferField(ref b) => Ok(b.clone()), _ => { let raw_buf = self.get_as_buffer(acpi_ctx)?; let buf = Box::new(AmlValue::Buffer(raw_buf.clone())); let idx = Box::new(AmlValue::IntegerConstant(0)); let len = Box::new(AmlValue::Integer(raw_buf.len() as u64)); Ok(BufferField { source_buf: buf, index: idx, length: len }) } } } pub fn get_as_ddb_handle(&self, acpi_ctx: &AcpiContext) -> Result<(Vec, SdtSignature), AmlError> { match *self { AmlValue::DDBHandle(ref v) => Ok(v.clone()), AmlValue::Integer(i) => if let Some(sig) = acpi_ctx.get_signature_from_index(i as usize) { Ok((vec!(), sig)) } else { log::error!("AmlValueError in get_as_ddb_handle integer"); Err(AmlError::AmlValueError) }, _ => { log::error!("AmlValueError in get_as_ddb_handle other"); Err(AmlError::AmlValueError) } } } pub fn get_as_device(&self) -> Result { match *self { AmlValue::Device(ref s) => Ok(s.clone()), _ => Err(AmlError::AmlValueError) } } pub fn get_as_event(&self) -> Result { match *self { AmlValue::Event(ref e) => Ok(e.clone()), _ => Err(AmlError::AmlValueError) } } pub fn get_as_field_unit(&self) -> Result { match *self { AmlValue::FieldUnit(ref e) => Ok(e.clone()), _ => Err(AmlError::AmlValueError) } } pub fn get_as_integer(&self, acpi_ctx: &AcpiContext) -> Result { match *self { AmlValue::IntegerConstant(ref i) => Ok(i.clone()), AmlValue::Integer(ref i) => Ok(i.clone()), AmlValue::Buffer(ref b) => { let mut b = b.clone(); if b.len() > 8 { return Err(AmlError::AmlValueError); } let mut i: u64 = 0; while b.len() > 0 { i <<= 8; i += b.pop().expect("Won't happen") as u64; } Ok(i) }, AmlValue::BufferField(_) => { let mut b = self.get_as_buffer(acpi_ctx)?; if b.len() > 8 { return Err(AmlError::AmlValueError); } let mut i: u64 = 0; while b.len() > 0 { i <<= 8; i += b.pop().expect("Won't happen") as u64; } Ok(i) }, AmlValue::DDBHandle(ref v) => if let Some(idx) = acpi_ctx.get_index_from_signature(&v.1) { Ok(idx as u64) } else { Err(AmlError::AmlValueError) }, AmlValue::String(ref s) => { let s = s.clone()[0..8].to_string().to_uppercase(); let mut i: u64 = 0; for c in s.chars() { if !c.is_digit(16) { break; } i <<= 8; i += c.to_digit(16).unwrap() as u64; } Ok(i) }, _ => Err(AmlError::AmlValueError) } } pub fn get_as_integer_constant(&self) -> Result { match *self { AmlValue::IntegerConstant(ref i) => Ok(i.clone()), _ => Err(AmlError::AmlValueError) } } pub fn get_as_method(&self) -> Result { match *self { AmlValue::Method(ref m) => Ok(m.clone()), _ => Err(AmlError::AmlValueError) } } pub fn get_as_mutex(&self) -> Result<(u8, Option), AmlError> { match *self { AmlValue::Mutex(ref m) => Ok(m.clone()), _ => Err(AmlError::AmlValueError) } } pub fn get_as_object_reference(&self) -> Result { match *self { AmlValue::ObjectReference(ref m) => Ok(m.clone()), _ => Err(AmlError::AmlValueError) } } /* pub fn get_as_operation_region(&self) -> Result { match *self { AmlValue::OperationRegion(ref p) => Ok(p.clone()), _ => Err(AmlError::AmlValueError) } } */ pub fn get_as_package(&self) -> Result, AmlError> { match *self { AmlValue::Package(ref p) => Ok(p.clone()), _ => Err(AmlError::AmlValueError) } } pub fn get_as_string(&self, ctx: &AcpiContext) -> Result { match *self { AmlValue::String(ref s) => Ok(s.clone()), AmlValue::Integer(ref i) => Ok(format!("{:X}", i)), AmlValue::IntegerConstant(ref i) => Ok(format!("{:X}", i)), AmlValue::Buffer(ref b) => Ok(String::from_utf8(b.clone()).expect("Invalid UTF-8")), AmlValue::BufferField(_) => { let b = self.get_as_buffer(ctx)?; Ok(String::from_utf8(b).expect("Invalid UTF-8")) }, _ => Err(AmlError::AmlValueError) } } pub fn get_as_power_resource(&self) -> Result { match *self { AmlValue::PowerResource(ref p) => Ok(p.clone()), _ => Err(AmlError::AmlValueError) } } pub fn get_as_processor(&self) -> Result { match *self { AmlValue::Processor(ref p) => Ok(p.clone()), _ => Err(AmlError::AmlValueError) } } pub fn get_as_raw_data_buffer(&self) -> Result, AmlError> { match *self { AmlValue::RawDataBuffer(ref p) => Ok(p.clone()), _ => Err(AmlError::AmlValueError) } } pub fn get_as_thermal_zone(&self) -> Result { match *self { AmlValue::ThermalZone(ref p) => Ok(p.clone()), _ => Err(AmlError::AmlValueError) } } } impl Method { pub fn execute(&self, acpi_ctx: &AcpiContext, scope: String, parameters: Vec) -> AmlValue { let mut ctx = AmlExecutionContext::new(acpi_ctx, scope); ctx.init_arg_vars(parameters); let _ = parse_term_list(&self.term_list[..], &mut ctx); ctx.clean_namespace(acpi_ctx); match ctx.state { ExecutionState::RETURN(v) => v, _ => AmlValue::IntegerConstant(0) } } } pub fn get_namespace_string(ctx: &AcpiContext, current: String, modifier_v: AmlValue) -> Result { let mut modifier = modifier_v.get_as_string(ctx)?; if current.len() == 0 { return Ok(modifier); } if modifier.len() == 0 { return Ok(current); } if modifier.starts_with("\\") { return Ok(modifier); } let mut namespace = current.clone(); if modifier.starts_with("^") { while modifier.starts_with("^") { modifier = modifier[1..].to_string(); if namespace.ends_with("\\") { return Err(AmlError::AmlValueError); } loop { if namespace.ends_with(".") { namespace.pop(); break; } if namespace.pop() == None { return Err(AmlError::AmlValueError); } } } } if !namespace.ends_with("\\") { namespace.push('.'); } Ok(namespace + &modifier) }