diff --git a/src/acpi/aml/dataobj.rs b/src/acpi/aml/dataobj.rs new file mode 100644 index 0000000000000000000000000000000000000000..4400c8d87c12c712529d9c5d89c7adbe51d180f2 --- /dev/null +++ b/src/acpi/aml/dataobj.rs @@ -0,0 +1,168 @@ +use collections::vec::Vec; +use collections::string::String; + +use super::{AmlInternalError, AmlExecutable, AmlValue, AmlNamespace, get_namespace_string}; + +use super::type2opcode::{parse_def_buffer, parse_def_package, parse_def_var_package, + DefBuffer, DefPackage, DefVarPackage}; +use super::termlist::{parse_term_arg, TermArg}; +use super::namestring::{parse_super_name, SuperName}; + +#[derive(Debug, Clone)] +pub enum DataObj { + ComputationalData(ComputationalData), + DefPackage(DefPackage), + DefVarPackage(DefVarPackage) +} + +#[derive(Debug, Clone)] +pub enum DataRefObj { + DataObj(DataObj), + ObjectReference(TermArg), + DDBHandle(SuperName) +} + +#[derive(Debug, Clone)] +pub struct ArgObj(u8); +#[derive(Debug, Clone)] +pub struct LocalObj(u8); +// Not actually doing anything to contain data, but does give us type guarantees, which is useful + +#[derive(Debug, Clone)] +pub enum ComputationalData { + Byte(u8), + Word(u16), + DWord(u32), + QWord(u64), + String(String), + Zero, + One, + Ones, + DefBuffer(DefBuffer), + RevisionOp +} + +impl AmlExecutable for DataRefObj { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option<AmlValue> { + match *self { + DataRefObj::DataObj(ref cd) => cd.execute(namespace, scope), + _ => Some(AmlValue::Integer) + } + } +} + +impl AmlExecutable for DataObj { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option<AmlValue> { + match *self { + DataObj::ComputationalData(ref cd) => cd.execute(namespace, scope), + DataObj::DefPackage(ref pkg) => pkg.execute(namespace, scope), + _ => Some(AmlValue::Integer) + } + } +} + +impl AmlExecutable for ComputationalData { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option<AmlValue> { + match *self { + ComputationalData::Byte(b) => Some(AmlValue::IntegerConstant(b as u64)), + ComputationalData::Word(w) => Some(AmlValue::IntegerConstant(w as u64)), + ComputationalData::DWord(d) => Some(AmlValue::IntegerConstant(d as u64)), + ComputationalData::QWord(q) => Some(AmlValue::IntegerConstant(q as u64)), + ComputationalData::Zero => Some(AmlValue::IntegerConstant(0)), + ComputationalData::One => Some(AmlValue::IntegerConstant(1)), + ComputationalData::Ones => Some(AmlValue::IntegerConstant(0xFFFFFFFFFFFFFFFF)), + _ => Some(AmlValue::Integer) + } + } +} + +pub fn parse_data_obj(data: &[u8]) -> Result<(DataObj, usize), AmlInternalError> { + parser_selector! { + data, + parser_wrap!(DataObj::ComputationalData, parse_computational_data), + parser_wrap!(DataObj::DefPackage, parse_def_package), + parser_wrap!(DataObj::DefVarPackage, parse_def_var_package) + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +pub fn parse_data_ref_obj(data: &[u8]) -> Result<(DataRefObj, usize), AmlInternalError> { + parser_selector! { + data, + parser_wrap!(DataRefObj::DataObj, parse_data_obj), + parser_wrap!(DataRefObj::ObjectReference, parse_term_arg), + parser_wrap!(DataRefObj::DDBHandle, parse_super_name) + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +pub fn parse_arg_obj(data: &[u8]) -> Result<(ArgObj, usize), AmlInternalError> { + match data[0] { + 0x68 ... 0x6E => Ok((ArgObj(data[0] - 0x68), 1 as usize)), + _ => Err(AmlInternalError::AmlInvalidOpCode) + } +} + +pub fn parse_local_obj(data: &[u8]) -> Result<(LocalObj, usize), AmlInternalError> { + match data[0] { + 0x60 ... 0x67 => Ok((LocalObj(data[0] - 0x60), 1 as usize)), + _ => Err(AmlInternalError::AmlInvalidOpCode) + } +} + +fn parse_computational_data(data: &[u8]) -> Result<(ComputationalData, usize), AmlInternalError> { + match data[0] { + 0x0A => Ok((ComputationalData::Byte(data[1]), 2 as usize)), + 0x0B => { + let res = (data[1] as u16) + + ((data[2] as u16) << 8); + Ok((ComputationalData::Word(res), 3 as usize)) + }, + 0x0C => { + let res = (data[1] as u32) + + ((data[2] as u32) << 8) + + ((data[3] as u32) << 16) + + ((data[4] as u32) << 24); + Ok((ComputationalData::DWord(res), 5 as usize)) + }, + 0x0D => { + let mut cur_ptr: usize = 1; + let mut cur_string: Vec<u8> = vec!(); + + while data[cur_ptr] != 0x00 { + cur_string.push(data[cur_ptr]); + cur_ptr += 1; + } + + match String::from_utf8(cur_string) { + Ok(s) => Ok((ComputationalData::String(s.clone()), s.clone().len() + 2)), + Err(_) => Err(AmlInternalError::AmlParseError("String data - invalid string")) + } + }, + 0x0E => { + let res = (data[1] as u64) + + ((data[2] as u64) << 8) + + ((data[3] as u64) << 16) + + ((data[4] as u64) << 24) + + ((data[5] as u64) << 32) + + ((data[6] as u64) << 40) + + ((data[7] as u64) << 48) + + ((data[8] as u64) << 56); + Ok((ComputationalData::QWord(res), 9 as usize)) + }, + 0x00 => Ok((ComputationalData::Zero, 1 as usize)), + 0x01 => Ok((ComputationalData::One, 1 as usize)), + 0x5B => if data[1] == 0x30 { + Ok((ComputationalData::RevisionOp, 2 as usize)) + } else { + Err(AmlInternalError::AmlInvalidOpCode) + }, + 0xFF => Ok((ComputationalData::Ones, 1 as usize)), + _ => match parse_def_buffer(data) { + Ok((res, size)) => Ok((ComputationalData::DefBuffer(res), size)), + Err(e) => Err(e) + } + } +} diff --git a/src/acpi/aml/mod.rs b/src/acpi/aml/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..3d35395d7adc2f1f4a3d75bc430351241eccbcd6 --- /dev/null +++ b/src/acpi/aml/mod.rs @@ -0,0 +1,85 @@ +//! # AML +//! Code to parse and execute AML tables + +use collections::vec::Vec; +use collections::string::String; +use collections::boxed::Box; +use core::fmt::Debug; +use core::str::FromStr; + +use super::sdt::Sdt; + +#[macro_use] +mod parsermacros; + +mod namespace; +mod termlist; +mod namespacemodifier; +mod pkglength; +mod namestring; +mod namedobj; +mod dataobj; +mod type1opcode; +mod type2opcode; + +use self::termlist::{parse_term_list, TermObj}; +pub use self::namespace::{AmlNamespace, AmlValue}; +use self::namespace::AmlNamespaceContents; + +// TODO: This should be able to take parameters, and may also return multiple values +pub trait AmlExecutable { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option<AmlValue>; +} + +// TODO: make private +pub enum AmlInternalError { + AmlParseError(&'static str), + AmlInvalidOpCode, + AmlDeferredLoad +} + +pub enum AmlError { + AmlParseError(&'static str) +} + +pub fn get_namespace_string(current: String, modifier: String) -> String { + if modifier.starts_with("\\") { + return modifier; + } + + if modifier.starts_with("^") { + // TODO + } + + let mut namespace = current.clone(); + namespace.push('.'); + namespace + &modifier +} + +pub fn parse_aml_table(sdt: &'static Sdt) -> Result<AmlNamespace, AmlError> { + let data = sdt.data(); + + let term_list = match parse_term_list(data) { + Ok(res) => res, + Err(AmlInternalError::AmlParseError(s)) => return Err(AmlError::AmlParseError(s)), + Err(AmlInternalError::AmlInvalidOpCode) => return Err(AmlError::AmlParseError("Unable to match opcode")), + Err(AmlInternalError::AmlDeferredLoad) => return Err(AmlError::AmlParseError("Deferred load reached top level")) + }; + + let global_namespace_specifier = String::from_str("\\").unwrap(); + // Unwrap is fine here. I mean come on, if this goes wrong you've got bigger problems than AML + // not loading... + + let mut global_namespace = AmlNamespace::new_namespace(&global_namespace_specifier); + term_list.execute(&mut global_namespace, global_namespace_specifier.clone()); + + Ok(global_namespace) +} + +pub fn is_aml_table(sdt: &'static Sdt) -> bool { + if &sdt.signature == b"DSDT" {//|| &sdt.signature == b"SSDT" { + true + } else { + false + } +} diff --git a/src/acpi/aml/namedobj.rs b/src/acpi/aml/namedobj.rs new file mode 100644 index 0000000000000000000000000000000000000000..67c2e32f6bbe86e2356c0d4b33a8799d0b633281 --- /dev/null +++ b/src/acpi/aml/namedobj.rs @@ -0,0 +1,783 @@ +use collections::vec::Vec; +use collections::string::String; +use collections::boxed::Box; + +use super::{AmlInternalError, AmlExecutable, AmlValue, AmlNamespace, AmlNamespaceContents, get_namespace_string}; +use super::namestring::{parse_name_string, parse_name_seg}; +use super::termlist::{parse_term_arg, parse_term_list, parse_object_list, TermArg, TermObj, Object}; +use super::pkglength::parse_pkg_length; +use super::type2opcode::{parse_def_buffer, DefBuffer}; + +#[derive(Debug, Clone)] +pub enum NamedObj { + DefBankField { + region_name: String, + bank_name: String, + bank_value: TermArg, + flags: FieldFlags, + field_list: Vec<FieldElement> + }, + DefCreateBitField { + name: String, + source_buf: TermArg, + bit_index: TermArg + }, + DefCreateByteField { + name: String, + source_buf: TermArg, + byte_index: TermArg + }, + DefCreateWordField { + name: String, + source_buf: TermArg, + byte_index: TermArg + }, + DefCreateDWordField { + name: String, + source_buf: TermArg, + byte_index: TermArg + }, + DefCreateQWordField { + name: String, + source_buf: TermArg, + byte_index: TermArg + }, + DefCreateField { + name: String, + source_buf: TermArg, + bit_index: TermArg, + num_bits: TermArg + }, + DefDataRegion { + name: String, + signature: TermArg, + oem_id: TermArg, + oem_table_id: TermArg + }, + DefDevice { + name: String, + obj_list: Vec<Object> + }, + DefEvent { + name: String + }, + DefOpRegion { + name: String, + region: RegionSpace, + offset: TermArg, + len: TermArg + }, + DefField { + name: String, + flags: FieldFlags, + field_list: Vec<FieldElement> + }, + DefIndexField { + idx_name: String, + data_name: String, + flags: FieldFlags, + field_list: Vec<FieldElement> + }, + DefMethod { + name: String, + method: Method + }, + DefMutex { + name: String, + sync_level: u8 + }, + DefPowerRes { + name: String, + system_level: u8, + resource_order: u16, + obj_list: Vec<Object> + }, + DefProcessor { + name: String, + proc_id: u8, + p_blk_addr: u32, + p_blk_len: u8, + obj_list: Vec<Object> + }, + DefThermalZone { + name: String, + obj_list: Vec<Object> + }, + DeferredLoad(Vec<u8>) +} + +#[derive(Debug, Clone)] +pub struct Method { + arg_count: u8, + serialized: bool, + sync_level: u8, + term_list: Vec<TermObj> +} + +impl AmlExecutable for NamedObj { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option<AmlValue> { + match *self { + NamedObj::DefOpRegion { ref name, ref region, ref offset, ref len } => { + let local_scope_string = get_namespace_string(scope.clone(), name.clone()); + + let resolved_offset = match offset.execute(namespace, scope.clone()) { + Some(r) => r, + _ => return None + }; + + let resolved_len = match len.execute(namespace, scope.clone()) { + Some(r) => r, + _ => return None + }; + + namespace.push_to(local_scope_string, AmlNamespaceContents::OpRegion { + region: *region, + offset: resolved_offset, + len: resolved_len + }); + }, + NamedObj::DefField { ref name, ref flags, ref field_list } => { + let mut offset: usize = 0; + + for f in field_list { + match *f { + FieldElement::ReservedField { length } => offset += length, + FieldElement::NamedField { name: ref field_name, length } => { + let local_scope_string = get_namespace_string(scope.clone(), + field_name.clone()); + namespace.push_to(local_scope_string, AmlNamespaceContents::Field { + op_region: name.clone(), + flags: flags.clone(), + offset: offset.clone(), + length: length.clone() + }); + + offset += length; + }, + _ => () + } + } + }, + NamedObj::DefMethod { ref name, ref method } => { + let local_scope_string = get_namespace_string(scope.clone(), name.clone()); + namespace.push_to(local_scope_string, AmlNamespaceContents::Value( + AmlValue::Method(method.clone()))); + }, + _ => () + } + + None + } +} + +#[derive(Debug, Copy, Clone)] +pub enum RegionSpace { + SystemMemory, + SystemIO, + PCIConfig, + EmbeddedControl, + SMBus, + SystemCMOS, + PciBarTarget, + IPMI, + GeneralPurposeIO, + GenericSerialBus, + UserDefined(u8) +} + +#[derive(Debug, Clone)] +pub struct FieldFlags { + access_type: AccessType, + lock_rule: bool, + update_rule: UpdateRule +} + +#[derive(Debug, Clone)] +pub enum AccessType { + AnyAcc, + ByteAcc, + WordAcc, + DWordAcc, + QWordAcc, + BufferAcc +} + +#[derive(Debug, Clone)] +pub enum UpdateRule { + Preserve, + WriteAsOnes, + WriteAsZeros +} + +#[derive(Debug, Clone)] +pub enum FieldElement { + NamedField { + name: String, + length: usize + }, + ReservedField { + length: usize + }, + AccessField { + access_type: AccessType, + access_attrib: AccessAttrib + }, + ConnectFieldNameString(String), + ConnectFieldBufferData(DefBuffer), +} + +#[derive(Debug, Clone)] +pub enum AccessAttrib { + AttribBytes(u8), + AttribRawBytes(u8), + AttribRawProcessBytes(u8), + AttribQuick, + AttribSendReceive, + AttribByte, + AttribWord, + AttribBlock, + AttribProcessCall, + AttribBlockProcessCall +} + +pub fn parse_named_obj(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_selector! { + data, + parse_def_bank_field, + parse_def_create_bit_field, + parse_def_create_byte_field, + parse_def_create_word_field, + parse_def_create_dword_field, + parse_def_create_qword_field, + parse_def_create_field, + parse_def_data_region, + parse_def_event, + parse_def_device, + parse_def_op_region, + parse_def_field, + parse_def_index_field, + parse_def_method, + parse_def_mutex, + parse_def_power_res, + parse_def_processor, + parse_def_thermal_zone + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +fn parse_def_bank_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x87); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[2..])?; + let (region_name, region_name_len) = match parse_name_string( + &data[2 + pkg_length_len .. 2 + pkg_length]) { + Ok(res) => res, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + let (bank_name, bank_name_len) = match parse_name_string( + &data[2 + pkg_length_len + region_name_len .. 2 + pkg_length]) { + Ok(res) => res, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + let (bank_value, bank_value_len) = match parse_term_arg( + &data[2 + pkg_length_len + region_name_len .. 2 + pkg_length]) { + Ok(res) => res, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + let flags_raw = data[2 + pkg_length_len + region_name_len + bank_name_len + bank_value_len]; + let flags = FieldFlags { + access_type: match flags_raw & 0x0F { + 0 => AccessType::AnyAcc, + 1 => AccessType::ByteAcc, + 2 => AccessType::WordAcc, + 3 => AccessType::DWordAcc, + 4 => AccessType::QWordAcc, + 5 => AccessType::BufferAcc, + _ => return Err(AmlInternalError::AmlParseError("BankField - invalid access type")) + }, + lock_rule: (flags_raw & 0x10) == 0x10, + update_rule: match (flags_raw & 0x60) >> 5 { + 0 => UpdateRule::Preserve, + 1 => UpdateRule::WriteAsOnes, + 2 => UpdateRule::WriteAsZeros, + _ => return Err(AmlInternalError::AmlParseError("BankField - invalid update rule")) + } + }; + + let field_list = match parse_field_list( + &data[3 + pkg_length_len + region_name_len + bank_name_len + bank_value_len .. + 2 + pkg_length]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + Ok((NamedObj::DefBankField {region_name, bank_name, bank_value, flags, field_list}, + 2 + pkg_length)) +} + +fn parse_def_create_bit_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode!(data, 0x8D); + + let (source_buf, source_buf_len) = parse_term_arg(&data[1..])?; + let (bit_index, bit_index_len) = parse_term_arg(&data[1 + source_buf_len..])?; + let (name, name_len) = parse_name_string(&data[1 + source_buf_len + bit_index_len..])?; + + Ok((NamedObj::DefCreateBitField {name, source_buf, bit_index}, + 1 + source_buf_len + bit_index_len + name_len)) +} + +fn parse_def_create_byte_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode!(data, 0x8C); + + let (source_buf, source_buf_len) = parse_term_arg(&data[1..])?; + let (byte_index, byte_index_len) = parse_term_arg(&data[1 + source_buf_len..])?; + let (name, name_len) = parse_name_string(&data[1 + source_buf_len + byte_index_len..])?; + + Ok((NamedObj::DefCreateByteField {name, source_buf, byte_index}, + 1 + source_buf_len + byte_index_len + name_len)) +} + +fn parse_def_create_word_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode!(data, 0x8B); + + let (source_buf, source_buf_len) = parse_term_arg(&data[1..])?; + let (byte_index, byte_index_len) = parse_term_arg(&data[1 + source_buf_len..])?; + let (name, name_len) = parse_name_string(&data[1 + source_buf_len + byte_index_len..])?; + + Ok((NamedObj::DefCreateWordField {name, source_buf, byte_index}, + 1 + source_buf_len + byte_index_len + name_len)) +} + +fn parse_def_create_dword_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode!(data, 0x8A); + + let (source_buf, source_buf_len) = parse_term_arg(&data[1..])?; + let (byte_index, byte_index_len) = parse_term_arg(&data[1 + source_buf_len..])?; + let (name, name_len) = parse_name_string(&data[1 + source_buf_len + byte_index_len..])?; + + Ok((NamedObj::DefCreateDWordField {name, source_buf, byte_index}, + 1 + source_buf_len + byte_index_len + name_len)) +} + +fn parse_def_create_qword_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode!(data, 0x8F); + + let (source_buf, source_buf_len) = parse_term_arg(&data[1..])?; + let (byte_index, byte_index_len) = parse_term_arg(&data[1 + source_buf_len..])?; + let (name, name_len) = parse_name_string(&data[1 + source_buf_len + byte_index_len..])?; + + Ok((NamedObj::DefCreateQWordField {name, source_buf, byte_index}, + 1 + source_buf_len + byte_index_len + name_len)) +} + +fn parse_def_create_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x13); + + let (source_buf, source_buf_len) = parse_term_arg(&data[2..])?; + let (bit_index, bit_index_len) = parse_term_arg(&data[2 + source_buf_len..])?; + let (num_bits, num_bits_len) = parse_term_arg(&data[2 + source_buf_len + bit_index_len..])?; + let (name, name_len) = parse_name_string( + &data[2 + source_buf_len + bit_index_len + num_bits_len..])?; + + Ok((NamedObj::DefCreateField {name, source_buf, bit_index, num_bits}, + 2 + source_buf_len + bit_index_len + num_bits_len + name_len)) +} + +fn parse_def_data_region(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x88); + + let (name, name_len) = parse_name_string(&data[2..])?; + let (signature, signature_len) = parse_term_arg(&data[2 + name_len..])?; + let (oem_id, oem_id_len) = parse_term_arg(&data[2 + name_len + signature_len..])?; + let (oem_table_id, oem_table_id_len) = parse_term_arg( + &data[2 + name_len + signature_len + oem_id_len..])?; + + Ok((NamedObj::DefDataRegion {name, signature, oem_id, oem_table_id}, + 2 + name_len + signature_len + oem_id_len + oem_table_id_len)) +} + +fn parse_def_event(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x02); + + let (name, name_len) = parse_name_string(&data[2..])?; + + Ok((NamedObj::DefEvent {name}, 2 + name_len)) +} + +fn parse_def_device(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x82); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[2..])?; + let (name, name_len) = match parse_name_string(&data[2 + pkg_length_len .. 2 + pkg_length]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + let obj_list = match parse_object_list(&data[2 + pkg_length_len + name_len .. 2 + pkg_length]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + Ok((NamedObj::DefDevice {name, obj_list}, 2 + pkg_length_len)) +} + +fn parse_def_op_region(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x80); + + let (name, name_len) = parse_name_string(&data[2..])?; + let region = match data[2 + name_len] { + 0x00 => RegionSpace::SystemMemory, + 0x01 => RegionSpace::SystemIO, + 0x02 => RegionSpace::PCIConfig, + 0x03 => RegionSpace::EmbeddedControl, + 0x04 => RegionSpace::SMBus, + 0x05 => RegionSpace::SystemCMOS, + 0x06 => RegionSpace::PciBarTarget, + 0x07 => RegionSpace::IPMI, + 0x08 => RegionSpace::GeneralPurposeIO, + 0x09 => RegionSpace::GenericSerialBus, + 0x80 ... 0xFF => RegionSpace::UserDefined(data[2 + name_len]), + _ => return Err(AmlInternalError::AmlParseError("OpRegion - invalid region")) + }; + + let (offset, offset_len) = parse_term_arg(&data[3 + name_len..])?; + let (len, len_len) = parse_term_arg(&data[3 + name_len + offset_len..])?; + + Ok((NamedObj::DefOpRegion {name, region, offset, len}, 3 + name_len + offset_len + len_len)) +} + +fn parse_def_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x81); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[2..])?; + let (name, name_len) = match parse_name_string(&data[2 + pkg_length_len .. 2 + pkg_length]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + let flags_raw = data[2 + pkg_length_len + name_len]; + let flags = FieldFlags { + access_type: match flags_raw & 0x0F { + 0 => AccessType::AnyAcc, + 1 => AccessType::ByteAcc, + 2 => AccessType::WordAcc, + 3 => AccessType::DWordAcc, + 4 => AccessType::QWordAcc, + 5 => AccessType::BufferAcc, + _ => return Err(AmlInternalError::AmlParseError("Field - Invalid access type")) + }, + lock_rule: (flags_raw & 0x10) == 0x10, + update_rule: match (flags_raw & 0x60) >> 5 { + 0 => UpdateRule::Preserve, + 1 => UpdateRule::WriteAsOnes, + 2 => UpdateRule::WriteAsZeros, + _ => return Err(AmlInternalError::AmlParseError("Field - Invalid update rule")) + } + }; + + let field_list = match parse_field_list(&data[3 + pkg_length_len + name_len .. 2 + pkg_length]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + Ok((NamedObj::DefField {name, flags, field_list}, 2 + pkg_length)) +} + +fn parse_def_index_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x86); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[2..])?; + let (idx_name, idx_name_len) = match parse_name_string( + &data[2 + pkg_length_len .. 2 + pkg_length]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + let (data_name, data_name_len) = match parse_name_string( + &data[2 + pkg_length_len + idx_name_len .. 2 + pkg_length]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + let flags_raw = data[2 + pkg_length_len + idx_name_len + data_name_len]; + let flags = FieldFlags { + access_type: match flags_raw & 0x0F { + 0 => AccessType::AnyAcc, + 1 => AccessType::ByteAcc, + 2 => AccessType::WordAcc, + 3 => AccessType::DWordAcc, + 4 => AccessType::QWordAcc, + 5 => AccessType::BufferAcc, + _ => return Err(AmlInternalError::AmlParseError("IndexField - Invalid access type")) + }, + lock_rule: (flags_raw & 0x10) == 0x10, + update_rule: match (flags_raw & 0x60) >> 5 { + 0 => UpdateRule::Preserve, + 1 => UpdateRule::WriteAsOnes, + 2 => UpdateRule::WriteAsZeros, + _ => return Err(AmlInternalError::AmlParseError("IndexField - Invalid update rule")) + } + }; + + let field_list = match parse_field_list( + &data[3 + pkg_length_len + idx_name_len + data_name_len .. 2 + pkg_length]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + Ok((NamedObj::DefIndexField {idx_name, data_name, flags, field_list}, 2 + pkg_length)) +} + +fn parse_field_list(data: &[u8]) -> Result<Vec<FieldElement>, AmlInternalError> { + let mut terms: Vec<FieldElement> = vec!(); + let mut current_offset: usize = 0; + + while current_offset < data.len() { + let (res, len) = match parse_field_element(&data[current_offset..]) { + Ok(r) => r, + Err(AmlInternalError::AmlInvalidOpCode) => + return Err(AmlInternalError::AmlParseError("FieldList - no valid field")), + Err(e) => return Err(e) + }; + + terms.push(res); + current_offset += len; + } + + Ok(terms) +} + +fn parse_field_element(data: &[u8]) -> Result<(FieldElement, usize), AmlInternalError> { + parser_selector! { + data, + parse_named_field, + parse_reserved_field, + parse_access_field, + parse_connect_field + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +fn parse_named_field(data: &[u8]) -> Result<(FieldElement, usize), AmlInternalError> { + let (name_seg, name_seg_len) = parse_name_seg(&data[0..4])?; + let name = match String::from_utf8(name_seg) { + Ok(s) => s, + Err(_) => return Err(AmlInternalError::AmlParseError("NamedField - invalid name")) + }; + let (length, length_len) = parse_pkg_length(&data[4..])?; + + Ok((FieldElement::NamedField {name, length}, 4 + length_len)) +} + +fn parse_reserved_field(data: &[u8]) -> Result<(FieldElement, usize), AmlInternalError> { + parser_opcode!(data, 0x00); + + let (length, length_len) = parse_pkg_length(&data[1..])?; + Ok((FieldElement::ReservedField {length}, 1 + length_len)) +} + +fn parse_access_field(data: &[u8]) -> Result<(FieldElement, usize), AmlInternalError> { + parser_opcode!(data, 0x01, 0x03); + + let flags_raw = data[1]; + let access_type = match flags_raw & 0x0F { + 0 => AccessType::AnyAcc, + 1 => AccessType::ByteAcc, + 2 => AccessType::WordAcc, + 3 => AccessType::DWordAcc, + 4 => AccessType::QWordAcc, + 5 => AccessType::BufferAcc, + _ => return Err(AmlInternalError::AmlParseError("AccessField - Invalid access type")) + }; + + let access_attrib = match (flags_raw & 0xC0) >> 6 { + 0 => match data[2] { + 0x02 => AccessAttrib::AttribQuick, + 0x04 => AccessAttrib::AttribSendReceive, + 0x06 => AccessAttrib::AttribByte, + 0x08 => AccessAttrib::AttribWord, + 0x0A => AccessAttrib::AttribBlock, + 0x0B => AccessAttrib::AttribBytes(data[3]), + 0x0C => AccessAttrib::AttribProcessCall, + 0x0D => AccessAttrib::AttribBlockProcessCall, + 0x0E => AccessAttrib::AttribRawBytes(data[3]), + 0x0F => AccessAttrib::AttribRawProcessBytes(data[3]), + _ => return Err(AmlInternalError::AmlParseError("AccessField - Invalid access attrib")) + }, + 1 => AccessAttrib::AttribBytes(data[2]), + 2 => AccessAttrib::AttribRawBytes(data[2]), + 3 => AccessAttrib::AttribRawProcessBytes(data[2]), + _ => return Err(AmlInternalError::AmlParseError("AccessField - Invalid access attrib")) + // This should never happen but the compiler bitches if I don't cover this + }; + + return Ok((FieldElement::AccessField {access_type, access_attrib}, if data[0] == 0x01 { + 3 as usize + } else { + 4 as usize + })) +} + +fn parse_connect_field(data: &[u8]) -> Result<(FieldElement, usize), AmlInternalError> { + parser_opcode!(data, 0x02); + + match parse_def_buffer(&data[1..]) { + Ok((buf, buf_len)) => return Ok((FieldElement::ConnectFieldBufferData(buf), buf_len + 1)), + Err(AmlInternalError::AmlInvalidOpCode) => (), + Err(e) => return Err(e) + } + + match parse_name_string(&data[1..]) { + Ok((name, name_len)) => Ok((FieldElement::ConnectFieldNameString(name), name_len + 1)), + Err(AmlInternalError::AmlInvalidOpCode) => Err(AmlInternalError::AmlParseError("ConnectField - unable to match field")), + Err(e) => Err(e) + } +} + +fn parse_def_method(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode!(data, 0x14); + + let (pkg_len, pkg_len_len) = parse_pkg_length(&data[1..])?; + let (name, name_len) = match parse_name_string(&data[1 + pkg_len_len..]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 1 + pkg_len].to_vec()), 1 + pkg_len)), + Err(e) => return Err(e) + }; + let flags = data[1 + pkg_len_len + name_len]; + + let arg_count = flags & 0x07; + let serialized = (flags & 0x08) == 0x08; + let sync_level = flags & 0xF0 >> 4; + + let term_list = match parse_term_list(&data[2 + pkg_len_len + name_len .. 1 + pkg_len]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 1 + pkg_len].to_vec()), 1 + pkg_len)), + Err(e) => return Err(e) + }; + + Ok((NamedObj::DefMethod { + name: name, + method: Method { + arg_count, + serialized, + sync_level, + term_list + } + }, pkg_len + 1)) +} + +fn parse_def_mutex(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x01); + + let (name, name_len) = match parse_name_string(&data[2 ..]) { + Ok(p) => p, + Err(e) => return Err(e), + }; + let flags = data[2 + name_len]; + let sync_level = flags & 0x0F; + + Ok((NamedObj::DefMutex {name, sync_level}, name_len + 3)) +} + +fn parse_def_power_res(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x84); + + let (pkg_len, pkg_len_len) = parse_pkg_length(&data[2..])?; + let (name, name_len) = match parse_name_string(&data[2 + pkg_len_len..]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_len].to_vec()), 2 + pkg_len)), + Err(e) => return Err(e) + }; + + let system_level = data[2 + pkg_len_len + name_len]; + let resource_order: u16 = (data[3 + pkg_len_len + name_len] as u16) + + ((data[4 + pkg_len_len + name_len] as u16) << 8); + + let obj_list = match parse_object_list(&data[5 + pkg_len_len + name_len .. 2 + pkg_len]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_len].to_vec()), 2 + pkg_len)), + Err(e) => return Err(e) + }; + + Ok((NamedObj::DefPowerRes {name, system_level, resource_order, obj_list}, 2 + pkg_len)) +} + +fn parse_def_processor(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x83); + + let (pkg_len, pkg_len_len) = parse_pkg_length(&data[2..])?; + let (name, name_len) = match parse_name_string(&data[2 + pkg_len_len..]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_len].to_vec()), 2 + pkg_len)), + Err(e) => return Err(e) + }; + + let proc_id = data[2 + pkg_len_len + name_len]; + let p_blk_addr: u32 = (data[3 + pkg_len_len + name_len] as u32) + + ((data[4 + pkg_len_len + name_len] as u32) << 8) + + ((data[5 + pkg_len_len + name_len] as u32) << 16) + + ((data[6 + pkg_len_len + name_len] as u32) << 24); + let p_blk_len = data[7 + pkg_len_len + name_len]; + + let obj_list = match parse_object_list(&data[8 + pkg_len_len + name_len .. 2 + pkg_len]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_len].to_vec()), 2 + pkg_len)), + Err(e) => return Err(e) + }; + + Ok((NamedObj::DefProcessor {name, proc_id, p_blk_addr, p_blk_len, obj_list}, 2 + pkg_len)) +} + +fn parse_def_thermal_zone(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x85); + + let (pkg_len, pkg_len_len) = parse_pkg_length(&data[2..])?; + let (name, name_len) = match parse_name_string(&data[2 + pkg_len_len..]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_len].to_vec()), 2 + pkg_len)), + Err(e) => return Err(e) + }; + + let obj_list = match parse_object_list(&data[2 + pkg_len_len + name_len .. 2 + pkg_len]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_len].to_vec()), 2 + pkg_len)), + Err(e) => return Err(e) + }; + + Ok((NamedObj::DefThermalZone {name, obj_list}, 2 + pkg_len)) +} diff --git a/src/acpi/aml/namespace.rs b/src/acpi/aml/namespace.rs new file mode 100644 index 0000000000000000000000000000000000000000..8a0c6f966fbb241c7e75b0cdb6619fcfc17807b9 --- /dev/null +++ b/src/acpi/aml/namespace.rs @@ -0,0 +1,225 @@ +use collections::string::String; +use collections::vec::Vec; +use collections::boxed::Box; + +use core::str::FromStr; + +use super::namedobj::{ RegionSpace, FieldFlags, Method }; + +#[derive(Debug, Clone)] +pub struct AmlNamespace { + name: String, + contents: AmlNamespaceContents +} + +#[derive(Debug, Clone)] +pub enum AmlNamespaceContents { + Value(AmlValue), + SubNamespace(Box<AmlNamespace>), + Namespace(Vec<AmlNamespaceContents>), + OpRegion { + region: RegionSpace, + offset: AmlValue, + len: AmlValue + }, + Field { + op_region: String, + flags: FieldFlags, + offset: usize, + length: usize + } +} + +#[derive(Debug, Clone)] +pub enum AmlValue { + Uninitialized, + Buffer, + BufferField, + DDBHandle, + DebugObject, + Device, + Event, + FieldUnit, + Integer, + IntegerConstant(u64), + Method(Method), + Mutex, + ObjectReference, + OperationRegion, + Package(Vec<AmlValue>), + String, + PowerResource, + Processor, + RawDataBuffer, + ThermalZone +} + +impl AmlValue { + pub fn get_as_package(&self) -> Option<Vec<AmlValue>> { + match *self { + AmlValue::Package(ref p) => Some(p.clone()), + _ => None + } + } + + pub fn get_as_integer(&self) -> Option<u64> { + match *self { + AmlValue::IntegerConstant(ref i) => Some(i.clone()), + _ => None + } + } +} + +impl AmlNamespace { + pub fn new_namespace(name: &String) -> AmlNamespace { + AmlNamespace { + name: name.clone(), + contents: AmlNamespaceContents::Namespace(vec!()) + } + } + + pub fn find_str(&self, scope_str: &str) -> Option<AmlValue> { + let scope_string = String::from_str(scope_str).unwrap(); + self.find(scope_string) + } + + pub fn find(&self, scope_string: String) -> Option<AmlValue> { + if scope_string.len() == 0 { + match self.contents { + AmlNamespaceContents::Value(ref v) => return Some(v.clone()), + _ => return None + } + } + + let mut scope_string = scope_string.clone(); + + if scope_string.starts_with("\\") { + if self.name != "\\" { + return None; + } + + scope_string.remove(0); + } + + if scope_string.starts_with(".") { + scope_string.remove(0); + } + + if scope_string.len() == 0 { + match self.contents { + AmlNamespaceContents::Value(ref v) => return Some(v.clone()), + _ => return None + } + } + + let (current, nextset) = match scope_string.find(".") { + Some(s) => { + let (x, mut y) = scope_string.split_at(s); + y = &y[1..]; + + (String::from_str(x).unwrap(), String::from_str(y).unwrap()) + }, + None => if scope_string.len() <= 4 { + (scope_string, String::from_str("").unwrap()) + } else { + return None; + } + }; + + match self.contents { + AmlNamespaceContents::Namespace(ref namespace) => { + // TODO: Remove this while loop here, there has to be a more elegant way + let mut current_index = 0; + while current_index < namespace.len() { + match namespace[current_index] { + AmlNamespaceContents::SubNamespace(ref ns) => if ns.name == current { + return ns.find(nextset); + }, + _ => () + } + + current_index += 1; + } + }, + _ => () + } + + None + } + + pub fn push(&mut self, val: AmlNamespaceContents) { + match self.contents { + AmlNamespaceContents::Namespace(ref mut v) => v.push(val), + _ => () // TODO: Error this + } + } + + pub fn push_to(&mut self, scope_string: String, contents: AmlNamespaceContents) { + if scope_string.len() == 0 { + return; + } + + let mut scope_string = scope_string.clone(); + + if scope_string.starts_with("\\") { + if self.name != "\\" { + return; + // TODO: Error this + } + + scope_string.remove(0); + } + + if scope_string.starts_with(".") { + scope_string.remove(0); + } + + if scope_string.len() == 0 { + return; + } + + let (current, nextset) = match scope_string.find(".") { + Some(s) => { + let (x, mut y) = scope_string.split_at(s); + y = &y[1..]; + + (String::from_str(x).unwrap(), String::from_str(y).unwrap()) + }, + None => if scope_string.len() <= 4 { + (scope_string, String::from_str("").unwrap()) + } else { + return; + } + }; + + match self.contents { + AmlNamespaceContents::Namespace(ref mut namespace) => { + // TODO: Remove this while loop here, there has to be a more elegant way + let mut current_index = 0; + while current_index < namespace.len() { + match namespace[current_index] { + AmlNamespaceContents::SubNamespace(ref mut ns) => if ns.name == current { + ns.push_to(nextset, contents); + return; + }, + _ => () + } + + current_index += 1; + } + + let mut next = AmlNamespace { + name: current, + contents: contents + }; + + namespace.push(AmlNamespaceContents::SubNamespace(Box::new(next))); + } + _ => () // TODO: Error this + } + } + + pub fn push_subordinate_namespace(&mut self, scope_string: String) { + self.push_to(scope_string, AmlNamespaceContents::Namespace(vec!())); + } +} diff --git a/src/acpi/aml/namespacemodifier.rs b/src/acpi/aml/namespacemodifier.rs new file mode 100644 index 0000000000000000000000000000000000000000..a49e2bb0b677978b6abb37a185c7e8bdc62b3d0a --- /dev/null +++ b/src/acpi/aml/namespacemodifier.rs @@ -0,0 +1,102 @@ +use collections::vec::Vec; +use collections::string::String; +use collections::boxed::Box; + +use super::{AmlInternalError, AmlExecutable, AmlValue, AmlNamespace, AmlNamespaceContents, get_namespace_string}; +use super::pkglength::parse_pkg_length; +use super::namestring::parse_name_string; +use super::termlist::{parse_term_list, TermObj}; +use super::dataobj::{parse_data_ref_obj, DataRefObj}; + +#[derive(Debug, Clone)] +pub enum NamespaceModifier { + Name { + name: String, + data_ref_obj: DataRefObj + }, + Scope { + name: String, + terms: Vec<TermObj> + }, + Alias { + source_name: String, + alias_name: String + }, + DeferredLoad(Vec<u8>) +} + +impl AmlExecutable for NamespaceModifier { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option<AmlValue> { + match *self { + NamespaceModifier::Scope { name: ref name, terms: ref terms } => { + let local_scope_string = get_namespace_string(scope, name.clone()); + namespace.push_subordinate_namespace(local_scope_string.clone()); + + terms.execute(namespace, local_scope_string); + }, + NamespaceModifier::Name { ref name, ref data_ref_obj } => { + let local_scope_string = get_namespace_string(scope.clone(), name.clone()); + let dro = match data_ref_obj.execute(namespace, scope) { + Some(s) => s, + None => return None + }; + + namespace.push_to(local_scope_string, AmlNamespaceContents::Value(dro)); + }, + _ => () + } + + None + } +} + +pub fn parse_namespace_modifier(data: &[u8]) -> Result<(NamespaceModifier, usize), AmlInternalError> { + parser_selector! { + data, + parse_alias_op, + parse_scope_op, + parse_name_op + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +fn parse_alias_op(data: &[u8]) -> Result<(NamespaceModifier, usize), AmlInternalError> { + parser_opcode!(data, 0x06); + + let (source_name, source_name_len) = parse_name_string(&data[1..])?; + let (alias_name, alias_name_len) = parse_name_string(&data[1 + source_name_len..])?; + + Ok((NamespaceModifier::Alias {source_name, alias_name}, 1 + source_name_len + alias_name_len)) +} + +fn parse_name_op(data: &[u8]) -> Result<(NamespaceModifier, usize), AmlInternalError> { + parser_opcode!(data, 0x08); + + let (name, name_len) = parse_name_string(&data[1..])?; + let (data_ref_obj, data_ref_obj_len) = parse_data_ref_obj(&data[1 + name_len..])?; + + Ok((NamespaceModifier::Name {name, data_ref_obj}, 1 + name_len + data_ref_obj_len)) +} + +fn parse_scope_op(data: &[u8]) -> Result<(NamespaceModifier, usize), AmlInternalError> { + parser_opcode!(data, 0x10); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; + let (name, name_len) = match parse_name_string(&data[1 + pkg_length_len..]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamespaceModifier::DeferredLoad(data[0 .. 1 + pkg_length].to_vec()), + 1 + pkg_length)), + Err(e) => return Err(e) + }; + let terms = match parse_term_list(&data[1 + pkg_length_len + name_len..]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamespaceModifier::DeferredLoad(data[0 .. 1 + pkg_length].to_vec()), + 1 + pkg_length)), + Err(e) => return Err(e) + }; + + Ok((NamespaceModifier::Scope {name, terms}, pkg_length + 1)) +} diff --git a/src/acpi/aml/namestring.rs b/src/acpi/aml/namestring.rs new file mode 100644 index 0000000000000000000000000000000000000000..8015a8ca8559a53421e5a38a72544f3476d706a2 --- /dev/null +++ b/src/acpi/aml/namestring.rs @@ -0,0 +1,188 @@ +use collections::vec::Vec; +use collections::string::String; + +use super::AmlInternalError; + +use super::dataobj::{parse_arg_obj, parse_local_obj, ArgObj, LocalObj}; +use super::type2opcode::{parse_type6_opcode, Type6OpCode}; + +#[derive(Debug, Clone)] +pub enum SuperName { + NameString(String), + ArgObj(ArgObj), + LocalObj(LocalObj), + DebugObj, + Type6OpCode(Type6OpCode) +} + +#[derive(Debug, Clone)] +pub enum Target { + SuperName(SuperName), + Null +} + +pub fn parse_name_string(data: &[u8]) -> Result<(String, usize), AmlInternalError> { + let mut characters: Vec<u8> = vec!(); + let mut starting_index: usize = 0; + + if data[0] == 0x5C { + characters.push(data[0]); + starting_index = 1; + } else if data[0] == 0x5E { + while data[starting_index] == 0x5E { + characters.push(data[starting_index]); + starting_index += 1; + } + } + + let sel = |data| { + parser_selector! { + data, + parse_dual_name_path, + parse_multi_name_path, + parse_null_name, + parse_name_seg + }; + + Err(AmlInternalError::AmlInvalidOpCode) + }; + let (mut chr, len) = sel(&data[starting_index..])?; + characters.append(&mut chr); + + let name_string = String::from_utf8(characters); + + match name_string { + Ok(s) => Ok((s.clone(), len + starting_index)), + Err(_) => Err(AmlInternalError::AmlParseError("Namestring - Name is invalid")) + } +} + +fn parse_null_name(data: &[u8]) -> Result<(Vec<u8>, usize), AmlInternalError> { + parser_opcode!(data, 0x00); + Ok((vec!(), 1 as usize)) +} + +pub fn parse_name_seg(data: &[u8]) -> Result<(Vec<u8>, usize), AmlInternalError> { + match data[0] { + 0x41 ... 0x5A | 0x5F => (), + _ => return Err(AmlInternalError::AmlInvalidOpCode) + } + + match data[1] { + 0x30 ... 0x39 | 0x41 ... 0x5A | 0x5F => (), + _ => return Err(AmlInternalError::AmlInvalidOpCode) + } + + match data[2] { + 0x30 ... 0x39 | 0x41 ... 0x5A | 0x5F => (), + _ => return Err(AmlInternalError::AmlInvalidOpCode) + } + + match data[3] { + 0x30 ... 0x39 | 0x41 ... 0x5A | 0x5F => (), + _ => return Err(AmlInternalError::AmlInvalidOpCode) + } + + let mut name_seg = vec!(data[0], data[1], data[2], data[3]); + while *(name_seg.last().unwrap()) == 0x5F { + name_seg.pop(); + } + + Ok((name_seg, 4 as usize)) +} + +fn parse_dual_name_path(data: &[u8]) -> Result<(Vec<u8>, usize), AmlInternalError> { + parser_opcode!(data, 0x2E); + + let mut characters: Vec<u8> = vec!(); + let mut dual_len: usize = 1; + + match parse_name_seg(&data[1..5]) { + Ok((mut v, len)) => { + characters.append(&mut v); + dual_len += len; + }, + Err(e) => return Err(e) + } + + characters.push(0x2E); + + match parse_name_seg(&data[5..9]) { + Ok((mut v, len)) => { + characters.append(&mut v); + dual_len += len; + }, + Err(e) => return Err(e) + } + + Ok((characters, dual_len)) +} + +fn parse_multi_name_path(data: &[u8]) -> Result<(Vec<u8>, usize), AmlInternalError> { + parser_opcode!(data, 0x2F); + + let seg_count = data[1]; + if seg_count == 0x00 { + return Err(AmlInternalError::AmlParseError("MultiName Path - can't have zero name segments")); + } + + let mut current_seg = 0; + let mut characters: Vec<u8> = vec!(); + let mut multi_len: usize = 2; + + while current_seg < seg_count { + match parse_name_seg(&data[(current_seg as usize * 4) + 2 ..]) { + Ok((mut v, len)) => { + characters.append(&mut v); + multi_len += len; + }, + Err(e) => return Err(e) + } + + characters.push(0x2E); + + current_seg += 1; + } + + characters.pop(); + + Ok((characters, multi_len)) +} + +pub fn parse_super_name(data: &[u8]) -> Result<(SuperName, usize), AmlInternalError> { + parser_selector! { + data, + parse_simple_name, + parser_wrap!(SuperName::Type6OpCode, parse_type6_opcode), + parse_debug_obj + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +fn parse_debug_obj(data: &[u8]) -> Result<(SuperName, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x31); + Ok((SuperName::DebugObj, 2 as usize)) +} + +pub fn parse_simple_name(data: &[u8]) -> Result<(SuperName, usize), AmlInternalError> { + parser_selector! { + data, + parser_wrap!(SuperName::NameString, parse_name_string), + parser_wrap!(SuperName::ArgObj, parse_arg_obj), + parser_wrap!(SuperName::LocalObj, parse_local_obj) + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +pub fn parse_target(data: &[u8]) -> Result<(Target, usize), AmlInternalError> { + if data[0] == 0x00 { + Ok((Target::Null, 1 as usize)) + } else { + match parse_super_name(data) { + Ok((name, name_len)) => Ok((Target::SuperName(name), name_len)), + Err(e) => Err(e) + } + } +} diff --git a/src/acpi/aml/parsermacros.rs b/src/acpi/aml/parsermacros.rs new file mode 100644 index 0000000000000000000000000000000000000000..50e3aed575cc59feb62baca60c2e5db7636c92b3 --- /dev/null +++ b/src/acpi/aml/parsermacros.rs @@ -0,0 +1,49 @@ +#[macro_export] +macro_rules! parser_selector { + {$data:expr, $func:expr} => { + match $func($data) { + Ok(res) => return Ok(res), + Err(AmlInternalError::AmlInvalidOpCode) => (), + Err(e) => return Err(e) + } + }; + {$data:expr, $func:expr, $($funcs:expr),+} => { + parser_selector! {$data, $func}; + parser_selector! {$data, $($funcs),*}; + }; +} + +#[macro_export] +macro_rules! parser_wrap { + ($wrap:expr, $func:expr) => { + |data| { + match $func(data) { + Ok((res, size)) => Ok(($wrap(res), size)), + Err(e) => Err(e) + } + } + }; +} + +#[macro_export] +macro_rules! parser_opcode { + ($data:expr, $opcode:expr) => { + if $data[0] != $opcode { + return Err(AmlInternalError::AmlInvalidOpCode); + } + }; + ($data:expr, $opcode:expr, $alternate_opcode:expr) => { + if $data[0] != $opcode && $data[0] != $alternate_opcode { + return Err(AmlInternalError::AmlInvalidOpCode); + } + }; +} + +#[macro_export] +macro_rules! parser_opcode_extended { + ($data:expr, $opcode:expr) => { + if $data[0] != 0x5B || $data[1] != $opcode { + return Err(AmlInternalError::AmlInvalidOpCode); + } + }; +} diff --git a/src/acpi/aml/pkglength.rs b/src/acpi/aml/pkglength.rs new file mode 100644 index 0000000000000000000000000000000000000000..7c4ace8d124aea4f64ac9bc7c8740d38449451a4 --- /dev/null +++ b/src/acpi/aml/pkglength.rs @@ -0,0 +1,25 @@ +use super::AmlInternalError; + +pub fn parse_pkg_length(data: &[u8]) -> Result<(usize, usize), AmlInternalError> { + let lead_byte = data[0]; + let count_bytes: usize = (lead_byte >> 6) as usize; + + if count_bytes == 0 { + return Ok(((lead_byte & 0x3F) as usize, 1 as usize)); + } + + let upper_two = (lead_byte >> 4) & 0x03; + if upper_two != 0 { + return Err(AmlInternalError::AmlParseError("Invalid package length")); + } + + let mut current_byte = 0; + let mut pkg_len: usize = (lead_byte & 0x0F) as usize; + + while current_byte < count_bytes { + pkg_len += (data[1 + current_byte] as u32 * 16 * (256 as u32).pow(current_byte as u32)) as usize; + current_byte += 1; + } + + return Ok((pkg_len, count_bytes + 1)); +} diff --git a/src/acpi/aml/termlist.rs b/src/acpi/aml/termlist.rs new file mode 100644 index 0000000000000000000000000000000000000000..014bddb97f49f0ff48e706da87b280422c59303c --- /dev/null +++ b/src/acpi/aml/termlist.rs @@ -0,0 +1,135 @@ +use collections::vec::Vec; +use collections::boxed::Box; +use collections::string::String; + +use super::{AmlInternalError, AmlExecutable, AmlValue, AmlNamespace, get_namespace_string}; +use super::namespacemodifier::{parse_namespace_modifier, NamespaceModifier}; +use super::namedobj::{parse_named_obj, NamedObj}; +use super::dataobj::{parse_data_obj, parse_arg_obj, parse_local_obj, DataObj, ArgObj, LocalObj}; +use super::type1opcode::{parse_type1_opcode, Type1OpCode}; +use super::type2opcode::{parse_type2_opcode, Type2OpCode}; +use super::namestring::parse_name_string; + +#[derive(Debug, Clone)] +pub enum TermArg { + LocalObj(Box<LocalObj>), + DataObj(Box<DataObj>), + ArgObj(Box<ArgObj>), + Type2Opcode(Box<Type2OpCode>) +} + +#[derive(Debug, Clone)] +pub enum TermObj { + NamespaceModifier(Box<NamespaceModifier>), + NamedObj(Box<NamedObj>), + Type1Opcode(Box<Type1OpCode>), + Type2Opcode(Box<Type2OpCode>) +} + +#[derive(Debug, Clone)] +pub enum Object { + NamespaceModifier(Box<NamespaceModifier>), + NamedObj(Box<NamedObj>) +} + +#[derive(Debug, Clone)] +pub struct MethodInvocation { + +} + +impl AmlExecutable for Vec<TermObj> { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option<AmlValue> { + for term in self { + term.execute(namespace, scope.clone()); + } + + None + } +} + +impl AmlExecutable for TermArg { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option<AmlValue> { + match *self { + TermArg::LocalObj(ref l) => Some(AmlValue::Integer), + TermArg::DataObj(ref d) => d.execute(namespace, scope), + TermArg::ArgObj(ref a) => Some(AmlValue::Integer), + TermArg::Type2Opcode(ref o) => Some(AmlValue::Integer) + } + } +} + +impl AmlExecutable for TermObj { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option<AmlValue> { + match *self { + TermObj::NamespaceModifier(ref res) => res.execute(namespace, scope.clone()), + TermObj::NamedObj(ref res) => res.execute(namespace, scope.clone()), + TermObj::Type1Opcode(ref res) => res.execute(namespace, scope.clone()), + TermObj::Type2Opcode(ref res) => res.execute(namespace, scope.clone()) + } + } +} + +pub fn parse_term_list(data: &[u8]) -> Result<Vec<TermObj>, AmlInternalError> { + let mut terms: Vec<TermObj> = vec!(); + let mut current_offset: usize = 0; + + while current_offset < data.len() { + let (res, len) = parse_term_obj(&data[current_offset..])?; + terms.push(res); + current_offset += len; + } + + Ok(terms) +} + +pub fn parse_term_arg(data: &[u8]) -> Result<(TermArg, usize), AmlInternalError> { + parser_selector! { + data, + parser_wrap!(TermArg::LocalObj, parser_wrap!(Box::new, parse_local_obj)), + parser_wrap!(TermArg::DataObj, parser_wrap!(Box::new, parse_data_obj)), + parser_wrap!(TermArg::ArgObj, parser_wrap!(Box::new, parse_arg_obj)), + parser_wrap!(TermArg::Type2Opcode, parser_wrap!(Box::new, parse_type2_opcode)) + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +pub fn parse_object_list(data: &[u8]) -> Result<Vec<Object>, AmlInternalError> { + let mut terms: Vec<Object> = vec!(); + let mut current_offset: usize = 0; + + while current_offset < data.len() { + let (res, len) = parse_object(&data[current_offset..])?; + terms.push(res); + current_offset += len; + } + + Ok(terms) +} + +fn parse_object(data: &[u8]) -> Result<(Object, usize), AmlInternalError> { + parser_selector! { + data, + parser_wrap!(Object::NamespaceModifier, parser_wrap!(Box::new, parse_namespace_modifier)), + parser_wrap!(Object::NamedObj, parser_wrap!(Box::new, parse_named_obj)) + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +pub fn parse_method_invocation(data: &[u8]) -> Result<(MethodInvocation, usize), AmlInternalError> { + let (name, name_len) = parse_name_string(data)?; + Err(AmlInternalError::AmlDeferredLoad) +} + +fn parse_term_obj(data: &[u8]) -> Result<(TermObj, usize), AmlInternalError> { + parser_selector! { + data, + parser_wrap!(TermObj::NamespaceModifier, parser_wrap!(Box::new, parse_namespace_modifier)), + parser_wrap!(TermObj::NamedObj, parser_wrap!(Box::new, parse_named_obj)), + parser_wrap!(TermObj::Type1Opcode, parser_wrap!(Box::new, parse_type1_opcode)), + parser_wrap!(TermObj::Type2Opcode, parser_wrap!(Box::new, parse_type2_opcode)) + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} diff --git a/src/acpi/aml/type1opcode.rs b/src/acpi/aml/type1opcode.rs new file mode 100644 index 0000000000000000000000000000000000000000..c6cc5cab5e207962e9282ca09809cbae9974114b --- /dev/null +++ b/src/acpi/aml/type1opcode.rs @@ -0,0 +1,259 @@ +use collections::vec::Vec; +use collections::string::String; +use collections::boxed::Box; + +use super::{AmlInternalError, AmlExecutable, AmlValue, AmlNamespace}; +use super::pkglength::parse_pkg_length; +use super::termlist::{parse_term_arg, parse_term_list, TermObj, TermArg}; +use super::namestring::{parse_name_string, parse_super_name, SuperName}; + +#[derive(Debug, Clone)] +pub enum Type1OpCode { + DefBreak, + DefBreakPoint, + DefContinue, + DefFatal { + fatal_type: u8, + fatal_code: u16, + fatal_arg: TermArg + }, + DefNoop, + DefIfElse { + if_block: IfBlock, + else_block: IfBlock + }, + DefLoad { + name: String, + ddb_handle_object: SuperName + }, + DefNotify { + object: SuperName, + value: TermArg + }, + DefRelease(SuperName), + DefReset(SuperName), + DefSignal(SuperName), + DefSleep(TermArg), + DefStall(TermArg), + DefUnload(SuperName), + DefWhile { + predicate: TermArg, + block: Vec<TermObj> + }, + DefReturn(TermArg), + DeferredLoad(Vec<u8>) +} + +impl AmlExecutable for Type1OpCode { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option<AmlValue> { + None + } +} + +#[derive(Debug, Clone)] +pub enum IfBlock { + If { + predicate: TermArg, + if_block: Vec<TermObj> + }, + Else(Vec<TermObj>), + NoBlock, + DeferredLoad(Vec<u8>) +} + +pub fn parse_type1_opcode(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + match data[0] { + 0xA5 => return Ok((Type1OpCode::DefBreak, 1 as usize)), + 0xCC => return Ok((Type1OpCode::DefBreakPoint, 1 as usize)), + 0x9F => return Ok((Type1OpCode::DefContinue, 1 as usize)), + 0xA3 => return Ok((Type1OpCode::DefNoop, 1 as usize)), + _ => () + } + + parser_selector! { + data, + parse_def_fatal, + parse_def_if_else, + parse_def_load, + parse_def_notify, + parse_def_release, + parse_def_reset, + parse_def_signal, + parse_def_sleep, + parse_def_stall, + parse_def_return, + parse_def_unload, + parse_def_while + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +fn parse_def_fatal(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x32 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let fatal_type = data[2]; + let fatal_code: u16 = (data[3] as u16) + + ((data[4] as u16) << 8); + let (fatal_arg, fatal_arg_len) = parse_term_arg(&data[5..])?; + + Ok((Type1OpCode::DefFatal {fatal_type, fatal_code, fatal_arg}, fatal_arg_len + 5)) +} + +fn parse_def_load(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x20 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (name, name_len) = parse_name_string(&data[2..])?; + let (ddb_handle_object, ddb_handle_object_len) = parse_super_name(&data[2 + name_len..])?; + + Ok((Type1OpCode::DefLoad {name, ddb_handle_object}, 2 + name_len + ddb_handle_object_len)) +} + +fn parse_def_notify(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0x86 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (object, object_len) = parse_super_name(&data[1..])?; + let (value, value_len) = parse_term_arg(&data[1 + object_len..])?; + + Ok((Type1OpCode::DefNotify {object, value}, 1 + object_len + value_len)) +} + +fn parse_def_release(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x27 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (object, object_len) = parse_super_name(&data[2..])?; + + Ok((Type1OpCode::DefRelease(object), 2 + object_len)) +} + +fn parse_def_reset(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x26 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (object, object_len) = parse_super_name(&data[2..])?; + + Ok((Type1OpCode::DefReset(object), 2 + object_len)) +} + +fn parse_def_signal(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x24 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (object, object_len) = parse_super_name(&data[2..])?; + + Ok((Type1OpCode::DefSignal(object), 2 + object_len)) +} + +fn parse_def_sleep(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x22 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (time, time_len) = parse_term_arg(&data[2..])?; + + Ok((Type1OpCode::DefSleep(time), 2 + time_len)) +} + +fn parse_def_stall(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x21 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (time, time_len) = parse_term_arg(&data[2..])?; + + Ok((Type1OpCode::DefStall(time), 2 + time_len)) +} + +fn parse_def_unload(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x2A { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (object, object_len) = parse_super_name(&data[2..])?; + + Ok((Type1OpCode::DefUnload(object), 2 + object_len)) +} + +fn parse_def_if_else(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0xA0 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; + + let if_block = match parse_term_arg(&data[1 + pkg_length_len..]) { + Ok((predicate, predicate_len)) => { + match parse_term_list(&data[1 + pkg_length_len + predicate_len .. 1 + pkg_length]) { + Ok(if_block) => IfBlock::If {predicate, if_block}, + Err(AmlInternalError::AmlDeferredLoad) => + IfBlock::DeferredLoad(data[0 .. 1 + pkg_length].to_vec()), + Err(e) => return Err(e) + } + }, + Err(AmlInternalError::AmlDeferredLoad) => + IfBlock::DeferredLoad(data[0 .. 1 + pkg_length].to_vec()), + Err(e) => return Err(e) + }; + + let (else_block, else_block_len) = parse_def_else(&data[1 + pkg_length..])?; + + return Ok((Type1OpCode::DefIfElse {if_block, else_block}, + pkg_length + else_block_len + 1)); +} + +fn parse_def_else(data: &[u8]) -> Result<(IfBlock, usize), AmlInternalError> { + if data.len() == 0 || data[0] != 0xA1 { + // We might be at the very end of a buffer, in which case there isn't an else + return Ok((IfBlock::NoBlock, 0)); + } + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; + match parse_term_list(&data[1 + pkg_length_len .. 1 + pkg_length]) { + Ok(term_list) => Ok((IfBlock::Else(term_list), 1 + pkg_length)), + Err(AmlInternalError::AmlDeferredLoad) => + Ok((IfBlock::DeferredLoad(data[0 .. 1 + pkg_length].to_vec()), 1 + pkg_length)), + Err(e) => return Err(e) + } +} + +fn parse_def_while(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0xA2 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; + let (predicate, predicate_len) = match parse_term_arg(&data[1 + pkg_length_len..]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((Type1OpCode::DeferredLoad(data[0 .. 1 + pkg_length].to_vec()), 1 + pkg_length)), + Err(e) => return Err(e) + }; + let block = match parse_term_list(&data[1 + pkg_length_len + predicate_len .. 1 + pkg_length]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((Type1OpCode::DeferredLoad(data[0 .. 1 + pkg_length].to_vec()), 1 + pkg_length)), + Err(e) => return Err(e) + }; + + Ok((Type1OpCode::DefWhile {predicate, block}, pkg_length + 1)) +} + +fn parse_def_return(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0xA4 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (arg_object, arg_object_len) = parse_term_arg(&data[1..])?; + + Ok((Type1OpCode::DefReturn(arg_object), 1 + arg_object_len)) +} diff --git a/src/acpi/aml/type2opcode.rs b/src/acpi/aml/type2opcode.rs new file mode 100644 index 0000000000000000000000000000000000000000..50d1ff2ea228ddd22b12428eaa21ccaf2b9579d1 --- /dev/null +++ b/src/acpi/aml/type2opcode.rs @@ -0,0 +1,932 @@ +use collections::vec::Vec; +use collections::string::String; +use collections::boxed::Box; + +use super::{AmlInternalError, AmlExecutable, AmlValue, AmlNamespace}; +use super::pkglength::parse_pkg_length; +use super::termlist::{parse_term_arg, parse_method_invocation, TermArg, MethodInvocation}; +use super::namestring::{parse_super_name, parse_target, parse_name_string, parse_simple_name, + SuperName, Target}; +use super::dataobj::{parse_data_ref_obj, DataRefObj}; + +#[derive(Debug, Clone)] +pub enum Type2OpCode { + DefAcquire { + object: SuperName, + timeout: u16 + }, + DefBuffer(DefBuffer), + DefPackage(DefPackage), + DefVarPackage(DefVarPackage), + DefDerefOf(TermArg), + DefRefOf(SuperName), + DefIncrement(SuperName), + DefIndex(DefIndex), + DefDecrement(SuperName), + DefFindSetLeftBit { + operand: TermArg, + target: Target + }, + DefFindSetRightBit { + operand: TermArg, + target: Target + }, + DefFromBCD { + operand: TermArg, + target: Target + }, + DefDivide { + dividend: TermArg, + divisor: TermArg, + remainder: Target, + quotient: Target + }, + DefCondRefOf { + operand: SuperName, + target: Target + }, + DefCopyObject { + source: TermArg, + destination: SuperName + }, + DefLAnd { + lhs: TermArg, + rhs: TermArg + }, + DefLEqual { + lhs: TermArg, + rhs: TermArg + }, + DefLGreater { + lhs: TermArg, + rhs: TermArg + }, + DefLLess { + lhs: TermArg, + rhs: TermArg + }, + DefLNot(TermArg), + DefLOr { + lhs: TermArg, + rhs: TermArg + }, + DefSizeOf(SuperName), + DefStore { + operand: TermArg, + target: SuperName + }, + DefSubtract { + minuend: TermArg, + subtrahend: TermArg, + target: Target + }, + DefToBuffer { + operand: TermArg, + target: Target + }, + DefToHexString { + operand: TermArg, + target: Target + }, + DefToBCD { + operand: TermArg, + target: Target + }, + DefToDecimalString { + operand: TermArg, + target: Target + }, + DefToInteger { + operand: TermArg, + target: Target + }, + DefToString { + operand: TermArg, + length: TermArg, + target: Target + }, + DefConcat { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefConcatRes { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefShiftLeft { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefShiftRight { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefAdd { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefMultiply { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefMod { + dividend: TermArg, + divisor: TermArg, + target: Target + }, + DefAnd { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefNAnd { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefOr { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefXor { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefNOr { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefNot { + operand: TermArg, + target: Target + }, + DefLoadTable { + signature: TermArg, + oem_id: TermArg, + oem_table_id: TermArg, + root_path: TermArg, + parameter_path: TermArg, + parameter_data: TermArg + }, + DefMatch { + search_pkg: TermArg, + first_operation: MatchOpcode, + first_operand: TermArg, + second_operation: MatchOpcode, + second_operand: TermArg, + start_index: TermArg + }, + DefMid { + source: TermArg, + index: TermArg, + length: TermArg, + target: Target + }, + DefWait { + event_object: SuperName, + operand: TermArg + }, + DefObjectType(DefObjectType), + DefTimer, + MethodInvocation(MethodInvocation) +} + +impl AmlExecutable for Type2OpCode { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option<AmlValue> { + None + } +} + +#[derive(Debug, Clone)] +pub enum DefObjectType { + SuperName(SuperName), + DefIndex(DefIndex), + DefRefOf(SuperName), + DefDerefOf(TermArg) +} + +#[derive(Debug, Clone)] +pub enum MatchOpcode { + MTR, + MEQ, + MLE, + MLT, + MGE, + MGT +} + +#[derive(Debug, Clone)] +pub enum Type6OpCode { + DefDerefOf(TermArg), + DefRefOf(Box<SuperName>), + DefIndex(DefIndex), + MethodInvocation(MethodInvocation) +} + +#[derive(Debug, Clone)] +pub struct DefIndex { + obj: TermArg, + idx: TermArg, + target: Box<Target> +} + +#[derive(Debug, Clone)] +pub enum DefBuffer { + Buffer { + buffer_size: TermArg, + byte_list: Vec<u8> + }, + DeferredLoad(Vec<u8>) +} + +#[derive(Debug, Clone)] +pub enum DefPackage { + Package { + num_elements: u8, + elements: Vec<PackageElement> + }, + DeferredLoad(Vec<u8>) +} + +#[derive(Debug, Clone)] +pub enum DefVarPackage { + Package { + num_elements: TermArg, + elements: Vec<PackageElement> + }, + DeferredLoad(Vec<u8>) +} + +#[derive(Debug, Clone)] +pub enum PackageElement { + DataRefObj(DataRefObj), + NameString(String) +} + +impl AmlExecutable for DefPackage { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option<AmlValue> { + match *self { + DefPackage::Package { ref num_elements, ref elements } => { + let mut values: Vec<AmlValue> = vec!(); + + for element in elements { + match *element { + PackageElement::DataRefObj(ref d) => { + let elem = match d.execute(namespace, scope.clone()) { + Some(e) => e, + None => continue + }; + + values.push(elem); + }, + _ => return None + } + } + + Some(AmlValue::Package(values)) + }, + _ => None + } + } +} + +pub fn parse_type2_opcode(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_selector! { + data, + parse_def_increment, + parse_def_acquire, + parse_def_wait, + parse_def_land, + parse_def_lequal, + parse_def_lgreater, + parse_def_lless, + parse_def_lnot, + parse_def_lor, + parse_def_size_of, + parse_def_store, + parse_def_subtract, + parse_def_to_buffer, + parse_def_to_hex_string, + parse_def_to_bcd, + parse_def_to_decimal_string, + parse_def_to_integer, + parse_def_to_string, + parse_def_add, + parse_def_xor, + parse_def_shift_left, + parse_def_shift_right, + parse_def_mod, + parse_def_and, + parse_def_or, + parse_def_concat_res, + parse_def_concat, + parse_def_cond_ref_of, + parse_def_copy_object, + parse_def_decrement, + parse_def_divide, + parse_def_find_set_left_bit, + parse_def_find_set_right_bit, + parse_def_from_bcd, + parse_def_load_table, + parse_def_match, + parse_def_mid, + parse_def_multiply, + parse_def_nand, + parse_def_nor, + parse_def_not, + parse_def_timer, + parser_wrap!(Type2OpCode::DefBuffer, parse_def_buffer), + parser_wrap!(Type2OpCode::DefPackage, parse_def_package), + parser_wrap!(Type2OpCode::DefVarPackage, parse_def_var_package), + parser_wrap!(Type2OpCode::DefObjectType, parse_def_object_type), + parser_wrap!(Type2OpCode::DefDerefOf, parse_def_deref_of), + parser_wrap!(Type2OpCode::DefRefOf, parse_def_ref_of), + parser_wrap!(Type2OpCode::DefIndex, parse_def_index), + parser_wrap!(Type2OpCode::MethodInvocation, parse_method_invocation) + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +pub fn parse_type6_opcode(data: &[u8]) -> Result<(Type6OpCode, usize), AmlInternalError> { + parser_selector! { + data, + parser_wrap!(Type6OpCode::DefDerefOf, parse_def_deref_of), + parser_wrap!(Type6OpCode::DefRefOf, parser_wrap!(Box::new, parse_def_ref_of)), + parser_wrap!(Type6OpCode::DefIndex, parse_def_index), + parser_wrap!(Type6OpCode::MethodInvocation, parse_method_invocation) + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +pub fn parse_def_object_type(data: &[u8]) -> Result<(DefObjectType, usize), AmlInternalError> { + parser_opcode!(data, 0x8E); + parser_selector! { + data, + parser_wrap!(DefObjectType::SuperName, parse_super_name), + parser_wrap!(DefObjectType::DefRefOf, parse_def_ref_of), + parser_wrap!(DefObjectType::DefDerefOf, parse_def_deref_of), + parser_wrap!(DefObjectType::DefIndex, parse_def_index) + } + + Err(AmlInternalError::AmlInvalidOpCode) +} + +pub fn parse_def_package(data: &[u8]) -> Result<(DefPackage, usize), AmlInternalError> { + parser_opcode!(data, 0x12); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; + let num_elements = data[1 + pkg_length_len]; + + let elements = match parse_package_elements_list(&data[2 + pkg_length_len .. 1 + pkg_length]) { + Ok(e) => e, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((DefPackage::DeferredLoad(data[0 .. 1 + pkg_length].to_vec()), 1 + pkg_length)), + Err(e) => return Err(e) + }; + + Ok((DefPackage::Package {num_elements, elements}, 1 + pkg_length)) +} + +pub fn parse_def_var_package(data: &[u8]) -> Result<(DefVarPackage, usize), AmlInternalError> { + parser_opcode!(data, 0x13); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; + let (num_elements, num_elements_len) = parse_term_arg(&data[1 + pkg_length_len ..])?; + + let elements = match parse_package_elements_list(&data[1 + pkg_length_len + num_elements_len .. + 1 + pkg_length]) { + Ok(e) => e, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((DefVarPackage::DeferredLoad(data[0 .. 1 + pkg_length].to_vec()), + 1 + pkg_length)), + Err(e) => return Err(e) + }; + + Ok((DefVarPackage::Package {num_elements, elements}, 1 + pkg_length)) +} + +fn parse_package_elements_list(data: &[u8]) -> Result<Vec<PackageElement>, AmlInternalError> { + let mut current_offset: usize = 0; + let mut elements: Vec<PackageElement> = vec!(); + + while current_offset < data.len() { + match parse_data_ref_obj(&data[current_offset ..]) { + Ok((data_ref_obj, data_ref_obj_len)) => { + elements.push(PackageElement::DataRefObj(data_ref_obj)); + current_offset += data_ref_obj_len; + }, + Err(AmlInternalError::AmlInvalidOpCode) => + match parse_name_string(&data[current_offset ..]) { + Ok((name_string, name_string_len)) => { + elements.push(PackageElement::NameString(name_string)); + current_offset += name_string_len; + }, + Err(e) => return Err(e) + }, + Err(e) => return Err(e) + } + } + + Ok(elements) +} + +pub fn parse_def_buffer(data: &[u8]) -> Result<(DefBuffer, usize), AmlInternalError> { + parser_opcode!(data, 0x11); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; + let (buffer_size, buffer_size_len) = match parse_term_arg(&data[1 + pkg_length_len..]) { + Ok(s) => s, + Err(AmlInternalError::AmlDeferredLoad) => return Ok((DefBuffer::DeferredLoad( + data[0 .. 1 + pkg_length].to_vec() + ), 1 + pkg_length)), + Err(e) => return Err(e), + }; + let byte_list = data[1 + pkg_length_len + buffer_size_len .. 1 + pkg_length].to_vec(); + + Ok((DefBuffer::Buffer {buffer_size, byte_list}, pkg_length + 1)) +} + +fn parse_def_ref_of(data: &[u8]) -> Result<(SuperName, usize), AmlInternalError> { + parser_opcode!(data, 0x71); + let (obj_reference, obj_reference_len) = parse_super_name(&data[1..])?; + + Ok((obj_reference, obj_reference_len + 1)) +} + +fn parse_def_deref_of(data: &[u8]) -> Result<(TermArg, usize), AmlInternalError> { + parser_opcode!(data, 0x83); + let (obj_reference, obj_reference_len) = parse_term_arg(&data[1..])?; + + Ok((obj_reference, obj_reference_len + 1)) +} + +fn parse_def_acquire(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x23); + + let (object, object_len) = parse_super_name(&data[2..])?; + let timeout = (data[2 + object_len] as u16) + + ((data[3 + object_len] as u16) << 8); + + Ok((Type2OpCode::DefAcquire {object, timeout}, object_len + 4)) +} + +fn parse_def_increment(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x75); + + let (obj, obj_len) = parse_super_name(&data[1..])?; + Ok((Type2OpCode::DefIncrement(obj), obj_len + 1)) +} + +fn parse_def_index(data: &[u8]) -> Result<(DefIndex, usize), AmlInternalError> { + parser_opcode!(data, 0x88); + + let (obj, obj_len) = parse_term_arg(&data[1..])?; + let (idx, idx_len) = parse_term_arg(&data[1 + obj_len..])?; + let (target, target_len) = parse_target(&data[1 + obj_len + idx_len..])?; + + Ok((DefIndex {obj, idx, target: Box::new(target)}, 1 + obj_len + idx_len + target_len)) +} + +fn parse_def_land(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x90); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + + Ok((Type2OpCode::DefLAnd {lhs, rhs}, 1 + lhs_len + rhs_len)) +} + +fn parse_def_lequal(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x93); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + + Ok((Type2OpCode::DefLEqual {lhs, rhs}, 1 + lhs_len + rhs_len)) +} + +fn parse_def_lgreater(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x94); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + + Ok((Type2OpCode::DefLGreater {lhs, rhs}, 1 + lhs_len + rhs_len)) +} + +fn parse_def_lless(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x95); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + + Ok((Type2OpCode::DefLLess {lhs, rhs}, 1 + lhs_len + rhs_len)) +} + +fn parse_def_lnot(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x92); + + let (operand, operand_len) = parse_term_arg(&data[1..])?; + + Ok((Type2OpCode::DefLNot(operand), 1 + operand_len)) +} + +fn parse_def_lor(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x91); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + + Ok((Type2OpCode::DefLOr {lhs, rhs}, 1 + lhs_len + rhs_len)) +} + +fn parse_def_to_hex_string(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x98); + + let (operand, operand_len) = parse_term_arg(&data[1..])?; + let (target, target_len) = parse_target(&data[1 + operand_len..])?; + + Ok((Type2OpCode::DefToHexString {operand, target}, 1 + operand_len + target_len)) +} + +fn parse_def_to_buffer(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x96); + + let (operand, operand_len) = parse_term_arg(&data[1..])?; + let (target, target_len) = parse_target(&data[1 + operand_len..])?; + + Ok((Type2OpCode::DefToBuffer {operand, target}, 1 + operand_len + target_len)) +} + +fn parse_def_to_bcd(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x29); + + let (operand, operand_len) = parse_term_arg(&data[2..])?; + let (target, target_len) = parse_target(&data[2 + operand_len..])?; + + Ok((Type2OpCode::DefToBCD {operand, target}, 2 + operand_len + target_len)) +} + +fn parse_def_to_decimal_string(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x97); + + let (operand, operand_len) = parse_term_arg(&data[1..])?; + let (target, target_len) = parse_target(&data[1 + operand_len..])?; + + Ok((Type2OpCode::DefToDecimalString {operand, target}, 1 + operand_len + target_len)) +} + +fn parse_def_to_integer(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x99); + + let (operand, operand_len) = parse_term_arg(&data[1..])?; + let (target, target_len) = parse_target(&data[1 + operand_len..])?; + + Ok((Type2OpCode::DefToInteger {operand, target}, 1 + operand_len + target_len)) +} + +fn parse_def_to_string(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x9C); + + let (operand, operand_len) = parse_term_arg(&data[1..])?; + let (length, length_len) = parse_term_arg(&data[1 + operand_len..])?; + let (target, target_len) = parse_target(&data[1 + operand_len + length_len..])?; + + Ok((Type2OpCode::DefToString {operand, length, target}, 1 + operand_len + length_len + target_len)) +} + +fn parse_def_subtract(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x74); + + let (minuend, minuend_len) = parse_term_arg(&data[1..])?; + let (subtrahend, subtrahend_len) = parse_term_arg(&data[1 + minuend_len..])?; + let (target, target_len) = parse_target(&data[1 + minuend_len + subtrahend_len..])?; + + Ok((Type2OpCode::DefSubtract {minuend, subtrahend, target}, 1 + minuend_len + subtrahend_len + target_len)) +} + +fn parse_def_size_of(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x87); + + let (name, name_len) = parse_super_name(&data[1..])?; + Ok((Type2OpCode::DefSizeOf(name), name_len + 1)) +} + +fn parse_def_store(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x70); + + let (operand, operand_len) = parse_term_arg(&data[1..])?; + let (target, target_len) = parse_super_name(&data[1 + operand_len..])?; + + Ok((Type2OpCode::DefStore {operand, target}, operand_len + target_len + 1)) +} + +fn parse_def_or(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x7D); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefOr {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_shift_left(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x79); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefShiftLeft {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_shift_right(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x7A); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefShiftRight {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_add(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x72); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefAdd {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_and(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x7B); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefAnd {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_xor(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x7F); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefXor {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_concat_res(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x84); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefConcatRes {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_wait(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x25); + + let (event_object, event_object_len) = parse_super_name(&data[2..])?; + let (operand, operand_len) = parse_term_arg(&data[2 + event_object_len..])?; + + + Ok((Type2OpCode::DefWait {event_object, operand}, 2 + event_object_len + operand_len)) +} + +fn parse_def_cond_ref_of(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x12); + + let (operand, operand_len) = parse_super_name(&data[2..])?; + let (target, target_len) = parse_target(&data[2 + operand_len..])?; + + Ok((Type2OpCode::DefCondRefOf {operand, target}, 2 + operand_len + target_len)) +} + +fn parse_def_copy_object(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x9D); + + let (source, source_len) = parse_term_arg(&data[1..])?; + let (destination, destination_len) = parse_simple_name(&data[1 + source_len..])?; + + Ok((Type2OpCode::DefCopyObject {source, destination}, 1 + source_len + destination_len)) +} + +fn parse_def_concat(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x73); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefConcat {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_decrement(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x76); + + let (target, target_len) = parse_super_name(&data[1..])?; + + Ok((Type2OpCode::DefDecrement(target), 1 + target_len)) +} + +fn parse_def_divide(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x78); + + let (dividend, dividend_len) = parse_term_arg(&data[1..])?; + let (divisor, divisor_len) = parse_term_arg(&data[1 + dividend_len..])?; + let (remainder, remainder_len) = parse_target(&data[1 + dividend_len + divisor_len..])?; + let (quotient, quotient_len) = parse_target(&data[1 + dividend_len + divisor_len + remainder_len..])?; + + Ok((Type2OpCode::DefDivide {dividend, divisor, remainder, quotient}, + 1 + dividend_len + divisor_len + remainder_len + quotient_len)) +} + +fn parse_def_find_set_left_bit(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x81); + + let (operand, operand_len) = parse_term_arg(&data[1..])?; + let (target, target_len) = parse_target(&data[1 + operand_len..])?; + + Ok((Type2OpCode::DefFindSetLeftBit {operand, target}, 1 + operand_len + target_len)) +} + +fn parse_def_find_set_right_bit(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x82 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (operand, operand_len) = parse_term_arg(&data[1..])?; + let (target, target_len) = parse_target(&data[1 + operand_len..])?; + + Ok((Type2OpCode::DefFindSetRightBit {operand, target}, 1 + operand_len + target_len)) +} + +fn parse_def_load_table(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x1F { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (signature, signature_len) = parse_term_arg(&data[2..])?; + let (oem_id, oem_id_len) = parse_term_arg(&data[2 + signature_len..])?; + let (oem_table_id, oem_table_id_len) = parse_term_arg(&data[2 + signature_len + oem_id_len..])?; + let (root_path, root_path_len) = + parse_term_arg(&data[2 + signature_len + oem_id_len + oem_table_id_len..])?; + let (parameter_path, parameter_path_len) = + parse_term_arg(&data[2 + signature_len + oem_id_len + oem_table_id_len + root_path_len..])?; + let (parameter_data, parameter_data_len) = + parse_term_arg(&data[2 + signature_len + oem_id_len + oem_table_id_len + root_path_len + + parameter_path_len..])?; + + Ok((Type2OpCode::DefLoadTable {signature, oem_id, oem_table_id, root_path, + parameter_path, parameter_data}, + 2 + signature_len + oem_id_len + oem_table_id_len + root_path_len + + parameter_path_len + parameter_data_len)) +} + +fn parse_def_match(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x89 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (search_pkg, search_pkg_len) = parse_term_arg(&data[1..])?; + let first_operation = match data[1 + search_pkg_len] { + 0 => MatchOpcode::MTR, + 1 => MatchOpcode::MEQ, + 2 => MatchOpcode::MLE, + 3 => MatchOpcode::MLT, + 4 => MatchOpcode::MGE, + 5 => MatchOpcode::MGT, + _ => return Err(AmlInternalError::AmlParseError("DefMatch - Invalid Opcode")) + }; + let (first_operand, first_operand_len) = parse_term_arg(&data[2 + search_pkg_len..])?; + + let second_operation = match data[2 + search_pkg_len + first_operand_len] { + 0 => MatchOpcode::MTR, + 1 => MatchOpcode::MEQ, + 2 => MatchOpcode::MLE, + 3 => MatchOpcode::MLT, + 4 => MatchOpcode::MGE, + 5 => MatchOpcode::MGT, + _ => return Err(AmlInternalError::AmlParseError("DefMatch - Invalid Opcode")) + }; + let (second_operand, second_operand_len) = + parse_term_arg(&data[3 + search_pkg_len + first_operand_len..])?; + + let (start_index, start_index_len) = + parse_term_arg(&data[3 + search_pkg_len + first_operand_len + second_operand_len..])?; + + Ok((Type2OpCode::DefMatch {search_pkg, first_operation, first_operand, + second_operation, second_operand, start_index}, + 3 + search_pkg_len + first_operand_len + second_operand_len + start_index_len)) +} + +fn parse_def_from_bcd(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x28 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (operand, operand_len) = parse_term_arg(&data[2..])?; + let (target, target_len) = parse_target(&data[2 + operand_len..])?; + + Ok((Type2OpCode::DefFromBCD {operand, target}, 2 + operand_len + target_len)) +} + +fn parse_def_mid(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x9E { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (source, source_len) = parse_term_arg(&data[1..])?; + let (index, index_len) = parse_term_arg(&data[1 + source_len..])?; + let (length, length_len) = parse_term_arg(&data[1 + source_len + index_len..])?; + let (target, target_len) = parse_target(&data[1 + source_len + index_len + length_len..])?; + + Ok((Type2OpCode::DefMid {source, index, length, target}, + 1 + source_len + index_len + length_len + target_len)) +} + +fn parse_def_mod(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x85 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (dividend, dividend_len) = parse_term_arg(&data[1..])?; + let (divisor, divisor_len) = parse_term_arg(&data[1 + dividend_len..])?; + let (target, target_len) = parse_target(&data[1 + dividend_len + divisor_len..])?; + + Ok((Type2OpCode::DefMod {dividend, divisor, target}, 1 + dividend_len + divisor_len + target_len)) +} + +fn parse_def_multiply(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x77 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefMultiply {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_nand(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x7C { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefNAnd {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_nor(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x7E { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefNOr {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_not(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x80 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (operand, operand_len) = parse_term_arg(&data[1..])?; + let (target, target_len) = parse_target(&data[1 + operand_len..])?; + + Ok((Type2OpCode::DefNot {operand, target}, 1 + operand_len + target_len)) +} + +fn parse_def_timer(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x33 { + return Err(AmlInternalError::AmlInvalidOpCode) + } + + Ok((Type2OpCode::DefTimer, 2 as usize)) +} diff --git a/src/acpi/dsdt.rs b/src/acpi/dsdt.rs deleted file mode 100644 index 67bcb7f96812b08992eee144b6bd08ec227d1b17..0000000000000000000000000000000000000000 --- a/src/acpi/dsdt.rs +++ /dev/null @@ -1,78 +0,0 @@ -use core::slice; - -use super::sdt::Sdt; - -#[derive(Debug)] -pub struct Dsdt(&'static Sdt); - -impl Dsdt { - pub fn new(sdt: &'static Sdt) -> Option<Dsdt> { - if &sdt.signature == b"DSDT" { - Some(Dsdt(sdt)) - } else { - None - } - } - - pub fn data(&self) -> &[u8] { - unsafe { slice::from_raw_parts(self.0.data_address() as *const u8, self.0.data_len()) } - } - - pub fn slp_typ(&self) -> Option<(u16, u16)> { - // Code from http://forum.osdev.org/viewtopic.php?t=16990, should be adapted - - let mut i = 0; - let data = self.data(); - - // search the \_S5 package in the DSDT - let s5_a = b"\x08_S5_\x12"; - let s5_b = b"\x08\\_S5_\x12"; - while i < data.len() { - if data[i..].starts_with(s5_a) { - i += s5_a.len(); - break; - } else if data[i..].starts_with(s5_b) { - i += s5_b.len(); - break; - } else { - i += 1; - } - } - - if i >= data.len() { - return None; - } - - // check if \_S5 was found - let pkglen = ((data[i] & 0xC0) >> 6) + 2; - i += pkglen as usize; - if i >= data.len() { - return None; - } - - if data[i] == 0x0A { - i += 1; // skip byteprefix - if i >= data.len() { - return None; - } - } - - let a = (data[i] as u16) << 10; - i += 1; - if i >= data.len() { - return None; - } - - if data[i] == 0x0A { - i += 1; // skip byteprefix - if i >= data.len() { - return None; - } - } - - let b = (data[i] as u16) << 10; - - Some((a, b)) - } - -} diff --git a/src/acpi/mod.rs b/src/acpi/mod.rs index 751044a8bbdcca8225f9a51002b74ea319313395..54a55e5a16fc5d0f66471abf1b315c1e817f9ec6 100644 --- a/src/acpi/mod.rs +++ b/src/acpi/mod.rs @@ -13,20 +13,21 @@ use paging::{entry, ActivePageTable, Page, PhysicalAddress, VirtualAddress}; use start::{kstart_ap, CPU_COUNT, AP_READY}; use self::dmar::{Dmar, DmarEntry}; -use self::dsdt::Dsdt; use self::fadt::Fadt; use self::madt::{Madt, MadtEntry}; use self::rsdt::Rsdt; use self::sdt::Sdt; use self::xsdt::Xsdt; +use self::aml::{is_aml_table, parse_aml_table, AmlNamespace, AmlError}; + mod dmar; -mod dsdt; mod fadt; mod madt; mod rsdt; mod sdt; mod xsdt; +mod aml; const TRAMPOLINE: usize = 0x7E00; const AP_STARTUP: usize = TRAMPOLINE + 512; @@ -70,9 +71,6 @@ fn parse_sdt(sdt: &'static Sdt, active_table: &mut ActivePageTable) { let dsdt = get_sdt(fadt.dsdt as usize, active_table); parse_sdt(dsdt, active_table); ACPI_TABLE.lock().fadt = Some(fadt); - } else if let Some(dsdt) = Dsdt::new(sdt) { - println!(": {}", dsdt.data().len()); - ACPI_TABLE.lock().dsdt = Some(dsdt); } else if let Some(madt) = Madt::new(sdt) { println!(": {:>08X}: {}", madt.local_address, madt.flags); @@ -197,6 +195,17 @@ fn parse_sdt(sdt: &'static Sdt, active_table: &mut ActivePageTable) { _ => () } } + } else if is_aml_table(sdt) { + ACPI_TABLE.lock().namespace = match parse_aml_table(sdt) { + Ok(res) => { + println!(": Parsed"); + Some(res) + }, + Err(AmlError::AmlParseError(e)) => { + println!(": {}", e); + None + } + }; } else { println!(": Unknown"); } @@ -259,10 +268,10 @@ pub unsafe fn init(active_table: &mut ActivePageTable) { pub struct Acpi { pub fadt: Option<Fadt>, - pub dsdt: Option<Dsdt>, + pub namespace: Option<AmlNamespace>, } -pub static ACPI_TABLE: Mutex<Acpi> = Mutex::new(Acpi { fadt: None, dsdt: None }); +pub static ACPI_TABLE: Mutex<Acpi> = Mutex::new(Acpi { fadt: None, namespace: None }); /// RSDP #[derive(Copy, Clone, Debug)] diff --git a/src/acpi/sdt.rs b/src/acpi/sdt.rs index 0d8cedd6bed1a3848d22c2f749950d0a3dc24792..62d55cf472bb0e97ce31e68dc6f6d23be494a5a0 100644 --- a/src/acpi/sdt.rs +++ b/src/acpi/sdt.rs @@ -1,4 +1,5 @@ use core::mem; +use core::slice; #[derive(Copy, Clone, Debug)] #[repr(packed)] @@ -30,4 +31,8 @@ impl Sdt { 0 } } + + pub fn data(&'static self) -> &[u8] { + unsafe { slice::from_raw_parts(self.data_address() as *const u8, self.data_len()) } + } } diff --git a/src/stop.rs b/src/stop.rs index db2dfd6e6f63dfb0f7943b9be0a6e656cc796e80..7a9ac751d98907c1ca83fe75894b3a3ee3335e08 100644 --- a/src/stop.rs +++ b/src/stop.rs @@ -11,12 +11,18 @@ pub unsafe extern fn kstop() -> ! { if let Some(ref fadt) = acpi.fadt { let port = fadt.pm1a_control_block as u16; let mut val = 1 << 13; - if let Some(ref dsdt) = acpi.dsdt { - if let Some((a, b)) = dsdt.slp_typ() { - println!("Shutdown SLP_TYPa {:X}, SLP_TYPb {:X}", a, b); - val |= a; + if let Some(ref namespace) = acpi.namespace { + if let Some(s) = namespace.find_str("\\_S5") { + if let Some(p) = s.get_as_package() { + let slp_typa = p[0].get_as_integer().expect("SLP_TYPa is not an integer"); + let slp_typb = p[1].get_as_integer().expect("SLP_TYPb is not an integer"); + + println!("Shutdown SLP_TYPa {:X}, SLP_TYPb {:X}", slp_typa, slp_typb); + val |= slp_typa as u16; + } } } + println!("Shutdown with ACPI outw(0x{:X}, 0x{:X})", port, val); Pio::<u16>::new(port).write(val); }