diff --git a/src/acpi/aml/dataobj.rs b/src/acpi/aml/dataobj.rs index 4400c8d87c12c712529d9c5d89c7adbe51d180f2..ba6e0f0e8cba2291ea4e2481e87efe47e0fdef4f 100644 --- a/src/acpi/aml/dataobj.rs +++ b/src/acpi/aml/dataobj.rs @@ -1,131 +1,134 @@ 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) - } +use super::AmlError; +use super::parser::{ AmlParseType, ParseResult, AmlExecutionContext, ExecutionState }; +use super::namespace::{ AmlValue, ObjectReference }; + +use super::type2opcode::{parse_def_buffer, parse_def_package, parse_def_var_package}; +use super::termlist::parse_term_arg; +use super::namestring::parse_super_name; + +pub fn parse_data_obj(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) } -} - -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) + data, ctx, + parse_computational_data, + parse_def_package, + parse_def_var_package }; - Err(AmlInternalError::AmlInvalidOpCode) + Err(AmlError::AmlInvalidOpCode) } -pub fn parse_data_ref_obj(data: &[u8]) -> Result<(DataRefObj, usize), AmlInternalError> { +pub fn parse_data_ref_obj(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + parser_selector! { - data, - parser_wrap!(DataRefObj::DataObj, parse_data_obj), - parser_wrap!(DataRefObj::ObjectReference, parse_term_arg), - parser_wrap!(DataRefObj::DDBHandle, parse_super_name) + data, ctx, + parse_data_obj, + parse_term_arg }; - Err(AmlInternalError::AmlInvalidOpCode) + match parse_super_name(data, ctx) { + Ok(res) => match res.val { + AmlValue::String(s) => Ok(AmlParseType { + val: AmlValue::ObjectReference(ObjectReference::Object(s)), + len: res.len + }), + _ => Ok(res) + }, + Err(e) => Err(e) + } } -pub fn parse_arg_obj(data: &[u8]) -> Result<(ArgObj, usize), AmlInternalError> { +pub fn parse_arg_obj(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + match data[0] { - 0x68 ... 0x6E => Ok((ArgObj(data[0] - 0x68), 1 as usize)), - _ => Err(AmlInternalError::AmlInvalidOpCode) + 0x68 ... 0x6E => Ok(AmlParseType { + val: AmlValue::ObjectReference(ObjectReference::ArgObj(data[0] - 0x68)), + len: 1 as usize + }), + _ => Err(AmlError::AmlInvalidOpCode) } } -pub fn parse_local_obj(data: &[u8]) -> Result<(LocalObj, usize), AmlInternalError> { +pub fn parse_local_obj(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + match data[0] { - 0x60 ... 0x67 => Ok((LocalObj(data[0] - 0x60), 1 as usize)), - _ => Err(AmlInternalError::AmlInvalidOpCode) + 0x68 ... 0x6E => Ok(AmlParseType { + val: AmlValue::ObjectReference(ObjectReference::LocalObj(data[0] - 0x60)), + len: 1 as usize + }), + _ => Err(AmlError::AmlInvalidOpCode) } } -fn parse_computational_data(data: &[u8]) -> Result<(ComputationalData, usize), AmlInternalError> { +fn parse_computational_data(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + match data[0] { - 0x0A => Ok((ComputationalData::Byte(data[1]), 2 as usize)), + 0x0A => Ok(AmlParseType { + val: AmlValue::Integer(data[1] as u64), + len: 2 as usize + }), 0x0B => { let res = (data[1] as u16) + ((data[2] as u16) << 8); - Ok((ComputationalData::Word(res), 3 as usize)) + + Ok(AmlParseType { + val: AmlValue::Integer(res as u64), + len: 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)) + + Ok(AmlParseType { + val: AmlValue::Integer(res as u64), + len: 5 as usize + }) }, 0x0D => { let mut cur_ptr: usize = 1; @@ -137,8 +140,11 @@ fn parse_computational_data(data: &[u8]) -> Result<(ComputationalData, usize), A } 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")) + Ok(s) => Ok(AmlParseType { + val: AmlValue::String(s.clone()), + len: s.clone().len() + 2 + }), + Err(_) => Err(AmlError::AmlParseError("String data - invalid string")) } }, 0x0E => { @@ -150,19 +156,32 @@ fn parse_computational_data(data: &[u8]) -> Result<(ComputationalData, usize), A ((data[6] as u64) << 40) + ((data[7] as u64) << 48) + ((data[8] as u64) << 56); - Ok((ComputationalData::QWord(res), 9 as usize)) + + Ok(AmlParseType { + val: AmlValue::Integer(res as u64), + len: 9 as usize + }) }, - 0x00 => Ok((ComputationalData::Zero, 1 as usize)), - 0x01 => Ok((ComputationalData::One, 1 as usize)), + 0x00 => Ok(AmlParseType { + val: AmlValue::IntegerConstant(0 as u64), + len: 1 as usize + }), + 0x01 => Ok(AmlParseType { + val: AmlValue::IntegerConstant(1 as u64), + len: 1 as usize + }), 0x5B => if data[1] == 0x30 { - Ok((ComputationalData::RevisionOp, 2 as usize)) + Ok(AmlParseType { + val: AmlValue::IntegerConstant(20170630 as u64), + len: 2 as usize + }) } else { - Err(AmlInternalError::AmlInvalidOpCode) + Err(AmlError::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) - } + 0xFF => Ok(AmlParseType { + val: AmlValue::IntegerConstant(0xFFFFFFFFFFFFFFFF), + len: 1 as usize + }), + _ => parse_def_buffer(data, ctx) } } diff --git a/src/acpi/aml/mod.rs b/src/acpi/aml/mod.rs index 296317d021b5568278343e64f201e49f22df2803..9ec105c625a587713062f705f34636fc57c0efee 100644 --- a/src/acpi/aml/mod.rs +++ b/src/acpi/aml/mod.rs @@ -1,10 +1,8 @@ //! # AML //! Code to parse and execute AML tables -use alloc::boxed::Box; use collections::string::String; use collections::vec::Vec; -use core::fmt::Debug; use core::str::FromStr; use super::sdt::Sdt; @@ -21,63 +19,37 @@ mod namedobj; mod dataobj; mod type1opcode; mod type2opcode; +mod parser; -use self::termlist::{parse_term_list, TermObj}; -pub use self::namespace::{AmlNamespace, AmlValue}; -use self::namespace::AmlNamespaceContents; +use self::parser::AmlExecutionContext; +use self::termlist::parse_term_list; +pub use self::namespace::AmlValue; -// 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 { +#[derive(Debug)] +pub enum AmlError { AmlParseError(&'static str), AmlInvalidOpCode, - AmlDeferredLoad + AmlValueError, + AmlDeferredLoad, + AmlFatalError(u8, u16, AmlValue), + AmlHardFatal } -pub enum AmlError { - AmlParseError(&'static str) +pub fn parse_aml_table(sdt: &Sdt) -> Result<Vec<String>, AmlError> { + parse_aml_with_scope(sdt, String::from_str("\\").unwrap()) } -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> { +pub fn parse_aml_with_scope(sdt: &Sdt, scope: String) -> Result<Vec<String>, AmlError> { let data = sdt.data(); + let mut ctx = AmlExecutionContext::new(scope); + + parse_term_list(data, &mut ctx)?; - 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) + Ok(ctx.namespace_delta) } -pub fn is_aml_table(sdt: &'static Sdt) -> bool { - if &sdt.signature == b"DSDT" {//|| &sdt.signature == b"SSDT" { +pub fn is_aml_table(sdt: &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 index 26cca7b0ed69712a384bf86ffe7dfc46718421da..bd813a8edbdaf476c79c8721a5430fcc8ed22bf0 100644 --- a/src/acpi/aml/namedobj.rs +++ b/src/acpi/aml/namedobj.rs @@ -1,174 +1,16 @@ use alloc::boxed::Box; use collections::string::String; -use collections::vec::Vec; +use collections::btree_map::BTreeMap; -use super::{AmlInternalError, AmlExecutable, AmlValue, AmlNamespace, AmlNamespaceContents, get_namespace_string}; +use super::AmlError; +use super::parser::{ AmlParseType, ParseResult, AmlParseTypeGeneric, AmlExecutionContext, ExecutionState }; +use super::namespace::{AmlValue, ObjectReference, FieldSelector, Method, get_namespace_string, + Accessor, BufferField, FieldUnit, Processor, PowerResource, OperationRegion, + Device, ThermalZone}; 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::termlist::{parse_term_arg, parse_object_list}; 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 - } -} +use super::type2opcode::parse_def_buffer; #[derive(Debug, Copy, Clone)] pub enum RegionSpace { @@ -199,7 +41,7 @@ pub enum AccessType { WordAcc, DWordAcc, QWordAcc, - BufferAcc + BufferAcc(AccessAttrib) } #[derive(Debug, Clone)] @@ -210,20 +52,15 @@ pub enum UpdateRule { } #[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), +pub struct NamedField { + name: String, + length: usize +} + +#[derive(Debug, Clone)] +pub struct AccessField { + access_type: AccessType, + access_attrib: AccessAttrib } #[derive(Debug, Clone)] @@ -240,9 +77,18 @@ pub enum AccessAttrib { AttribBlockProcessCall } -pub fn parse_named_obj(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { +pub fn parse_named_obj(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + parser_selector! { - data, + data, ctx, parse_def_bank_field, parse_def_create_bit_field, parse_def_create_byte_field, @@ -252,6 +98,7 @@ pub fn parse_named_obj(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalErro parse_def_create_field, parse_def_data_region, parse_def_event, + parse_def_external, parse_def_device, parse_def_op_region, parse_def_field, @@ -263,185 +110,351 @@ pub fn parse_named_obj(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalErro parse_def_thermal_zone }; - Err(AmlInternalError::AmlInvalidOpCode) + Err(AmlError::AmlInvalidOpCode) } -fn parse_def_bank_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { +fn parse_def_bank_field(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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 data = &data[2 + pkg_length_len .. 2 + pkg_length]; + + let region_name = parse_name_string(data, ctx)?; + let bank_name = parse_name_string(&data[2 + pkg_length_len + region_name.len .. 2 + pkg_length], ctx)?; - 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 bank_value = parse_term_arg(&data[2 + pkg_length_len + region_name.len .. 2 + pkg_length], ctx)?; - let flags_raw = data[2 + pkg_length_len + region_name_len + bank_name_len + bank_value_len]; - let flags = FieldFlags { + let flags_raw = data[2 + pkg_length_len + region_name.len + bank_name.len + bank_value.len]; + let mut 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")) + 5 => AccessType::BufferAcc(AccessAttrib::AttribByte), + _ => return Err(AmlError::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")) + _ => return Err(AmlError::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) + let selector = FieldSelector::Bank { + region: region_name.val.get_as_string()?, + bank_register: bank_name.val.get_as_string()?, + bank_selector: Box::new(bank_value.val) }; - Ok((NamedObj::DefBankField {region_name, bank_name, bank_value, flags, field_list}, - 2 + pkg_length)) + parse_field_list(&data[3 + pkg_length_len + region_name.len + bank_name.len + bank_value.len .. + 2 + pkg_length], ctx, selector, &mut flags)?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + pkg_length + }) } -fn parse_def_create_bit_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { +fn parse_def_create_bit_field(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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> { + let source_buf = parse_term_arg(&data[2..], ctx)?; + let bit_index = parse_term_arg(&data[2 + source_buf.len..], ctx)?; + let name = parse_name_string(&data[1 + source_buf.len + bit_index.len..], ctx)?; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + + ctx.add_to_namespace(local_scope_string, AmlValue::BufferField(BufferField { + source_buf: Box::new(source_buf.val), + index: Box::new(bit_index.val), + length: Box::new(AmlValue::IntegerConstant(1)) + }))?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + name.len + source_buf.len + bit_index.len + }) +} + +fn parse_def_create_byte_field(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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> { + let source_buf = parse_term_arg(&data[2..], ctx)?; + let bit_index = parse_term_arg(&data[2 + source_buf.len..], ctx)?; + let name = parse_name_string(&data[1 + source_buf.len + bit_index.len..], ctx)?; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + + ctx.add_to_namespace(local_scope_string, AmlValue::BufferField(BufferField { + source_buf: Box::new(source_buf.val), + index: Box::new(bit_index.val), + length: Box::new(AmlValue::IntegerConstant(8)) + }))?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + name.len + source_buf.len + bit_index.len + }) +} + +fn parse_def_create_word_field(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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> { + let source_buf = parse_term_arg(&data[2..], ctx)?; + let bit_index = parse_term_arg(&data[2 + source_buf.len..], ctx)?; + let name = parse_name_string(&data[1 + source_buf.len + bit_index.len..], ctx)?; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + + ctx.add_to_namespace(local_scope_string, AmlValue::BufferField(BufferField { + source_buf: Box::new(source_buf.val), + index: Box::new(bit_index.val), + length: Box::new(AmlValue::IntegerConstant(16)) + }))?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + name.len + source_buf.len + bit_index.len + }) +} + +fn parse_def_create_dword_field(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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> { + let source_buf = parse_term_arg(&data[2..], ctx)?; + let bit_index = parse_term_arg(&data[2 + source_buf.len..], ctx)?; + let name = parse_name_string(&data[1 + source_buf.len + bit_index.len..], ctx)?; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + + ctx.add_to_namespace(local_scope_string, AmlValue::BufferField(BufferField { + source_buf: Box::new(source_buf.val), + index: Box::new(bit_index.val), + length: Box::new(AmlValue::IntegerConstant(32)) + })); + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + name.len + source_buf.len + bit_index.len + }) +} + +fn parse_def_create_qword_field(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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> { + let source_buf = parse_term_arg(&data[2..], ctx)?; + let bit_index = parse_term_arg(&data[2 + source_buf.len..], ctx)?; + let name = parse_name_string(&data[1 + source_buf.len + bit_index.len..], ctx)?; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + + ctx.add_to_namespace(local_scope_string, AmlValue::BufferField(BufferField { + source_buf: Box::new(source_buf.val), + index: Box::new(bit_index.val), + length: Box::new(AmlValue::IntegerConstant(64)) + }))?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + name.len + source_buf.len + bit_index.len + }) +} + +fn parse_def_create_field(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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> { + let source_buf = parse_term_arg(&data[2..], ctx)?; + let bit_index = parse_term_arg(&data[2 + source_buf.len..], ctx)?; + let num_bits = parse_term_arg(&data[2 + source_buf.len + bit_index.len..], ctx)?; + let name = parse_name_string(&data[2 + source_buf.len + bit_index.len + num_bits.len..], ctx)?; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + + ctx.add_to_namespace(local_scope_string, AmlValue::BufferField(BufferField { + source_buf: Box::new(source_buf.val), + index: Box::new(bit_index.val), + length: Box::new(num_bits.val) + }))?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + name.len + source_buf.len + bit_index.len + num_bits.len + }) +} + +fn parse_def_data_region(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + + // TODO: Find the actual offset and length, once table mapping is implemented 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..])?; + let name = parse_name_string(&data[2..], ctx)?; + let signature = parse_term_arg(&data[2 + name.len..], ctx)?; + let oem_id = parse_term_arg(&data[2 + name.len + signature.len..], ctx)?; + let oem_table_id = parse_term_arg(&data[2 + name.len + signature.len + oem_id.len..], ctx)?; - Ok((NamedObj::DefDataRegion {name, signature, oem_id, oem_table_id}, - 2 + name_len + signature_len + oem_id_len + oem_table_id_len)) -} + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; -fn parse_def_event(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + ctx.add_to_namespace(local_scope_string, AmlValue::OperationRegion(OperationRegion { + region: RegionSpace::SystemMemory, + offset: Box::new(AmlValue::IntegerConstant(0)), + len: Box::new(AmlValue::IntegerConstant(0)), + accessor: Accessor { + read: |x| 0 as u64, + write: |x, y| () + }, + accessed_by: None + }))?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + name.len + signature.len + oem_id.len + oem_table_id.len + }) +} + +fn parse_def_event(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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> { + let name = parse_name_string(&data[2..], ctx)?; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + ctx.add_to_namespace(local_scope_string, AmlValue::Event(0))?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + name.len + }) +} + +fn parse_def_device(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + + // TODO: How to handle local context deferreds 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> { + let name = parse_name_string(&data[2 + pkg_length_len .. 2 + pkg_length], ctx)?; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + let mut local_ctx = AmlExecutionContext::new(local_scope_string.clone()); + + parse_object_list(&data[2 + pkg_length_len + name.len .. 2 + pkg_length], &mut local_ctx)?; + + ctx.add_to_namespace(local_scope_string, AmlValue::Device(Device { + obj_list: local_ctx.namespace_delta.clone(), + notify_methods: BTreeMap::new() + }))?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + pkg_length + }) +} + +fn parse_def_op_region(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + parser_opcode_extended!(data, 0x80); - let (name, name_len) = parse_name_string(&data[2..])?; - let region = match data[2 + name_len] { + let name = parse_name_string(&data[2..], ctx)?; + let region = match data[2 + name.len] { 0x00 => RegionSpace::SystemMemory, 0x01 => RegionSpace::SystemIO, 0x02 => RegionSpace::PCIConfig, @@ -452,158 +465,241 @@ fn parse_def_op_region(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalErro 0x07 => RegionSpace::IPMI, 0x08 => RegionSpace::GeneralPurposeIO, 0x09 => RegionSpace::GenericSerialBus, - 0x80 ... 0xFF => RegionSpace::UserDefined(data[2 + name_len]), - _ => return Err(AmlInternalError::AmlParseError("OpRegion - invalid region")) + 0x80 ... 0xFF => RegionSpace::UserDefined(data[2 + name.len]), + _ => return Err(AmlError::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> { + let offset = parse_term_arg(&data[3 + name.len..], ctx)?; + let len = parse_term_arg(&data[3 + name.len + offset.len..], ctx)?; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + ctx.add_to_namespace(local_scope_string, AmlValue::OperationRegion(OperationRegion { + region: region, + offset: Box::new(offset.val), + len: Box::new(len.val), + accessor: Accessor { + read: |x| 0 as u64, + write: |x, y| () + }, + accessed_by: None + }))?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 3 + name.len + offset.len + len.len + }) +} + +fn parse_def_field(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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 name = parse_name_string(&data[2 + pkg_length_len .. 2 + pkg_length], ctx)?; - let flags_raw = data[2 + pkg_length_len + name_len]; - let flags = FieldFlags { + let flags_raw = data[2 + pkg_length_len + name.len]; + let mut 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")) + 5 => AccessType::BufferAcc(AccessAttrib::AttribByte), + _ => return Err(AmlError::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")) + _ => return Err(AmlError::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) - }; + let selector = FieldSelector::Region(name.val.get_as_string()?); - Ok((NamedObj::DefField {name, flags, field_list}, 2 + pkg_length)) + parse_field_list(&data[3 + pkg_length_len + name.len .. 2 + pkg_length], ctx, selector, &mut flags)?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + pkg_length + }) } -fn parse_def_index_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { +fn parse_def_index_field(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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 idx_name = parse_name_string(&data[2 + pkg_length_len .. 2 + pkg_length], ctx)?; + let data_name = parse_name_string(&data[2 + pkg_length_len + idx_name.len .. 2 + pkg_length], ctx)?; - let flags_raw = data[2 + pkg_length_len + idx_name_len + data_name_len]; - let flags = FieldFlags { + let flags_raw = data[2 + pkg_length_len + idx_name.len + data_name.len]; + let mut 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")) + 5 => AccessType::BufferAcc(AccessAttrib::AttribByte), + _ => return Err(AmlError::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")) + _ => return Err(AmlError::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) + let selector = FieldSelector::Index { + index_selector: idx_name.val.get_as_string()?, + data_selector: data_name.val.get_as_string()? }; - 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!(); + parse_field_list(&data[3 + pkg_length_len + idx_name.len + data_name.len .. 2 + pkg_length], + ctx, selector, &mut flags)?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + pkg_length + }) +} + +fn parse_field_list(data: &[u8], + ctx: &mut AmlExecutionContext, + selector: FieldSelector, + flags: &mut FieldFlags) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + let mut current_offset: usize = 0; + let mut field_offset: usize = 0; + let mut connection = AmlValue::Uninitialized; 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; + let res = parse_field_element(&data[current_offset..], ctx, selector.clone(), &mut connection, flags, &mut field_offset)?; + + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + + current_offset += res.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 + Ok(AmlParseType { + val: AmlValue::None, + len: data.len() + }) +} + +fn parse_field_element(data: &[u8], + ctx: &mut AmlExecutionContext, + selector: FieldSelector, + connection: &mut AmlValue, + flags: &mut FieldFlags, + offset: &mut usize) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + + let length = if let Ok(field) = parse_named_field(data, ctx) { + let local_scope_string = get_namespace_string(ctx.scope.clone(), AmlValue::String(field.val.name.clone()))?; + + ctx.add_to_namespace(local_scope_string, AmlValue::FieldUnit(FieldUnit { + selector: selector.clone(), + connection: Box::new(connection.clone()), + flags: flags.clone(), + offset: offset.clone(), + length: field.val.length + }))?; + + *offset += field.val.length; + field.len + } else if let Ok(field) = parse_reserved_field(data, ctx) { + *offset += field.val; + field.len + } else if let Ok(field) = parse_access_field(data, ctx) { + match field.val.access_type { + AccessType::BufferAcc(_) => + flags.access_type = AccessType::BufferAcc(field.val.access_attrib.clone()), + ref a => flags.access_type = a.clone() + } + + field.len + } else if let Ok(field) = parse_connect_field(data, ctx) { + *connection = field.val.clone(); + field.len + } else { + return Err(AmlError::AmlInvalidOpCode); }; - - Err(AmlInternalError::AmlInvalidOpCode) + + Ok(AmlParseType { + val: AmlValue::None, + len: length + }) } -fn parse_named_field(data: &[u8]) -> Result<(FieldElement, usize), AmlInternalError> { +fn parse_named_field(data: &[u8], + ctx: &mut AmlExecutionContext) -> Result<AmlParseTypeGeneric<NamedField>, AmlError> { 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")) + Err(_) => return Err(AmlError::AmlParseError("NamedField - invalid name")) }; let (length, length_len) = parse_pkg_length(&data[4..])?; - Ok((FieldElement::NamedField {name, length}, 4 + length_len)) + Ok(AmlParseTypeGeneric { + val: NamedField { name, length }, + len: name_seg_len + length_len + }) } -fn parse_reserved_field(data: &[u8]) -> Result<(FieldElement, usize), AmlInternalError> { +fn parse_reserved_field(data: &[u8], + ctx: &mut AmlExecutionContext) -> Result<AmlParseTypeGeneric<usize>, AmlError> { parser_opcode!(data, 0x00); let (length, length_len) = parse_pkg_length(&data[1..])?; - Ok((FieldElement::ReservedField {length}, 1 + length_len)) + Ok(AmlParseTypeGeneric { + val: length, + len: 1 + length_len + }) } -fn parse_access_field(data: &[u8]) -> Result<(FieldElement, usize), AmlInternalError> { +fn parse_access_field(data: &[u8], + ctx: &mut AmlExecutionContext) -> Result<AmlParseTypeGeneric<AccessField>, AmlError> { parser_opcode!(data, 0x01, 0x03); let flags_raw = data[1]; @@ -613,8 +709,8 @@ fn parse_access_field(data: &[u8]) -> Result<(FieldElement, usize), AmlInternalE 2 => AccessType::WordAcc, 3 => AccessType::DWordAcc, 4 => AccessType::QWordAcc, - 5 => AccessType::BufferAcc, - _ => return Err(AmlInternalError::AmlParseError("AccessField - Invalid access type")) + 5 => AccessType::BufferAcc(AccessAttrib::AttribByte), + _ => return Err(AmlError::AmlParseError("AccessField - Invalid access type")) }; let access_attrib = match (flags_raw & 0xC0) >> 6 { @@ -629,155 +725,252 @@ fn parse_access_field(data: &[u8]) -> Result<(FieldElement, usize), AmlInternalE 0x0D => AccessAttrib::AttribBlockProcessCall, 0x0E => AccessAttrib::AttribRawBytes(data[3]), 0x0F => AccessAttrib::AttribRawProcessBytes(data[3]), - _ => return Err(AmlInternalError::AmlParseError("AccessField - Invalid access attrib")) + _ => return Err(AmlError::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")) + _ => return Err(AmlError::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 - })) + Ok(AmlParseTypeGeneric { + val: AccessField { access_type, access_attrib }, + len: 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) +fn parse_connect_field(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) } + + parser_opcode!(data, 0x02); - 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) + if let Ok(e) = parse_def_buffer(&data[1..], ctx) { + Ok(AmlParseType { + val: e.val, + len: e.len + 1 + }) + } else { + let name = parse_name_string(&data[1..], ctx)?; + Ok(AmlParseType { + val: AmlValue::Alias(name.val.get_as_string()?), + len: name.len + 1 + }) } } -fn parse_def_method(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { +fn parse_def_method(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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 name = parse_name_string(&data[1 + pkg_len_len..], ctx)?; + 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> { + let term_list = &data[2 + pkg_len_len + name.len .. 1 + pkg_len]; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + ctx.add_to_namespace(local_scope_string, AmlValue::Method(Method { + arg_count, + serialized, + sync_level, + term_list: term_list.to_vec() + }))?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 1 + pkg_len + }) +} + +fn parse_def_mutex(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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 name = parse_name_string(&data[2 ..], ctx)?; + 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> { + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + ctx.add_to_namespace(local_scope_string, AmlValue::Mutex((sync_level, None)))?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 3 + name.len + }) +} + +fn parse_def_power_res(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + + // TODO: How to handle local context deferreds 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> { + let name = parse_name_string(&data[2 + pkg_len_len..], ctx)?; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + + 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 mut local_ctx = AmlExecutionContext::new(local_scope_string.clone()); + parse_object_list(&data[5 + pkg_len_len + name.len .. 2 + pkg_len], &mut local_ctx)?; + + ctx.add_to_namespace(local_scope_string, AmlValue::PowerResource(PowerResource { + system_level, + resource_order, + obj_list: local_ctx.namespace_delta.clone() + }))?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + pkg_len + }) +} + +fn parse_def_processor(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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 name = parse_name_string(&data[2 + pkg_len_len..], ctx)?; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + + 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 mut local_ctx = AmlExecutionContext::new(local_scope_string.clone()); + parse_object_list(&data[8 + pkg_len_len + name.len .. 2 + pkg_len], &mut local_ctx)?; + + ctx.add_to_namespace(local_scope_string, AmlValue::Processor(Processor { + proc_id: proc_id, + p_blk: if p_blk_len > 0 { Some(p_blk_addr) } else { None }, + obj_list: local_ctx.namespace_delta.clone(), + notify_methods: BTreeMap::new() + }))?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + pkg_len + }) +} + +fn parse_def_thermal_zone(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + + 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 name = parse_name_string(&data[2 + pkg_len_len .. 2 + pkg_len], ctx)?; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + + let mut local_ctx = AmlExecutionContext::new(local_scope_string.clone()); + parse_object_list(&data[2 + pkg_len_len + name.len .. 2 + pkg_len], &mut local_ctx)?; + + ctx.add_to_namespace(local_scope_string, AmlValue::ThermalZone(ThermalZone { + obj_list: local_ctx.namespace_delta.clone(), + notify_methods: BTreeMap::new() + }))?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + pkg_len + }) +} + +fn parse_def_external(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + + parser_opcode_extended!(data, 0x15); + + let object_name = parse_name_string(&data[1..], ctx)?; + let object_type = data[1 + object_name.len]; + let argument_count = data[2 + object_name.len]; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), object_name.val)?; + + let obj = match object_type { + 8 => AmlValue::Method(Method { + arg_count: argument_count, + serialized: false, + sync_level: 0, + term_list: vec!() + }), + _ => AmlValue::Uninitialized }; - 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) - }; + ctx.add_to_namespace(local_scope_string, obj)?; - Ok((NamedObj::DefThermalZone {name, obj_list}, 2 + pkg_len)) + Ok(AmlParseType { + val: AmlValue::None, + len: 3 + object_name.len + }) } diff --git a/src/acpi/aml/namespace.rs b/src/acpi/aml/namespace.rs index dc3c1c89733e2ce64018f70710744493a825c198..18eb7a34e49bd5362ff55d1c8a1a5ff4cb0d3ced 100644 --- a/src/acpi/aml/namespace.rs +++ b/src/acpi/aml/namespace.rs @@ -1,225 +1,491 @@ use alloc::boxed::Box; use collections::string::String; +use collections::string::ToString; use collections::vec::Vec; +use collections::btree_map::BTreeMap; +use core::fmt::{Debug, Formatter, Error}; use core::str::FromStr; -use super::namedobj::{ RegionSpace, FieldFlags, Method }; +use super::termlist::parse_term_list; +use super::namedobj::{ RegionSpace, FieldFlags }; +use super::parser::{AmlExecutionContext, ExecutionState}; +use super::AmlError; -#[derive(Debug, Clone)] -pub struct AmlNamespace { - name: String, - contents: AmlNamespaceContents -} +use acpi::{SdtSignature, get_signature_from_index, get_index_from_signature}; -#[derive(Debug, Clone)] -pub enum AmlNamespaceContents { - Value(AmlValue), - SubNamespace(Box<AmlNamespace>), - Namespace(Vec<AmlNamespaceContents>), - OpRegion { - region: RegionSpace, - offset: AmlValue, - len: AmlValue +#[derive(Clone)] +pub enum FieldSelector { + Region(String), + Bank { + region: String, + bank_register: String, + bank_selector: Box<AmlValue> }, - Field { - op_region: String, - flags: FieldFlags, - offset: usize, - length: usize + Index { + index_selector: String, + data_selector: String + } +} + +#[derive(Clone)] +pub enum ObjectReference { + ArgObj(u8), + LocalObj(u8), + Object(String), + Index(Box<AmlValue>, Box<AmlValue>) +} + +#[derive(Clone)] +pub struct Method { + pub arg_count: u8, + pub serialized: bool, + pub sync_level: u8, + pub term_list: Vec<u8> +} + +#[derive(Clone)] +pub struct BufferField { + pub source_buf: Box<AmlValue>, + pub index: Box<AmlValue>, + pub length: Box<AmlValue> +} + +#[derive(Clone)] +pub struct FieldUnit { + pub selector: FieldSelector, + pub connection: Box<AmlValue>, + pub flags: FieldFlags, + pub offset: usize, + pub length: usize +} + +#[derive(Clone)] +pub struct Device { + pub obj_list: Vec<String>, + pub notify_methods: BTreeMap<u8, Vec<fn()>> +} + +#[derive(Clone)] +pub struct ThermalZone { + pub obj_list: Vec<String>, + pub notify_methods: BTreeMap<u8, Vec<fn()>> +} + +#[derive(Clone)] +pub struct Processor { + pub proc_id: u8, + pub p_blk: Option<u32>, + pub obj_list: Vec<String>, + pub notify_methods: BTreeMap<u8, Vec<fn()>> +} + +#[derive(Clone)] +pub struct OperationRegion { + pub region: RegionSpace, + pub offset: Box<AmlValue>, + pub len: Box<AmlValue>, + pub accessor: Accessor, + pub accessed_by: Option<u64> +} + +#[derive(Clone)] +pub struct PowerResource { + pub system_level: u8, + pub resource_order: u16, + pub obj_list: Vec<String> +} + +pub struct Accessor { + pub read: fn(usize) -> u64, + pub write: fn(usize, u64) +} + +impl Clone for Accessor { + fn clone(&self) -> Accessor { + Accessor { + read: (*self).read, + write: (*self).write + } } } -#[derive(Debug, Clone)] +#[derive(Clone)] pub enum AmlValue { + None, Uninitialized, - Buffer, - BufferField, - DDBHandle, + Alias(String), + Buffer(Vec<u8>), + BufferField(BufferField), + DDBHandle((Vec<String>, SdtSignature)), DebugObject, - Device, - Event, - FieldUnit, - Integer, + Device(Device), + Event(u64), + FieldUnit(FieldUnit), + Integer(u64), IntegerConstant(u64), Method(Method), - Mutex, - ObjectReference, - OperationRegion, + Mutex((u8, Option<u64>)), + ObjectReference(ObjectReference), + OperationRegion(OperationRegion), Package(Vec<AmlValue>), - String, - PowerResource, - Processor, - RawDataBuffer, - ThermalZone + String(String), + PowerResource(PowerResource), + Processor(Processor), + RawDataBuffer(Vec<u8>), + ThermalZone(ThermalZone) +} + +impl Debug for AmlValue { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { Ok(()) } } impl AmlValue { - pub fn get_as_package(&self) -> Option<Vec<AmlValue>> { + pub fn get_type_string(&self) -> String { match *self { - AmlValue::Package(ref p) => Some(p.clone()), - _ => None + AmlValue::Uninitialized => String::from_str("[Uninitialized Object]").unwrap(), + AmlValue::Integer(_) => String::from_str("[Integer]").unwrap(), + AmlValue::String(_) => String::from_str("[String]").unwrap(), + AmlValue::Buffer(_) => String::from_str("[Buffer]").unwrap(), + AmlValue::Package(_) => String::from_str("[Package]").unwrap(), + AmlValue::FieldUnit(_) => String::from_str("[Field]").unwrap(), + AmlValue::Device(_) => String::from_str("[Device]").unwrap(), + AmlValue::Event(_) => String::from_str("[Event]").unwrap(), + AmlValue::Method(_) => String::from_str("[Control Method]").unwrap(), + AmlValue::Mutex(_) => String::from_str("[Mutex]").unwrap(), + AmlValue::OperationRegion(_) => String::from_str("[Operation Region]").unwrap(), + AmlValue::PowerResource(_) => String::from_str("[Power Resource]").unwrap(), + AmlValue::Processor(_) => String::from_str("[Processor]").unwrap(), + AmlValue::ThermalZone(_) => String::from_str("[Thermal Zone]").unwrap(), + AmlValue::BufferField(_) => String::from_str("[Buffer Field]").unwrap(), + AmlValue::DDBHandle(_) => String::from_str("[DDB Handle]").unwrap(), + AmlValue::DebugObject => String::from_str("[Debug Object]").unwrap(), + _ => String::new() + } + } + + pub fn get_as_type(&self, t: AmlValue) -> Result<AmlValue, AmlError> { + match t { + AmlValue::None => Ok(AmlValue::None), + AmlValue::Uninitialized => Ok(self.clone()), + AmlValue::Alias(_) => match *self { + AmlValue::Alias(_) => Ok(self.clone()), + _ => Err(AmlError::AmlValueError) + }, + AmlValue::Buffer(_) => Ok(AmlValue::Buffer(self.get_as_buffer()?)), + AmlValue::BufferField(_) => Ok(AmlValue::BufferField(self.get_as_buffer_field()?)), + AmlValue::DDBHandle(_) => Ok(AmlValue::DDBHandle(self.get_as_ddb_handle()?)), + AmlValue::DebugObject => match *self { + AmlValue::DebugObject => Ok(self.clone()), + _ => Err(AmlError::AmlValueError) + }, + AmlValue::Device(_) => Ok(AmlValue::Device(self.get_as_device()?)), + AmlValue::Event(_) => Ok(AmlValue::Event(self.get_as_event()?)), + AmlValue::FieldUnit(_) => Ok(AmlValue::FieldUnit(self.get_as_field_unit()?)), + AmlValue::Integer(_) => Ok(AmlValue::Integer(self.get_as_integer()?)), + AmlValue::IntegerConstant(_) => Ok(AmlValue::IntegerConstant(self.get_as_integer_constant()?)), + AmlValue::Method(_) => Ok(AmlValue::Method(self.get_as_method()?)), + AmlValue::Mutex(_) => Ok(AmlValue::Mutex(self.get_as_mutex()?)), + AmlValue::ObjectReference(_) => Ok(AmlValue::ObjectReference(self.get_as_object_reference()?)), + AmlValue::OperationRegion(_) => match *self { + AmlValue::OperationRegion(_) => Ok(self.clone()), + _ => Err(AmlError::AmlValueError) + }, + AmlValue::Package(_) => Ok(AmlValue::Package(self.get_as_package()?)), + AmlValue::String(_) => Ok(AmlValue::String(self.get_as_string()?)), + AmlValue::PowerResource(_) => Ok(AmlValue::PowerResource(self.get_as_power_resource()?)), + AmlValue::Processor(_) => Ok(AmlValue::Processor(self.get_as_processor()?)), + AmlValue::RawDataBuffer(_) => Ok(AmlValue::RawDataBuffer(self.get_as_raw_data_buffer()?)), + AmlValue::ThermalZone(_) => Ok(AmlValue::ThermalZone(self.get_as_thermal_zone()?)) } } - pub fn get_as_integer(&self) -> Option<u64> { + pub fn get_as_buffer(&self) -> Result<Vec<u8>, AmlError> { match *self { - AmlValue::IntegerConstant(ref i) => Some(i.clone()), - _ => None + AmlValue::Buffer(ref b) => Ok(b.clone()), + AmlValue::Integer(ref i) => { + let mut v: Vec<u8> = vec!(); + let mut i = i.clone(); + + while i != 0 { + v.push((i & 0xFF) as u8); + i >>= 8; + } + + while v.len() < 8 { + v.push(0); + } + + Ok(v) + }, + AmlValue::String(ref s) => { + Ok(s.clone().into_bytes()) + }, + AmlValue::BufferField(ref b) => { + let buf = b.source_buf.get_as_buffer()?; + let idx = b.index.get_as_integer()? as usize; + let len = b.length.get_as_integer()? as usize; + + if idx + len > buf.len() { + return Err(AmlError::AmlValueError); + } + + Ok(buf[idx .. idx + len].to_vec()) + }, + _ => Err(AmlError::AmlValueError) } } -} -impl AmlNamespace { - pub fn new_namespace(name: &String) -> AmlNamespace { - AmlNamespace { - name: name.clone(), - contents: AmlNamespaceContents::Namespace(vec!()) + pub fn get_as_buffer_field(&self) -> Result<BufferField, AmlError> { + match *self { + AmlValue::BufferField(ref b) => Ok(b.clone()), + _ => { + let raw_buf = self.get_as_buffer()?; + let buf = Box::new(AmlValue::Buffer(raw_buf.clone())); + let idx = Box::new(AmlValue::IntegerConstant(0)); + let len = Box::new(AmlValue::Integer(raw_buf.len() as u64)); + + Ok(BufferField { + source_buf: buf, + index: idx, + length: len + }) + } } } - pub fn find_str(&self, scope_str: &str) -> Option<AmlValue> { - let scope_string = String::from_str(scope_str).unwrap(); - self.find(scope_string) + pub fn get_as_ddb_handle(&self) -> Result<(Vec<String>, SdtSignature), AmlError> { + match *self { + AmlValue::DDBHandle(ref v) => Ok(v.clone()), + AmlValue::Integer(i) => if let Some(sig) = get_signature_from_index(i as usize) { + Ok((vec!(), sig)) + } else { + Err(AmlError::AmlValueError) + }, + _ => Err(AmlError::AmlValueError) + } } - 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 - } + pub fn get_as_device(&self) -> Result<Device, AmlError> { + match *self { + AmlValue::Device(ref s) => Ok(s.clone()), + _ => Err(AmlError::AmlValueError) + } + } + + pub fn get_as_event(&self) -> Result<u64, AmlError> { + match *self { + AmlValue::Event(ref e) => Ok(e.clone()), + _ => Err(AmlError::AmlValueError) } + } + + pub fn get_as_field_unit(&self) -> Result<FieldUnit, AmlError> { + match *self { + AmlValue::FieldUnit(ref e) => Ok(e.clone()), + _ => Err(AmlError::AmlValueError) + } + } - let mut scope_string = scope_string.clone(); + pub fn get_as_integer(&self) -> Result<u64, AmlError> { + match *self { + AmlValue::IntegerConstant(ref i) => Ok(i.clone()), + AmlValue::Integer(ref i) => Ok(i.clone()), + AmlValue::Buffer(ref b) => { + let mut b = b.clone(); + if b.len() > 8 { + return Err(AmlError::AmlValueError); + } - if scope_string.starts_with("\\") { - if self.name != "\\" { - return None; - } + let mut i: u64 = 0; - scope_string.remove(0); - } + while b.len() > 0 { + i <<= 8; + i += b.pop().expect("Won't happen") as u64; + } - if scope_string.starts_with(".") { - scope_string.remove(0); - } + Ok(i) + }, + AmlValue::BufferField(_) => { + let mut b = self.get_as_buffer()?; + if b.len() > 8 { + return Err(AmlError::AmlValueError); + } - if scope_string.len() == 0 { - match self.contents { - AmlNamespaceContents::Value(ref v) => return Some(v.clone()), - _ => return None - } - } + let mut i: u64 = 0; - let (current, nextset) = match scope_string.find(".") { - Some(s) => { - let (x, mut y) = scope_string.split_at(s); - y = &y[1..]; + while b.len() > 0 { + i <<= 8; + i += b.pop().expect("Won't happen") as u64; + } - (String::from_str(x).unwrap(), String::from_str(y).unwrap()) + Ok(i) }, - None => if scope_string.len() <= 4 { - (scope_string, String::from_str("").unwrap()) + AmlValue::DDBHandle(ref v) => if let Some(idx) = get_index_from_signature(v.1.clone()) { + Ok(idx as u64) } 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); - }, - _ => () - } + Err(AmlError::AmlValueError) + }, + AmlValue::String(ref s) => { + let mut s = s.clone()[0..8].to_string().to_uppercase(); + let mut i: u64 = 0; - current_index += 1; + for c in s.chars() { + if !c.is_digit(16) { + break; + } + + i <<= 8; + i += c.to_digit(16).unwrap() as u64; } + + Ok(i) }, - _ => () + _ => Err(AmlError::AmlValueError) + } + } + + pub fn get_as_integer_constant(&self) -> Result<u64, AmlError> { + match *self { + AmlValue::IntegerConstant(ref i) => Ok(i.clone()), + _ => Err(AmlError::AmlValueError) } + } - None + pub fn get_as_method(&self) -> Result<Method, AmlError> { + match *self { + AmlValue::Method(ref m) => Ok(m.clone()), + _ => Err(AmlError::AmlValueError) + } } - pub fn push(&mut self, val: AmlNamespaceContents) { - match self.contents { - AmlNamespaceContents::Namespace(ref mut v) => v.push(val), - _ => () // TODO: Error this + pub fn get_as_mutex(&self) -> Result<(u8, Option<u64>), AmlError> { + match *self { + AmlValue::Mutex(ref m) => Ok(m.clone()), + _ => Err(AmlError::AmlValueError) } } - pub fn push_to(&mut self, scope_string: String, contents: AmlNamespaceContents) { - if scope_string.len() == 0 { - return; + pub fn get_as_object_reference(&self) -> Result<ObjectReference, AmlError> { + match *self { + AmlValue::ObjectReference(ref m) => Ok(m.clone()), + _ => Err(AmlError::AmlValueError) + } + } + + pub fn get_as_operation_region(&self) -> Result<OperationRegion, AmlError> { + match *self { + AmlValue::OperationRegion(ref p) => Ok(p.clone()), + _ => Err(AmlError::AmlValueError) + } + } + + pub fn get_as_package(&self) -> Result<Vec<AmlValue>, AmlError> { + match *self { + AmlValue::Package(ref p) => Ok(p.clone()), + _ => Err(AmlError::AmlValueError) + } + } + + pub fn get_as_string(&self) -> Result<String, AmlError> { + match *self { + AmlValue::String(ref s) => Ok(s.clone()), + AmlValue::Integer(ref i) => Ok(format!("{:X}", i)), + AmlValue::IntegerConstant(ref i) => Ok(format!("{:X}", i)), + AmlValue::Buffer(ref b) => Ok(String::from_utf8(b.clone()).expect("Invalid UTF-8")), + AmlValue::BufferField(_) => { + let b = self.get_as_buffer()?; + Ok(String::from_utf8(b).expect("Invalid UTF-8")) + }, + _ => Err(AmlError::AmlValueError) + } + } + + pub fn get_as_power_resource(&self) -> Result<PowerResource, AmlError> { + match *self { + AmlValue::PowerResource(ref p) => Ok(p.clone()), + _ => Err(AmlError::AmlValueError) + } + } + + pub fn get_as_processor(&self) -> Result<Processor, AmlError> { + match *self { + AmlValue::Processor(ref p) => Ok(p.clone()), + _ => Err(AmlError::AmlValueError) } + } + + pub fn get_as_raw_data_buffer(&self) -> Result<Vec<u8>, AmlError> { + match *self { + AmlValue::RawDataBuffer(ref p) => Ok(p.clone()), + _ => Err(AmlError::AmlValueError) + } + } + + pub fn get_as_thermal_zone(&self) -> Result<ThermalZone, AmlError> { + match *self { + AmlValue::ThermalZone(ref p) => Ok(p.clone()), + _ => Err(AmlError::AmlValueError) + } + } +} - let mut scope_string = scope_string.clone(); +impl Method { + pub fn execute(&self, scope: String, parameters: Vec<AmlValue>) -> AmlValue { + let mut ctx = AmlExecutionContext::new(scope); + ctx.init_arg_vars(parameters); - if scope_string.starts_with("\\") { - if self.name != "\\" { - return; - // TODO: Error this - } + parse_term_list(&self.term_list[..], &mut ctx); + ctx.clean_namespace(); - scope_string.remove(0); + match ctx.state { + ExecutionState::RETURN(v) => v, + _ => AmlValue::IntegerConstant(0) } + } +} - if scope_string.starts_with(".") { - scope_string.remove(0); - } +pub fn get_namespace_string(current: String, modifier_v: AmlValue) -> Result<String, AmlError> { + let mut modifier = modifier_v.get_as_string()?; + + if current.len() == 0 { + return Ok(modifier); + } - if scope_string.len() == 0 { - return; - } + if modifier.len() == 0 { + return Ok(current); + } + + if modifier.starts_with("\\") { + return Ok(modifier); + } - let (current, nextset) = match scope_string.find(".") { - Some(s) => { - let (x, mut y) = scope_string.split_at(s); - y = &y[1..]; + let mut namespace = current.clone(); - (String::from_str(x).unwrap(), String::from_str(y).unwrap()) - }, - None => if scope_string.len() <= 4 { - (scope_string, String::from_str("").unwrap()) - } else { - return; + if modifier.starts_with("^") { + while modifier.starts_with("^") { + modifier = modifier[1..].to_string(); + + if namespace.ends_with("\\") { + return Err(AmlError::AmlValueError); } - }; - - 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; + loop { + if namespace.ends_with(".") { + namespace.pop(); + break; } - let mut next = AmlNamespace { - name: current, - contents: contents - }; - - namespace.push(AmlNamespaceContents::SubNamespace(Box::new(next))); + if namespace.pop() == None { + return Err(AmlError::AmlValueError); + } } - _ => () // TODO: Error this } } - pub fn push_subordinate_namespace(&mut self, scope_string: String) { - self.push_to(scope_string, AmlNamespaceContents::Namespace(vec!())); + if !namespace.ends_with("\\") { + namespace.push('.'); } + + Ok(namespace + &modifier) } diff --git a/src/acpi/aml/namespacemodifier.rs b/src/acpi/aml/namespacemodifier.rs index 217347a0bf2ea82156234ddf4066dc982d990895..a223f5c8ad72bd181819858b8ac756932386bd76 100644 --- a/src/acpi/aml/namespacemodifier.rs +++ b/src/acpi/aml/namespacemodifier.rs @@ -1,102 +1,106 @@ -use alloc::boxed::Box; -use collections::string::String; -use collections::vec::Vec; - -use super::{AmlInternalError, AmlExecutable, AmlValue, AmlNamespace, AmlNamespaceContents, get_namespace_string}; +use super::AmlError; +use super::parser::{AmlParseType, ParseResult, AmlExecutionContext, ExecutionState}; +use super::namespace::{AmlValue, ObjectReference, 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 +use super::termlist::parse_term_list; +use super::dataobj::parse_data_ref_obj; + +pub fn parse_namespace_modifier(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) } -} - -pub fn parse_namespace_modifier(data: &[u8]) -> Result<(NamespaceModifier, usize), AmlInternalError> { + parser_selector! { - data, + data, ctx, parse_alias_op, parse_scope_op, parse_name_op }; - Err(AmlInternalError::AmlInvalidOpCode) + Err(AmlError::AmlInvalidOpCode) } -fn parse_alias_op(data: &[u8]) -> Result<(NamespaceModifier, usize), AmlInternalError> { +fn parse_alias_op(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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)) + let source_name = parse_name_string(&data[1..], ctx)?; + let alias_name = parse_name_string(&data[1 + source_name.len..], ctx)?; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), source_name.val)?; + let local_alias_string = get_namespace_string(ctx.scope.clone(), alias_name.val)?; + + ctx.add_to_namespace(local_scope_string, AmlValue::Alias(local_alias_string))?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 1 + source_name.len + alias_name.len + }) } -fn parse_name_op(data: &[u8]) -> Result<(NamespaceModifier, usize), AmlInternalError> { +fn parse_name_op(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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)) + + let name = parse_name_string(&data[1..], ctx)?; + let data_ref_obj = parse_data_ref_obj(&data[1 + name.len..], ctx)?; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + + ctx.add_to_namespace(local_scope_string, data_ref_obj.val)?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 1 + name.len + data_ref_obj.len + }) } -fn parse_scope_op(data: &[u8]) -> Result<(NamespaceModifier, usize), AmlInternalError> { +fn parse_scope_op(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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)) + let name = parse_name_string(&data[1 + pkg_length_len..], ctx)?; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val.clone())?; + let containing_scope_string = ctx.scope.clone(); + + ctx.scope = local_scope_string; + parse_term_list(&data[1 + pkg_length_len + name.len .. 1 + pkg_length], ctx)?; + ctx.scope = containing_scope_string; + + Ok(AmlParseType { + val: AmlValue::None, + len: 1 + pkg_length + }) } diff --git a/src/acpi/aml/namestring.rs b/src/acpi/aml/namestring.rs index 8015a8ca8559a53421e5a38a72544f3476d706a2..8464b6ccf8fbf932c6ea5cf8607637ec4e0f47a9 100644 --- a/src/acpi/aml/namestring.rs +++ b/src/acpi/aml/namestring.rs @@ -1,27 +1,22 @@ 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> { +use super::AmlError; +use super::parser::{AmlParseType, ParseResult, AmlExecutionContext, ExecutionState}; +use super::namespace::AmlValue; +use super::dataobj::{parse_arg_obj, parse_local_obj}; +use super::type2opcode::parse_type6_opcode; + +pub fn parse_name_string(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + let mut characters: Vec<u8> = vec!(); let mut starting_index: usize = 0; @@ -36,7 +31,7 @@ pub fn parse_name_string(data: &[u8]) -> Result<(String, usize), AmlInternalErro } let sel = |data| { - parser_selector! { + parser_selector_simple! { data, parse_dual_name_path, parse_multi_name_path, @@ -44,7 +39,7 @@ pub fn parse_name_string(data: &[u8]) -> Result<(String, usize), AmlInternalErro parse_name_seg }; - Err(AmlInternalError::AmlInvalidOpCode) + Err(AmlError::AmlInvalidOpCode) }; let (mut chr, len) = sel(&data[starting_index..])?; characters.append(&mut chr); @@ -52,35 +47,38 @@ pub fn parse_name_string(data: &[u8]) -> Result<(String, usize), AmlInternalErro 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")) + Ok(s) => Ok(AmlParseType { + val: AmlValue::String(s.clone()), + len: len + starting_index + }), + Err(_) => Err(AmlError::AmlParseError("Namestring - Name is invalid")) } } -fn parse_null_name(data: &[u8]) -> Result<(Vec<u8>, usize), AmlInternalError> { +fn parse_null_name(data: &[u8]) -> Result<(Vec<u8>, usize), AmlError> { parser_opcode!(data, 0x00); Ok((vec!(), 1 as usize)) } -pub fn parse_name_seg(data: &[u8]) -> Result<(Vec<u8>, usize), AmlInternalError> { +pub fn parse_name_seg(data: &[u8]) -> Result<(Vec<u8>, usize), AmlError> { match data[0] { 0x41 ... 0x5A | 0x5F => (), - _ => return Err(AmlInternalError::AmlInvalidOpCode) + _ => return Err(AmlError::AmlInvalidOpCode) } match data[1] { 0x30 ... 0x39 | 0x41 ... 0x5A | 0x5F => (), - _ => return Err(AmlInternalError::AmlInvalidOpCode) + _ => return Err(AmlError::AmlInvalidOpCode) } match data[2] { 0x30 ... 0x39 | 0x41 ... 0x5A | 0x5F => (), - _ => return Err(AmlInternalError::AmlInvalidOpCode) + _ => return Err(AmlError::AmlInvalidOpCode) } match data[3] { 0x30 ... 0x39 | 0x41 ... 0x5A | 0x5F => (), - _ => return Err(AmlInternalError::AmlInvalidOpCode) + _ => return Err(AmlError::AmlInvalidOpCode) } let mut name_seg = vec!(data[0], data[1], data[2], data[3]); @@ -91,7 +89,7 @@ pub fn parse_name_seg(data: &[u8]) -> Result<(Vec<u8>, usize), AmlInternalError> Ok((name_seg, 4 as usize)) } -fn parse_dual_name_path(data: &[u8]) -> Result<(Vec<u8>, usize), AmlInternalError> { +fn parse_dual_name_path(data: &[u8]) -> Result<(Vec<u8>, usize), AmlError> { parser_opcode!(data, 0x2E); let mut characters: Vec<u8> = vec!(); @@ -118,12 +116,12 @@ fn parse_dual_name_path(data: &[u8]) -> Result<(Vec<u8>, usize), AmlInternalErro Ok((characters, dual_len)) } -fn parse_multi_name_path(data: &[u8]) -> Result<(Vec<u8>, usize), AmlInternalError> { +fn parse_multi_name_path(data: &[u8]) -> Result<(Vec<u8>, usize), AmlError> { 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")); + return Err(AmlError::AmlParseError("MultiName Path - can't have zero name segments")); } let mut current_seg = 0; @@ -149,40 +147,80 @@ fn parse_multi_name_path(data: &[u8]) -> Result<(Vec<u8>, usize), AmlInternalErr Ok((characters, multi_len)) } -pub fn parse_super_name(data: &[u8]) -> Result<(SuperName, usize), AmlInternalError> { +pub fn parse_super_name(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + parser_selector! { - data, + data, ctx, parse_simple_name, - parser_wrap!(SuperName::Type6OpCode, parse_type6_opcode), + parse_type6_opcode, parse_debug_obj }; - Err(AmlInternalError::AmlInvalidOpCode) + Err(AmlError::AmlInvalidOpCode) } -fn parse_debug_obj(data: &[u8]) -> Result<(SuperName, usize), AmlInternalError> { +fn parse_debug_obj(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + parser_opcode_extended!(data, 0x31); - Ok((SuperName::DebugObj, 2 as usize)) + + Ok(AmlParseType { + val: AmlValue::DebugObject, + len: 2 as usize + }) } -pub fn parse_simple_name(data: &[u8]) -> Result<(SuperName, usize), AmlInternalError> { +pub fn parse_simple_name(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + parser_selector! { - data, - parser_wrap!(SuperName::NameString, parse_name_string), - parser_wrap!(SuperName::ArgObj, parse_arg_obj), - parser_wrap!(SuperName::LocalObj, parse_local_obj) + data, ctx, + parse_name_string, + parse_arg_obj, + parse_local_obj }; - Err(AmlInternalError::AmlInvalidOpCode) + Err(AmlError::AmlInvalidOpCode) } -pub fn parse_target(data: &[u8]) -> Result<(Target, usize), AmlInternalError> { +pub fn parse_target(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + if data[0] == 0x00 { - Ok((Target::Null, 1 as usize)) + Ok(AmlParseType { + val: AmlValue::None, + len: 1 as usize + }) } else { - match parse_super_name(data) { - Ok((name, name_len)) => Ok((Target::SuperName(name), name_len)), - Err(e) => Err(e) - } + parse_super_name(data, ctx) } } diff --git a/src/acpi/aml/parser.rs b/src/acpi/aml/parser.rs new file mode 100644 index 0000000000000000000000000000000000000000..13c51a935e4b8883d7e609e84cba7261e09e2abc --- /dev/null +++ b/src/acpi/aml/parser.rs @@ -0,0 +1,553 @@ +use collections::string::String; +use collections::btree_map::BTreeMap; +use collections::vec::Vec; +use alloc::boxed::Box; + +use spin::RwLockWriteGuard; + +use super::namespace::{ AmlValue, ObjectReference }; +use super::AmlError; + +use acpi::ACPI_TABLE; + +pub type ParseResult = Result<AmlParseType, AmlError>; +pub type AmlParseType = AmlParseTypeGeneric<AmlValue>; + +pub struct AmlParseTypeGeneric<T> { + pub val: T, + pub len: usize +} + +pub enum ExecutionState { + EXECUTING, + CONTINUE, + BREAK, + RETURN(AmlValue) +} + +pub struct AmlExecutionContext { + pub scope: String, + pub local_vars: [AmlValue; 8], + pub arg_vars: [AmlValue; 8], + pub state: ExecutionState, + pub namespace_delta: Vec<String>, + pub ctx_id: u64, + pub sync_level: u8 +} + +impl AmlExecutionContext { + pub fn new(scope: String) -> AmlExecutionContext { + let mut idptr = ACPI_TABLE.next_ctx.write(); + let id: u64 = *idptr; + + *idptr += 1; + + AmlExecutionContext { + scope: scope, + local_vars: [AmlValue::Uninitialized, + AmlValue::Uninitialized, + AmlValue::Uninitialized, + AmlValue::Uninitialized, + AmlValue::Uninitialized, + AmlValue::Uninitialized, + AmlValue::Uninitialized, + AmlValue::Uninitialized], + arg_vars: [AmlValue::Uninitialized, + AmlValue::Uninitialized, + AmlValue::Uninitialized, + AmlValue::Uninitialized, + AmlValue::Uninitialized, + AmlValue::Uninitialized, + AmlValue::Uninitialized, + AmlValue::Uninitialized], + state: ExecutionState::EXECUTING, + namespace_delta: vec!(), + ctx_id: id, + sync_level: 0 + } + } + + pub fn wait_for_event(&mut self, event_ptr: AmlValue) -> Result<bool, AmlError> { + let mut namespace_ptr = self.prelock(); + let mut namespace = match *namespace_ptr { + Some(ref mut n) => n, + None => return Err(AmlError::AmlHardFatal) + }; + + let mutex_idx = match event_ptr { + AmlValue::String(ref s) => s.clone(), + AmlValue::ObjectReference(ref o) => match *o { + ObjectReference::Object(ref s) => s.clone(), + _ => return Err(AmlError::AmlValueError) + }, + _ => return Err(AmlError::AmlValueError) + }; + + let mutex = match namespace.get(&mutex_idx) { + Some(s) => s.clone(), + None => return Err(AmlError::AmlValueError) + }; + + match mutex { + AmlValue::Event(count) => { + if count > 0 { + namespace.insert(mutex_idx, AmlValue::Event(count - 1)); + return Ok(true); + } + }, + _ => return Err(AmlError::AmlValueError) + } + + Ok(false) + } + + pub fn signal_event(&mut self, event_ptr: AmlValue) -> Result<(), AmlError> { + let mut namespace_ptr = self.prelock(); + let mut namespace = match *namespace_ptr { + Some(ref mut n) => n, + None => return Err(AmlError::AmlHardFatal) + }; + + + let mutex_idx = match event_ptr { + AmlValue::String(ref s) => s.clone(), + AmlValue::ObjectReference(ref o) => match *o { + ObjectReference::Object(ref s) => s.clone(), + _ => return Err(AmlError::AmlValueError) + }, + _ => return Err(AmlError::AmlValueError) + }; + + let mutex = match namespace.get(&mutex_idx) { + Some(s) => s.clone(), + None => return Err(AmlError::AmlValueError) + }; + + match mutex { + AmlValue::Event(count) => { + namespace.insert(mutex_idx, AmlValue::Event(count + 1)); + return Ok(()); + }, + _ => return Err(AmlError::AmlValueError) + } + + Ok(()) + } + + pub fn release_mutex(&mut self, mutex_ptr: AmlValue) -> Result<(), AmlError> { + let id = self.ctx_id; + + let mut namespace_ptr = self.prelock(); + let mut namespace = match *namespace_ptr { + Some(ref mut n) => n, + None => return Err(AmlError::AmlHardFatal) + }; + + let mutex_idx = match mutex_ptr { + AmlValue::String(ref s) => s.clone(), + AmlValue::ObjectReference(ref o) => match *o { + ObjectReference::Object(ref s) => s.clone(), + _ => return Err(AmlError::AmlValueError) + }, + _ => return Err(AmlError::AmlValueError) + }; + + let mutex = match namespace.get(&mutex_idx) { + Some(s) => s.clone(), + None => return Err(AmlError::AmlValueError) + }; + + match mutex { + AmlValue::Mutex((sync_level, owner)) => { + if let Some(o) = owner { + if o == id { + if sync_level == self.sync_level { + namespace.insert(mutex_idx, AmlValue::Mutex((sync_level, None))); + return Ok(()); + } else { + return Err(AmlError::AmlValueError); + } + } else { + return Err(AmlError::AmlHardFatal); + } + } + }, + AmlValue::OperationRegion(ref region) => { + if let Some(o) = region.accessed_by { + if o == id { + let mut new_region = region.clone(); + new_region.accessed_by = None; + + namespace.insert(mutex_idx, AmlValue::OperationRegion(new_region)); + return Ok(()); + } else { + return Err(AmlError::AmlHardFatal); + } + } + }, + _ => return Err(AmlError::AmlValueError) + } + + Ok(()) + } + + pub fn acquire_mutex(&mut self, mutex_ptr: AmlValue) -> Result<bool, AmlError> { + let id = self.ctx_id; + + let mut namespace_ptr = self.prelock(); + let mut namespace = match *namespace_ptr { + Some(ref mut n) => n, + None => return Err(AmlError::AmlHardFatal) + }; + let mutex_idx = match mutex_ptr { + AmlValue::String(ref s) => s.clone(), + AmlValue::ObjectReference(ref o) => match *o { + ObjectReference::Object(ref s) => s.clone(), + _ => return Err(AmlError::AmlValueError) + }, + _ => return Err(AmlError::AmlValueError) + }; + + let mutex = match namespace.get(&mutex_idx) { + Some(s) => s.clone(), + None => return Err(AmlError::AmlValueError) + }; + + match mutex { + AmlValue::Mutex((sync_level, owner)) => { + if owner == None { + if sync_level < self.sync_level { + return Err(AmlError::AmlValueError); + } + + namespace.insert(mutex_idx, AmlValue::Mutex((sync_level, Some(id)))); + self.sync_level = sync_level; + + return Ok(true); + } + }, + AmlValue::OperationRegion(ref o) => { + if o.accessed_by == None { + let mut new_region = o.clone(); + new_region.accessed_by = Some(id); + + namespace.insert(mutex_idx, AmlValue::OperationRegion(new_region)); + return Ok(true); + } + }, + _ => return Err(AmlError::AmlValueError) + } + + Ok(false) + } + + pub fn add_to_namespace(&mut self, name: String, value: AmlValue) -> Result<(), AmlError> { + let mut namespace = ACPI_TABLE.namespace.write(); + + if let Some(ref mut namespace) = *namespace { + if let Some(obj) = namespace.get(&name) { + match *obj { + AmlValue::Uninitialized => (), + AmlValue::Method(ref m) => { + if m.term_list.len() != 0 { + return Err(AmlError::AmlValueError); + } + }, + _ => return Err(AmlError::AmlValueError) + } + } + + self.namespace_delta.push(name.clone()); + namespace.insert(name, value); + + Ok(()) + } else { + Err(AmlError::AmlValueError) + } + } + + pub fn clean_namespace(&mut self) { + let mut namespace = ACPI_TABLE.namespace.write(); + + if let Some(ref mut namespace) = *namespace { + for k in &self.namespace_delta { + namespace.remove(k); + } + } + } + + pub fn init_arg_vars(&mut self, parameters: Vec<AmlValue>) { + if parameters.len() > 8 { + return; + } + + let mut cur = 0; + while cur < parameters.len() { + self.arg_vars[cur] = parameters[cur].clone(); + cur += 1; + } + } + + pub fn prelock(&mut self) -> RwLockWriteGuard<'static, Option<BTreeMap<String, AmlValue>>> { + ACPI_TABLE.namespace.write() + } + + fn modify_local_obj(&mut self, local: usize, value: AmlValue) -> Result<(), AmlError> { + self.local_vars[local] = value.get_as_type(self.local_vars[local].clone())?; + Ok(()) + } + + fn modify_object(&mut self, name: String, value: AmlValue) -> Result<(), AmlError> { + if let Some(ref mut namespace) = *ACPI_TABLE.namespace.write() { + let coercion_obj = { + let obj = namespace.get(&name); + + if let Some(o) = obj { + o.clone() + } else { + AmlValue::Uninitialized + } + }; + + namespace.insert(name, value.get_as_type(coercion_obj)?); + Ok(()) + } else { + Err(AmlError::AmlHardFatal) + } + } + + fn modify_index_final(&mut self, name: String, value: AmlValue, indices: Vec<u64>) -> Result<(), AmlError> { + if let Some(ref mut namespace) = *ACPI_TABLE.namespace.write() { + let mut obj = if let Some(s) = namespace.get(&name) { + s.clone() + } else { + return Err(AmlError::AmlValueError); + }; + + obj = self.modify_index_core(obj, value, indices)?; + + namespace.insert(name, obj); + Ok(()) + } else { + Err(AmlError::AmlValueError) + } + } + + fn modify_index_core(&mut self, obj: AmlValue, value: AmlValue, indices: Vec<u64>) -> Result<AmlValue, AmlError> { + match obj { + AmlValue::String(ref string) => { + if indices.len() != 1 { + return Err(AmlError::AmlValueError); + } + + let mut bytes = string.clone().into_bytes(); + bytes[indices[0] as usize] = value.get_as_integer()? as u8; + + let string = String::from_utf8(bytes).unwrap(); + + Ok(AmlValue::String(string)) + }, + AmlValue::Buffer(ref b) => { + if indices.len() != 1 { + return Err(AmlError::AmlValueError); + } + + let mut b = b.clone(); + b[indices[0] as usize] = value.get_as_integer()? as u8; + + Ok(AmlValue::Buffer(b)) + }, + AmlValue::BufferField(ref b) => { + if indices.len() != 1 { + return Err(AmlError::AmlValueError); + } + + let mut idx = indices[0]; + idx += b.index.get_as_integer()?; + + self.modify(AmlValue::ObjectReference(ObjectReference::Index(b.source_buf.clone(), Box::new(AmlValue::Integer(idx.clone())))), value); + + Ok(AmlValue::BufferField(b.clone())) + }, + AmlValue::Package(ref p) => { + if indices.len() < 0 { + return Err(AmlError::AmlValueError); + } + + let mut p = p.clone(); + + if indices.len() == 1 { + p[indices[0] as usize] = value; + } else { + p[indices[0] as usize] = self.modify_index_core(p[indices[0] as usize].clone(), value, indices[1..].to_vec())?; + } + + Ok(AmlValue::Package(p)) + }, + _ => return Err(AmlError::AmlValueError) + } + } + + pub fn modify_index(&mut self, name: AmlValue, value: AmlValue, indices: Vec<u64>) -> Result<(), AmlError>{ + match name { + AmlValue::ObjectReference(r) => match r { + ObjectReference::Object(s) => self.modify_index_final(s, value, indices), + ObjectReference::Index(c, v) => { + let mut indices = indices.clone(); + indices.push(v.get_as_integer()?); + + self.modify_index(*c, value, indices) + }, + ObjectReference::ArgObj(_) => Err(AmlError::AmlValueError), + ObjectReference::LocalObj(i) => { + let v = self.local_vars[i as usize].clone(); + self.local_vars[i as usize] = self.modify_index_core(v, value, indices)?; + + Ok(()) + } + }, + _ => Err(AmlError::AmlValueError) + } + } + + pub fn modify(&mut self, name: AmlValue, value: AmlValue) -> Result<(), AmlError> { + match name { + AmlValue::ObjectReference(r) => match r { + ObjectReference::ArgObj(_) => Err(AmlError::AmlValueError), + ObjectReference::LocalObj(i) => self.modify_local_obj(i as usize, value), + ObjectReference::Object(s) => self.modify_object(s, value), + ObjectReference::Index(c, v) => self.modify_index(*c, value, vec!(v.get_as_integer()?)) + }, + AmlValue::String(s) => self.modify_object(s, value), + _ => Err(AmlError::AmlValueError) + } + } + + fn copy_local_obj(&mut self, local: usize, value: AmlValue) -> Result<(), AmlError> { + self.local_vars[local] = value; + Ok(()) + } + + fn copy_object(&mut self, name: String, value: AmlValue) -> Result<(), AmlError> { + if let Some(ref mut namespace) = *ACPI_TABLE.namespace.write() { + namespace.insert(name, value); + Ok(()) + } else { + Err(AmlError::AmlHardFatal) + } + } + + pub fn copy(&mut self, name: AmlValue, value: AmlValue) -> Result<(), AmlError> { + match name { + AmlValue::ObjectReference(r) => match r { + ObjectReference::ArgObj(_) => Err(AmlError::AmlValueError), + ObjectReference::LocalObj(i) => self.copy_local_obj(i as usize, value), + ObjectReference::Object(s) => self.copy_object(s, value), + ObjectReference::Index(c, v) => self.modify_index(*c, value, vec!(v.get_as_integer()?)) + }, + AmlValue::String(s) => self.copy_object(s, value), + _ => Err(AmlError::AmlValueError) + } + } + + fn get_index_final(&self, name: String, indices: Vec<u64>) -> Result<AmlValue, AmlError> { + if let Some(ref namespace) = *ACPI_TABLE.namespace.read() { + let obj = if let Some(s) = namespace.get(&name) { + s.clone() + } else { + return Err(AmlError::AmlValueError); + }; + + self.get_index_core(obj, indices) + } else { + Err(AmlError::AmlValueError) + } + } + + fn get_index_core(&self, obj: AmlValue, indices: Vec<u64>) -> Result<AmlValue, AmlError> { + match obj { + AmlValue::String(ref string) => { + if indices.len() != 1 { + return Err(AmlError::AmlValueError); + } + + let mut bytes = string.clone().into_bytes(); + Ok(AmlValue::Integer(bytes[indices[0] as usize] as u64)) + }, + AmlValue::Buffer(ref b) => { + if indices.len() != 1 { + return Err(AmlError::AmlValueError); + } + + Ok(AmlValue::Integer(b[indices[0] as usize] as u64)) + }, + AmlValue::BufferField(ref b) => { + if indices.len() != 1 { + return Err(AmlError::AmlValueError); + } + + let mut idx = indices[0]; + idx += b.index.get_as_integer()?; + + Ok(AmlValue::Integer(b.source_buf.get_as_buffer()?[idx as usize] as u64)) + }, + AmlValue::Package(ref p) => { + if indices.len() < 0 { + return Err(AmlError::AmlValueError); + } + + if indices.len() == 1 { + Ok(p[indices[0] as usize].clone()) + } else { + self.get_index_core(p[indices[0] as usize].clone(), indices[1..].to_vec()) + } + }, + _ => Err(AmlError::AmlValueError) + } + } + + pub fn get_index(&self, name: AmlValue, indices: Vec<u64>) -> Result<AmlValue, AmlError>{ + match name { + AmlValue::ObjectReference(r) => match r { + ObjectReference::Object(s) => self.get_index_final(s, indices), + ObjectReference::Index(c, v) => { + let mut indices = indices.clone(); + indices.push(v.get_as_integer()?); + + self.get_index(*c, indices) + }, + ObjectReference::ArgObj(_) => Err(AmlError::AmlValueError), + ObjectReference::LocalObj(i) => { + let v = self.local_vars[i as usize].clone(); + self.get_index_core(v, indices) + } + }, + _ => Err(AmlError::AmlValueError) + } + } + + pub fn get(&self, name: AmlValue) -> Result<AmlValue, AmlError> { + Ok(match name { + AmlValue::ObjectReference(r) => match r { + ObjectReference::ArgObj(i) => self.arg_vars[i as usize].clone(), + ObjectReference::LocalObj(i) => self.local_vars[i as usize].clone(), + ObjectReference::Object(ref s) => if let Some(ref namespace) = *ACPI_TABLE.namespace.read() { + if let Some(o) = namespace.get(s) { + o.clone() + } else { + AmlValue::None + } + } else { AmlValue::None }, + ObjectReference::Index(c, v) => self.get_index(*c, vec!(v.get_as_integer()?))?, + }, + AmlValue::String(ref s) => if let Some(ref namespace) = *ACPI_TABLE.namespace.read() { + if let Some(o) = namespace.get(s) { + o.clone() + } else { + AmlValue::None + } + } else { AmlValue::None }, + _ => AmlValue::None + }) + } +} diff --git a/src/acpi/aml/parsermacros.rs b/src/acpi/aml/parsermacros.rs index 50e3aed575cc59feb62baca60c2e5db7636c92b3..31a23386ffc232dbc87b74d8b5b6a8005db25563 100644 --- a/src/acpi/aml/parsermacros.rs +++ b/src/acpi/aml/parsermacros.rs @@ -1,40 +1,43 @@ #[macro_export] macro_rules! parser_selector { - {$data:expr, $func:expr} => { - match $func($data) { + {$data:expr, $ctx:expr, $func:expr} => { + match $func($data, $ctx) { Ok(res) => return Ok(res), - Err(AmlInternalError::AmlInvalidOpCode) => (), + Err(AmlError::AmlInvalidOpCode) => (), Err(e) => return Err(e) } }; - {$data:expr, $func:expr, $($funcs:expr),+} => { - parser_selector! {$data, $func}; - parser_selector! {$data, $($funcs),*}; + {$data:expr, $ctx:expr, $func:expr, $($funcs:expr),+} => { + parser_selector! {$data, $ctx, $func}; + parser_selector! {$data, $ctx, $($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_rules! parser_selector_simple { + {$data:expr, $func:expr} => { + match $func($data) { + Ok(res) => return Ok(res), + Err(AmlError::AmlInvalidOpCode) => (), + Err(e) => return Err(e) } }; + {$data:expr, $func:expr, $($funcs:expr),+} => { + parser_selector_simple! {$data, $func}; + parser_selector_simple! {$data, $($funcs),*}; + }; } #[macro_export] macro_rules! parser_opcode { ($data:expr, $opcode:expr) => { if $data[0] != $opcode { - return Err(AmlInternalError::AmlInvalidOpCode); + return Err(AmlError::AmlInvalidOpCode); } }; ($data:expr, $opcode:expr, $alternate_opcode:expr) => { if $data[0] != $opcode && $data[0] != $alternate_opcode { - return Err(AmlInternalError::AmlInvalidOpCode); + return Err(AmlError::AmlInvalidOpCode); } }; } @@ -43,7 +46,7 @@ macro_rules! parser_opcode { macro_rules! parser_opcode_extended { ($data:expr, $opcode:expr) => { if $data[0] != 0x5B || $data[1] != $opcode { - return Err(AmlInternalError::AmlInvalidOpCode); + return Err(AmlError::AmlInvalidOpCode); } }; } diff --git a/src/acpi/aml/pkglength.rs b/src/acpi/aml/pkglength.rs index 7c4ace8d124aea4f64ac9bc7c8740d38449451a4..b93939f0da8dac6301628475b07f120397b54cc9 100644 --- a/src/acpi/aml/pkglength.rs +++ b/src/acpi/aml/pkglength.rs @@ -1,6 +1,6 @@ -use super::AmlInternalError; +use super::AmlError; -pub fn parse_pkg_length(data: &[u8]) -> Result<(usize, usize), AmlInternalError> { +pub fn parse_pkg_length(data: &[u8]) -> Result<(usize, usize), AmlError> { let lead_byte = data[0]; let count_bytes: usize = (lead_byte >> 6) as usize; @@ -10,7 +10,7 @@ pub fn parse_pkg_length(data: &[u8]) -> Result<(usize, usize), AmlInternalError> let upper_two = (lead_byte >> 4) & 0x03; if upper_two != 0 { - return Err(AmlInternalError::AmlParseError("Invalid package length")); + return Err(AmlError::AmlParseError("Invalid package length")); } let mut current_byte = 0; diff --git a/src/acpi/aml/termlist.rs b/src/acpi/aml/termlist.rs index b236584e10895b0a352e1d961c81692e8b969c62..262f731263ddf59cbb92973016439d88e2ed1f29 100644 --- a/src/acpi/aml/termlist.rs +++ b/src/acpi/aml/termlist.rs @@ -1,135 +1,174 @@ -use alloc::boxed::Box; -use collections::string::String; use collections::vec::Vec; -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::AmlError; +use super::parser::{ AmlParseType, ParseResult, AmlExecutionContext, ExecutionState }; +use super::namespace::{AmlValue, get_namespace_string}; +use super::namespacemodifier::parse_namespace_modifier; +use super::namedobj::parse_named_obj; +use super::dataobj::{parse_data_obj, parse_arg_obj, parse_local_obj}; +use super::type1opcode::parse_type1_opcode; +use super::type2opcode::parse_type2_opcode; 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], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) } -} - -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; + let res = parse_term_obj(&data[current_offset..], ctx)?; + + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: data.len() + }) + } + + current_offset += res.len; } - Ok(terms) + Ok(AmlParseType { + val: AmlValue::None, + len: data.len() + }) } -pub fn parse_term_arg(data: &[u8]) -> Result<(TermArg, usize), AmlInternalError> { +pub fn parse_term_arg(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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)) + data, ctx, + parse_local_obj, + parse_data_obj, + parse_arg_obj, + parse_type2_opcode }; - Err(AmlInternalError::AmlInvalidOpCode) + Err(AmlError::AmlInvalidOpCode) } -pub fn parse_object_list(data: &[u8]) -> Result<Vec<Object>, AmlInternalError> { - let mut terms: Vec<Object> = vec!(); +pub fn parse_object_list(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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; + let res = parse_object(&data[current_offset..], ctx)?; + + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: data.len() + }) + } + + current_offset += res.len; } - Ok(terms) + Ok(AmlParseType { + val: AmlValue::None, + len: data.len() + }) } -fn parse_object(data: &[u8]) -> Result<(Object, usize), AmlInternalError> { +fn parse_object(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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)) + data, ctx, + parse_namespace_modifier, + parse_named_obj }; - Err(AmlInternalError::AmlInvalidOpCode) + Err(AmlError::AmlInvalidOpCode) } -pub fn parse_method_invocation(data: &[u8]) -> Result<(MethodInvocation, usize), AmlInternalError> { - let (name, name_len) = parse_name_string(data)?; - Err(AmlInternalError::AmlDeferredLoad) +pub fn parse_method_invocation(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + + let name = parse_name_string(data, ctx)?; + let method = ctx.get(name.val.clone())?; + + let method = match method { + AmlValue::None => return Err(AmlError::AmlDeferredLoad), + _ => method.get_as_method()? + }; + + let mut cur = 0; + let mut params: Vec<AmlValue> = vec!(); + + let mut current_offset = name.len; + + while cur < method.arg_count { + let res = parse_term_arg(&data[current_offset..], ctx)?; + + current_offset += res.len; + cur += 1; + + params.push(res.val); + } + + Ok(AmlParseType { + val: method.execute(get_namespace_string(ctx.scope.clone(), name.val)?, params), + len: current_offset + }) } -fn parse_term_obj(data: &[u8]) -> Result<(TermObj, usize), AmlInternalError> { +fn parse_term_obj(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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)) + data, ctx, + parse_namespace_modifier, + parse_named_obj, + parse_type1_opcode, + parse_type2_opcode }; - Err(AmlInternalError::AmlInvalidOpCode) + Err(AmlError::AmlInvalidOpCode) } diff --git a/src/acpi/aml/type1opcode.rs b/src/acpi/aml/type1opcode.rs index 103e5428483c7e2348d1f7e427b73ee015c21b4d..e5c702315118a13b799bfebed8b7826697f66325 100644 --- a/src/acpi/aml/type1opcode.rs +++ b/src/acpi/aml/type1opcode.rs @@ -1,77 +1,31 @@ -use alloc::boxed::Box; -use collections::string::String; -use collections::vec::Vec; - -use super::{AmlInternalError, AmlExecutable, AmlValue, AmlNamespace}; +use super::AmlError; +use super::parser::{AmlParseType, ParseResult, AmlExecutionContext, ExecutionState}; +use super::namespace::{AmlValue, ObjectReference, OperationRegion}; 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 +use super::termlist::{parse_term_arg, parse_term_list}; +use super::namestring::{parse_name_string, parse_super_name}; + +use time::monotonic; + +use acpi::{Sdt, load_table, get_sdt_signature}; +use super::{parse_aml_table, is_aml_table}; + +pub fn parse_type1_opcode(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) } -} - -#[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, + data, ctx, + parse_def_break, + parse_def_breakpoint, + parse_def_continue, + parse_def_noop, parse_def_fatal, parse_def_if_else, parse_def_load, @@ -86,174 +40,433 @@ pub fn parse_type1_opcode(data: &[u8]) -> Result<(Type1OpCode, usize), AmlIntern parse_def_while }; - Err(AmlInternalError::AmlInvalidOpCode) + Err(AmlError::AmlInvalidOpCode) } -fn parse_def_fatal(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { - if data[0] != 0x5B || data[1] != 0x32 { - return Err(AmlInternalError::AmlInvalidOpCode); +fn parse_def_break(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) } + + parser_opcode!(data, 0xA5); + ctx.state = ExecutionState::BREAK; + + Ok(AmlParseType { + val: AmlValue::None, + len: 1 as usize + }) +} - 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..])?; +fn parse_def_breakpoint(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + + parser_opcode!(data, 0xCC); - Ok((Type1OpCode::DefFatal {fatal_type, fatal_code, fatal_arg}, fatal_arg_len + 5)) + Ok(AmlParseType { + val: AmlValue::None, + len: 1 as usize + }) } -fn parse_def_load(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { - if data[0] != 0x5B || data[1] != 0x20 { - return Err(AmlInternalError::AmlInvalidOpCode); +fn parse_def_continue(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) } + + parser_opcode!(data, 0x9F); + ctx.state = ExecutionState::CONTINUE; + + Ok(AmlParseType { + val: AmlValue::None, + len: 1 as usize + }) +} - let (name, name_len) = parse_name_string(&data[2..])?; - let (ddb_handle_object, ddb_handle_object_len) = parse_super_name(&data[2 + name_len..])?; +fn parse_def_noop(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + + parser_opcode!(data, 0xA3); - Ok((Type1OpCode::DefLoad {name, ddb_handle_object}, 2 + name_len + ddb_handle_object_len)) + Ok(AmlParseType { + val: AmlValue::None, + len: 1 as usize + }) } -fn parse_def_notify(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { - if data[0] != 0x86 { - return Err(AmlInternalError::AmlInvalidOpCode); +fn parse_def_fatal(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) } + + parser_opcode_extended!(data, 0x32); - let (object, object_len) = parse_super_name(&data[1..])?; - let (value, value_len) = parse_term_arg(&data[1 + object_len..])?; + let fatal_type = data[2]; + let fatal_code: u16 = (data[3] as u16) + ((data[4] as u16) << 8); + let fatal_arg = parse_term_arg(&data[5..], ctx)?; - Ok((Type1OpCode::DefNotify {object, value}, 1 + object_len + value_len)) + Err(AmlError::AmlFatalError(fatal_type, fatal_code, fatal_arg.val)) } -fn parse_def_release(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { - if data[0] != 0x5B || data[1] != 0x27 { - return Err(AmlInternalError::AmlInvalidOpCode); +fn parse_def_load(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + + parser_opcode_extended!(data, 0x20); + + let name = parse_name_string(&data[2..], ctx)?; + let ddb_handle_object = parse_super_name(&data[2 + name.len..], ctx)?; + + let tbl = ctx.get(name.val)?.get_as_buffer()?; + let sdt = unsafe { &*(tbl.as_ptr() as *const Sdt) }; + + if is_aml_table(sdt) { + load_table(get_sdt_signature(sdt)); + let delta = parse_aml_table(sdt)?; + ctx.modify(ddb_handle_object.val, AmlValue::DDBHandle((delta, get_sdt_signature(sdt)))); + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + name.len + ddb_handle_object.len + }) + } else { + Err(AmlError::AmlValueError) } - - 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); +fn parse_def_notify(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) } + + parser_opcode!(data, 0x86); - let (object, object_len) = parse_super_name(&data[2..])?; + let object = parse_super_name(&data[1..], ctx)?; + let value = parse_term_arg(&data[1 + object.len..], ctx)?; - Ok((Type1OpCode::DefReset(object), 2 + object_len)) -} + let number = value.val.get_as_integer()? as u8; -fn parse_def_signal(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { - if data[0] != 0x5B || data[1] != 0x24 { - return Err(AmlInternalError::AmlInvalidOpCode); + match ctx.get(object.val)? { + AmlValue::Device(d) => { + if let Some(methods) = d.notify_methods.get(&number) { + for method in methods { + method(); + } + } + }, + AmlValue::Processor(d) => { + if let Some(methods) = d.notify_methods.get(&number) { + for method in methods { + method(); + } + } + }, + AmlValue::ThermalZone(d) => { + if let Some(methods) = d.notify_methods.get(&number) { + for method in methods { + method(); + } + } + }, + _ => return Err(AmlError::AmlValueError) } - let (object, object_len) = parse_super_name(&data[2..])?; + Ok(AmlParseType { + val: AmlValue::None, + len: 1 + object.len + value.len + }) +} - Ok((Type1OpCode::DefSignal(object), 2 + object_len)) +fn parse_def_release(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + + parser_opcode_extended!(data, 0x27); + + let obj = parse_super_name(&data[2..], ctx)?; + ctx.release_mutex(obj.val); + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + obj.len + }) } -fn parse_def_sleep(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { - if data[0] != 0x5B || data[1] != 0x22 { - return Err(AmlInternalError::AmlInvalidOpCode); +fn parse_def_reset(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) } + + parser_opcode_extended!(data, 0x26); + + let object = parse_super_name(&data[2..], ctx)?; + ctx.get(object.val.clone())?.get_as_event()?; - let (time, time_len) = parse_term_arg(&data[2..])?; + ctx.modify(object.val.clone(), AmlValue::Event(0)); - Ok((Type1OpCode::DefSleep(time), 2 + time_len)) + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + object.len + }) } -fn parse_def_stall(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { - if data[0] != 0x5B || data[1] != 0x21 { - return Err(AmlInternalError::AmlInvalidOpCode); +fn parse_def_signal(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) } + + parser_opcode_extended!(data, 0x24); + let object = parse_super_name(&data[2..], ctx)?; + + ctx.signal_event(object.val)?; + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + object.len + }) +} - let (time, time_len) = parse_term_arg(&data[2..])?; +fn parse_def_sleep(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + + parser_opcode_extended!(data, 0x22); + + let time = parse_term_arg(&data[2..], ctx)?; + let timeout = time.val.get_as_integer()?; + + let (seconds, nanoseconds) = monotonic(); + let starting_time_ns = nanoseconds + (seconds * 1000000000); + + loop { + let (seconds, nanoseconds) = monotonic(); + let current_time_ns = nanoseconds + (seconds * 1000000000); + + if current_time_ns - starting_time_ns > timeout as u64 * 1000000 { + break; + } + } - Ok((Type1OpCode::DefStall(time), 2 + time_len)) + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + time.len + }) } -fn parse_def_unload(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { - if data[0] != 0x5B || data[1] != 0x2A { - return Err(AmlInternalError::AmlInvalidOpCode); +fn parse_def_stall(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + + parser_opcode_extended!(data, 0x21); + + let time = parse_term_arg(&data[2..], ctx)?; + let timeout = time.val.get_as_integer()?; + + let (seconds, nanoseconds) = monotonic(); + let starting_time_ns = nanoseconds + (seconds * 1000000000); + + loop { + let (seconds, nanoseconds) = monotonic(); + let current_time_ns = nanoseconds + (seconds * 1000000000); + + if current_time_ns - starting_time_ns > timeout as u64 * 1000 { + break; + } } - let (object, object_len) = parse_super_name(&data[2..])?; - - Ok((Type1OpCode::DefUnload(object), 2 + object_len)) + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + time.len + }) } -fn parse_def_if_else(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { - if data[0] != 0xA0 { - return Err(AmlInternalError::AmlInvalidOpCode); +fn parse_def_unload(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) } + + parser_opcode_extended!(data, 0x2A); - let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; + let object = parse_super_name(&data[2..], ctx)?; - 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 delta = ctx.get(object.val)?.get_as_ddb_handle()?; + let mut namespace = ctx.prelock(); - let (else_block, else_block_len) = parse_def_else(&data[1 + pkg_length..])?; + if let Some(ref mut ns) = *namespace { + for o in delta.0 { + ns.remove(&o); + } + } - return Ok((Type1OpCode::DefIfElse {if_block, else_block}, - pkg_length + else_block_len + 1)); + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + object.len + }) } -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)); +fn parse_def_if_else(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) } + + parser_opcode!(data, 0xA0); 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) + let if_condition = parse_term_arg(&data[1 + pkg_length_len .. 1 + pkg_length], ctx)?; + + let (else_length, else_length_len) = if data.len() > 1 + pkg_length && data[1 + pkg_length] == 0xA1 { + parse_pkg_length(&data[2 + pkg_length..])? + } else { + (0 as usize, 0 as usize) + }; + + if if_condition.val.get_as_integer()? > 0 { + parse_term_list(&data[1 + pkg_length_len + if_condition.len .. 1 + pkg_length], ctx)?; + } else if else_length > 0 { + parse_term_list(&data[2 + pkg_length + else_length_len .. 2 + pkg_length + else_length], ctx)?; } + + Ok(AmlParseType { + val: AmlValue::None, + len: 1 + pkg_length + if else_length > 0 { 1 + else_length } else { 0 } + }) } -fn parse_def_while(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { - if data[0] != 0xA2 { - return Err(AmlInternalError::AmlInvalidOpCode); +fn parse_def_while(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) } + + parser_opcode!(data, 0xA2); 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)) + loop { + let predicate = parse_term_arg(&data[1 + pkg_length_len..], ctx)?; + if predicate.val.get_as_integer()? == 0 { + break; + } + + parse_term_list(&data[1 + pkg_length_len + predicate.len .. 1 + pkg_length], ctx)?; + + match ctx.state { + ExecutionState::EXECUTING => (), + ExecutionState::BREAK => { + ctx.state = ExecutionState::EXECUTING; + break; + }, + ExecutionState::CONTINUE => ctx.state = ExecutionState::EXECUTING, + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + } + + Ok(AmlParseType { + val: AmlValue::None, + len: 1 + pkg_length + }) } -fn parse_def_return(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { - if data[0] != 0xA4 { - return Err(AmlInternalError::AmlInvalidOpCode); +fn parse_def_return(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) } + + parser_opcode!(data, 0xA4); - let (arg_object, arg_object_len) = parse_term_arg(&data[1..])?; + let arg_object = parse_term_arg(&data[1..], ctx)?; + ctx.state = ExecutionState::RETURN(arg_object.val); - Ok((Type1OpCode::DefReturn(arg_object), 1 + arg_object_len)) + Ok(AmlParseType { + val: AmlValue::None, + len: 1 + arg_object.len + }) } diff --git a/src/acpi/aml/type2opcode.rs b/src/acpi/aml/type2opcode.rs index 744dbef502ce9b4b11b12bbf06fd71f8f43eb822..37b3001da1382534cc5b1da8947b6a56edf94a65 100644 --- a/src/acpi/aml/type2opcode.rs +++ b/src/acpi/aml/type2opcode.rs @@ -2,217 +2,16 @@ use alloc::boxed::Box; use collections::string::String; use collections::vec::Vec; -use super::{AmlInternalError, AmlExecutable, AmlValue, AmlNamespace}; +use super::{AmlError, parse_aml_with_scope}; +use super::parser::{AmlParseType, ParseResult, AmlExecutionContext, ExecutionState}; +use super::namespace::{AmlValue, ObjectReference, OperationRegion}; 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}; +use super::termlist::{parse_term_arg, parse_method_invocation}; +use super::namestring::{parse_super_name, parse_target, parse_name_string, parse_simple_name}; +use super::dataobj::parse_data_ref_obj; -#[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) -} +use time::monotonic; +use acpi::{ACPI_TABLE, SDT_POINTERS}; #[derive(Debug, Clone)] pub enum MatchOpcode { @@ -224,84 +23,18 @@ pub enum MatchOpcode { 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], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) } -} - -pub fn parse_type2_opcode(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_selector! { - data, + data, ctx, parse_def_increment, parse_def_acquire, parse_def_wait, @@ -344,589 +77,1703 @@ pub fn parse_type2_opcode(data: &[u8]) -> Result<(Type2OpCode, usize), AmlIntern 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) + parse_def_buffer, + parse_def_package, + parse_def_var_package, + parse_def_object_type, + parse_def_deref_of, + parse_def_ref_of, + parse_def_index, + parse_method_invocation }; - Err(AmlInternalError::AmlInvalidOpCode) + Err(AmlError::AmlInvalidOpCode) } -pub fn parse_type6_opcode(data: &[u8]) -> Result<(Type6OpCode, usize), AmlInternalError> { +pub fn parse_type6_opcode(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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) + data, ctx, + parse_def_deref_of, + parse_def_ref_of, + parse_def_index, + parse_method_invocation }; - Err(AmlInternalError::AmlInvalidOpCode) + Err(AmlError::AmlInvalidOpCode) } -pub fn parse_def_object_type(data: &[u8]) -> Result<(DefObjectType, usize), AmlInternalError> { +pub fn parse_def_object_type(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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) + data, ctx, + parse_super_name, + parse_def_ref_of, + parse_def_deref_of, + parse_def_index } - Err(AmlInternalError::AmlInvalidOpCode) + Err(AmlError::AmlInvalidOpCode) } -pub fn parse_def_package(data: &[u8]) -> Result<(DefPackage, usize), AmlInternalError> { +pub fn parse_def_package(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + + // TODO: Handle deferred loads in here 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)) + let numelements = data[1 + pkg_length_len] as usize; + let mut elements = parse_package_elements_list(&data[2 + pkg_length_len .. 1 + pkg_length], ctx)?.val.get_as_package()?; + + if elements.len() > numelements { + elements = elements[0 .. numelements].to_vec(); + } else if numelements > elements.len() { + for _ in 0..numelements - elements.len() { + elements.push(AmlValue::Uninitialized); + } + } + + Ok(AmlParseType { + val: AmlValue::Package(elements), + len: 1 + pkg_length + }) } -pub fn parse_def_var_package(data: &[u8]) -> Result<(DefVarPackage, usize), AmlInternalError> { +pub fn parse_def_var_package(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + + // TODO: Handle deferred loads in here 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) - }; + let num_elements = parse_term_arg(&data[1 + pkg_length_len .. 1 + pkg_length], ctx)?; + let mut elements = parse_package_elements_list(&data[1 + pkg_length_len + num_elements.len .. + 1 + pkg_length], ctx)?.val.get_as_package()?; - Ok((DefVarPackage::Package {num_elements, elements}, 1 + pkg_length)) + let numelements = num_elements.val.get_as_integer()? as usize; + + if elements.len() > numelements { + elements = elements[0 .. numelements].to_vec(); + } else if numelements > elements.len() { + for _ in 0..numelements - elements.len() { + elements.push(AmlValue::Uninitialized); + } + } + + Ok(AmlParseType { + val: AmlValue::Package(elements), + len: 1 + pkg_length + }) } -fn parse_package_elements_list(data: &[u8]) -> Result<Vec<PackageElement>, AmlInternalError> { +fn parse_package_elements_list(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + let mut current_offset: usize = 0; - let mut elements: Vec<PackageElement> = vec!(); + let mut elements: Vec<AmlValue> = 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) - } + let dro = if let Ok(e) = parse_data_ref_obj(&data[current_offset..], ctx) { + e + } else { + let d = parse_name_string(&data[current_offset..], ctx)?; + AmlParseType { + val: AmlValue::ObjectReference(ObjectReference::Object(d.val.get_as_string()?)), + len: d.len + } + }; + + elements.push(dro.val); + current_offset += dro.len; } - Ok(elements) + Ok(AmlParseType { + val: AmlValue::Package(elements), + len: data.len() + }) } -pub fn parse_def_buffer(data: &[u8]) -> Result<(DefBuffer, usize), AmlInternalError> { +pub fn parse_def_buffer(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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(); + let buffer_size = parse_term_arg(&data[1 + pkg_length_len..], ctx)?; + let mut byte_list = data[1 + pkg_length_len + buffer_size.len .. 1 + pkg_length].to_vec().clone(); - Ok((DefBuffer::Buffer {buffer_size, byte_list}, pkg_length + 1)) + byte_list.truncate(buffer_size.val.get_as_integer()? as usize); + + Ok(AmlParseType { + val: AmlValue::Buffer(byte_list), + len: 1 + pkg_length + }) } -fn parse_def_ref_of(data: &[u8]) -> Result<(SuperName, usize), AmlInternalError> { +fn parse_def_ref_of(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + parser_opcode!(data, 0x71); - let (obj_reference, obj_reference_len) = parse_super_name(&data[1..])?; - Ok((obj_reference, obj_reference_len + 1)) + let obj = parse_super_name(&data[1..], ctx)?; + let res = match obj.val { + AmlValue::String(ref s) => { + match ctx.get(AmlValue::String(s.clone()))? { + AmlValue::None => return Err(AmlError::AmlValueError), + _ => ObjectReference::Object(s.clone()) + } + }, + AmlValue::ObjectReference(ref o) => o.clone(), + _ => return Err(AmlError::AmlValueError) + }; + + Ok(AmlParseType { + val: AmlValue::ObjectReference(res), + len: 1 + obj.len + }) } -fn parse_def_deref_of(data: &[u8]) -> Result<(TermArg, usize), AmlInternalError> { +fn parse_def_deref_of(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + parser_opcode!(data, 0x83); - let (obj_reference, obj_reference_len) = parse_term_arg(&data[1..])?; - Ok((obj_reference, obj_reference_len + 1)) + let obj = parse_term_arg(&data[1..], ctx)?; + let res = ctx.get(obj.val)?; + + match res { + AmlValue::None => Err(AmlError::AmlValueError), + _ => Ok(AmlParseType { + val: res, + len: 1 + obj.len + }) + } } -fn parse_def_acquire(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { +fn parse_def_acquire(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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)) + let obj = parse_super_name(&data[1..], ctx)?; + let timeout = (data[2 + obj.len] as u16) + ((data[3 + obj.len] as u16) << 8); + + let (seconds, nanoseconds) = monotonic(); + let starting_time_ns = nanoseconds + (seconds * 1000000000); + + loop { + match ctx.acquire_mutex(obj.val.clone()) { + Err(e) => return Err(e), + Ok(b) => if b { + return Ok(AmlParseType { + val: AmlValue::Integer(0), + len: 4 + obj.len + }); + } else if timeout == 0xFFFF { + // TODO: Brief sleep here + } else { + let (seconds, nanoseconds) = monotonic(); + let current_time_ns = nanoseconds + (seconds * 1000000000); + + if current_time_ns - starting_time_ns > timeout as u64 * 1000000 { + return Ok(AmlParseType { + val: AmlValue::Integer(1), + len: 4 + obj.len + }); + } + } + } + } } -fn parse_def_increment(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { +fn parse_def_increment(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + parser_opcode!(data, 0x75); - let (obj, obj_len) = parse_super_name(&data[1..])?; - Ok((Type2OpCode::DefIncrement(obj), obj_len + 1)) + let obj = parse_super_name(&data[1..], ctx)?; + + let mut namespace = ctx.prelock(); + let value = AmlValue::Integer(ctx.get(obj.val.clone())?.get_as_integer()? + 1); + ctx.modify(obj.val, value.clone()); + + Ok(AmlParseType { + val: value, + len: 1 + obj.len + }) } -fn parse_def_index(data: &[u8]) -> Result<(DefIndex, usize), AmlInternalError> { +fn parse_def_index(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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)) + let obj = parse_term_arg(&data[1..], ctx)?; + let idx = parse_term_arg(&data[1 + obj.len..], ctx)?; + let target = parse_target(&data[1 + obj.len + idx.len..], ctx)?; + + let reference = AmlValue::ObjectReference(ObjectReference::Index(Box::new(obj.val), Box::new(idx.val))); + ctx.modify(target.val, reference.clone()); + + Ok(AmlParseType { + val: reference, + len: 1 + obj.len + idx.len + target.len + }) } -fn parse_def_land(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { +fn parse_def_land(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + parser_opcode!(data, 0x90); - let (lhs, lhs_len) = parse_term_arg(&data[1..])?; - let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - Ok((Type2OpCode::DefLAnd {lhs, rhs}, 1 + lhs_len + rhs_len)) + let result = if lhs.val.get_as_integer()? > 0 && rhs.val.get_as_integer()? > 0 { 1 } else { 0 }; + + Ok(AmlParseType { + val: AmlValue::IntegerConstant(result), + len: 1 + lhs.len + rhs.len + }) } -fn parse_def_lequal(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { +fn parse_def_lequal(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + parser_opcode!(data, 0x93); - let (lhs, lhs_len) = parse_term_arg(&data[1..])?; - let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - Ok((Type2OpCode::DefLEqual {lhs, rhs}, 1 + lhs_len + rhs_len)) + let result = if lhs.val.get_as_integer()? == rhs.val.get_as_integer()? { 1 } else { 0 }; + + Ok(AmlParseType { + val: AmlValue::IntegerConstant(result), + len: 1 + lhs.len + rhs.len + }) } -fn parse_def_lgreater(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { +fn parse_def_lgreater(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + parser_opcode!(data, 0x94); - let (lhs, lhs_len) = parse_term_arg(&data[1..])?; - let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - Ok((Type2OpCode::DefLGreater {lhs, rhs}, 1 + lhs_len + rhs_len)) + let result = if lhs.val.get_as_integer()? > rhs.val.get_as_integer()? { 1 } else { 0 }; + + Ok(AmlParseType { + val: AmlValue::IntegerConstant(result), + len: 1 + lhs.len + rhs.len + }) } -fn parse_def_lless(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { +fn parse_def_lless(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + parser_opcode!(data, 0x95); - let (lhs, lhs_len) = parse_term_arg(&data[1..])?; - let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - Ok((Type2OpCode::DefLLess {lhs, rhs}, 1 + lhs_len + rhs_len)) + let result = if lhs.val.get_as_integer()? < rhs.val.get_as_integer()? { 1 } else { 0 }; + + Ok(AmlParseType { + val: AmlValue::IntegerConstant(result), + len: 1 + lhs.len + rhs.len + }) } -fn parse_def_lnot(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { +fn parse_def_lnot(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + parser_opcode!(data, 0x92); - let (operand, operand_len) = parse_term_arg(&data[1..])?; - - Ok((Type2OpCode::DefLNot(operand), 1 + operand_len)) + let operand = parse_term_arg(&data[1..], ctx)?; + let result = if operand.val.get_as_integer()? == 0 { 1 } else { 0 }; + + Ok(AmlParseType { + val: AmlValue::IntegerConstant(result), + len: 1 + operand.len + }) } -fn parse_def_lor(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { +fn parse_def_lor(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + parser_opcode!(data, 0x91); - let (lhs, lhs_len) = parse_term_arg(&data[1..])?; - let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - Ok((Type2OpCode::DefLOr {lhs, rhs}, 1 + lhs_len + rhs_len)) + let result = if lhs.val.get_as_integer()? > 0 || rhs.val.get_as_integer()? > 0 { 1 } else { 0 }; + + Ok(AmlParseType { + val: AmlValue::IntegerConstant(result), + len: 1 + lhs.len + rhs.len + }) } -fn parse_def_to_hex_string(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { +fn parse_def_to_hex_string(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + parser_opcode!(data, 0x98); - let (operand, operand_len) = parse_term_arg(&data[1..])?; - let (target, target_len) = parse_target(&data[1 + operand_len..])?; + let operand = parse_term_arg(&data[2..], ctx)?; + let target = parse_target(&data[2 + operand.len..], ctx)?; + + let res = match operand.val { + AmlValue::Integer(_) => { + let result: String = format!("{:X}", operand.val.get_as_integer()?); + AmlValue::String(result) + }, + AmlValue::String(s) => AmlValue::String(s), + AmlValue::Buffer(_) => { + let mut string: String = String::new(); + + for b in operand.val.get_as_buffer()? { + string.push_str(&format!("{:X}", b)); + } + + AmlValue::String(string) + }, + _ => return Err(AmlError::AmlValueError) + }; + + ctx.modify(target.val, res.clone()); - Ok((Type2OpCode::DefToHexString {operand, target}, 1 + operand_len + target_len)) + Ok(AmlParseType { + val: res, + len: 1 + operand.len + target.len + }) } -fn parse_def_to_buffer(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { +fn parse_def_to_buffer(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + parser_opcode!(data, 0x96); - let (operand, operand_len) = parse_term_arg(&data[1..])?; - let (target, target_len) = parse_target(&data[1 + operand_len..])?; + let operand = parse_term_arg(&data[2..], ctx)?; + let target = parse_target(&data[2 + operand.len..], ctx)?; - Ok((Type2OpCode::DefToBuffer {operand, target}, 1 + operand_len + target_len)) + let res = AmlValue::Buffer(operand.val.get_as_buffer()?); + ctx.modify(target.val, res.clone()); + + Ok(AmlParseType { + val: res, + len: 1 + operand.len + target.len + }) } -fn parse_def_to_bcd(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { +fn parse_def_to_bcd(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + parser_opcode_extended!(data, 0x29); - let (operand, operand_len) = parse_term_arg(&data[2..])?; - let (target, target_len) = parse_target(&data[2 + operand_len..])?; + let operand = parse_term_arg(&data[2..], ctx)?; + let target = parse_target(&data[2 + operand.len..], ctx)?; + + let mut i = operand.val.get_as_integer()?; + let mut result = 0; - Ok((Type2OpCode::DefToBCD {operand, target}, 2 + operand_len + target_len)) + while i != 0 { + result <<= 4; + result += i % 10; + i /= 10; + } + + let result = AmlValue::Integer(result); + ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 1 + operand.len + target.len + }) } -fn parse_def_to_decimal_string(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { +fn parse_def_to_decimal_string(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + parser_opcode!(data, 0x97); - let (operand, operand_len) = parse_term_arg(&data[1..])?; - let (target, target_len) = parse_target(&data[1 + operand_len..])?; + let operand = parse_term_arg(&data[2..], ctx)?; + let target = parse_target(&data[2 + operand.len..], ctx)?; + let res = match operand.val { + AmlValue::Integer(_) => { + let result: String = format!("{}", operand.val.get_as_integer()?); + AmlValue::String(result) + }, + AmlValue::String(s) => AmlValue::String(s), + AmlValue::Buffer(_) => { + let mut string: String = String::new(); + + for b in operand.val.get_as_buffer()? { + string.push_str(&format!("{}", b)); + } + + AmlValue::String(string) + }, + _ => return Err(AmlError::AmlValueError) + }; - Ok((Type2OpCode::DefToDecimalString {operand, target}, 1 + operand_len + target_len)) + ctx.modify(target.val, res.clone()); + + Ok(AmlParseType { + val: res, + len: 1 + operand.len + target.len + }) } -fn parse_def_to_integer(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { +fn parse_def_to_integer(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + parser_opcode!(data, 0x99); - let (operand, operand_len) = parse_term_arg(&data[1..])?; - let (target, target_len) = parse_target(&data[1 + operand_len..])?; + let operand = parse_term_arg(&data[2..], ctx)?; + let target = parse_target(&data[2 + operand.len..], ctx)?; - Ok((Type2OpCode::DefToInteger {operand, target}, 1 + operand_len + target_len)) + let res = AmlValue::Integer(operand.val.get_as_integer()?); + + ctx.modify(target.val, res.clone()); + + Ok(AmlParseType { + val: res, + len: 1 + operand.len + target.len + }) } -fn parse_def_to_string(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { +fn parse_def_to_string(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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..])?; + let operand = parse_term_arg(&data[1..], ctx)?; + let length = parse_term_arg(&data[1 + operand.len..], ctx)?; + let target = parse_target(&data[1 + operand.len + length.len..], ctx)?; + + let buf = operand.val.get_as_buffer()?; + let mut string = match String::from_utf8(buf) { + Ok(s) => s, + Err(_) => return Err(AmlError::AmlValueError) + }; - Ok((Type2OpCode::DefToString {operand, length, target}, 1 + operand_len + length_len + target_len)) + string.truncate(length.val.get_as_integer()? as usize); + let res = AmlValue::String(string); + + ctx.modify(target.val, res.clone()); + + Ok(AmlParseType { + val: res, + len: 1 + operand.len + length.len + target.len + }) } -fn parse_def_subtract(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { +fn parse_def_subtract(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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..])?; + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - Ok((Type2OpCode::DefSubtract {minuend, subtrahend, target}, 1 + minuend_len + subtrahend_len + target_len)) + let result = AmlValue::Integer(lhs.val.get_as_integer()? - rhs.val.get_as_integer()?); + + ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 1 + lhs.len + rhs.len + target.len + }) } -fn parse_def_size_of(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { +fn parse_def_size_of(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + parser_opcode!(data, 0x87); - let (name, name_len) = parse_super_name(&data[1..])?; - Ok((Type2OpCode::DefSizeOf(name), name_len + 1)) + let name = parse_super_name(&data[1..], ctx)?; + let obj = ctx.get(name.val)?; + + let res = match obj { + AmlValue::Buffer(ref v) => v.len(), + AmlValue::String(ref s) => s.len(), + AmlValue::Package(ref p) => p.len(), + _ => return Err(AmlError::AmlValueError) + }; + + Ok(AmlParseType { + val: AmlValue::Integer(res as u64), + len: 1 + name.len + }) } -fn parse_def_store(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { +fn parse_def_store(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + parser_opcode!(data, 0x70); - let (operand, operand_len) = parse_term_arg(&data[1..])?; - let (target, target_len) = parse_super_name(&data[1 + operand_len..])?; + let operand = parse_term_arg(&data[1..], ctx)?; + let target = parse_super_name(&data[1 + operand.len..], ctx)?; - Ok((Type2OpCode::DefStore {operand, target}, operand_len + target_len + 1)) + ctx.modify(target.val.clone(), operand.val); + + Ok(AmlParseType { + val: target.val, + len: 1 + operand.len + target.len + }) } -fn parse_def_or(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { +fn parse_def_or(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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)) + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; + + let result = AmlValue::Integer(lhs.val.get_as_integer()? | rhs.val.get_as_integer()?); + + ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 1 + lhs.len + rhs.len + target.len + }) } -fn parse_def_shift_left(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { +fn parse_def_shift_left(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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)) + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; + + let result = AmlValue::Integer(lhs.val.get_as_integer()? >> rhs.val.get_as_integer()?); + + ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 1 + lhs.len + rhs.len + target.len + }) } -fn parse_def_shift_right(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { +fn parse_def_shift_right(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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..])?; + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; + + let result = AmlValue::Integer(lhs.val.get_as_integer()? << rhs.val.get_as_integer()?); - Ok((Type2OpCode::DefShiftRight {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) + ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 1 + lhs.len + rhs.len + target.len + }) } -fn parse_def_add(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { +fn parse_def_add(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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)) + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; + + let result = AmlValue::Integer(lhs.val.get_as_integer()? + rhs.val.get_as_integer()?); + + ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 1 + lhs.len + rhs.len + target.len + }) } -fn parse_def_and(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { +fn parse_def_and(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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)) + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; + + let result = AmlValue::Integer(lhs.val.get_as_integer()? & rhs.val.get_as_integer()?); + + ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 1 + lhs.len + rhs.len + target.len + }) } -fn parse_def_xor(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { +fn parse_def_xor(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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)) + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; + + let result = AmlValue::Integer(lhs.val.get_as_integer()? ^ rhs.val.get_as_integer()?); + + ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 1 + lhs.len + rhs.len + target.len + }) } -fn parse_def_concat_res(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { +fn parse_def_concat_res(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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..])?; + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - Ok((Type2OpCode::DefConcatRes {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) -} + let mut buf1 = lhs.val.get_as_buffer()?.clone(); + let mut buf2 = rhs.val.get_as_buffer()?.clone(); -fn parse_def_wait(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { - parser_opcode_extended!(data, 0x25); + if buf1.len() == 1 || buf2.len() == 1 { + return Err(AmlError::AmlValueError); + } + + if buf1.len() >= 2 && buf1[buf1.len() - 2] == 0x79 { + buf1 = buf1[0..buf1.len() - 2].to_vec(); + } + + if buf2.len() >= 2 && buf2[buf2.len() - 2] == 0x79 { + buf2 = buf2[0..buf2.len() - 2].to_vec(); + } - let (event_object, event_object_len) = parse_super_name(&data[2..])?; - let (operand, operand_len) = parse_term_arg(&data[2 + event_object_len..])?; + buf1.append(&mut buf2); + buf1.push(0x79); + let mut checksum: u8 = 0; + let loopbuf = buf1.clone(); + for b in loopbuf { + checksum += b; + } - Ok((Type2OpCode::DefWait {event_object, operand}, 2 + event_object_len + operand_len)) + checksum = (!checksum) + 1; + buf1.push(checksum); + + let res = AmlValue::Buffer(buf1); + ctx.modify(target.val, res.clone())?; + + Ok(AmlParseType { + val: res, + len: 1 + lhs.len + rhs.len + target.len + }) } -fn parse_def_cond_ref_of(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { +fn parse_def_wait(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + + parser_opcode_extended!(data, 0x25); + + let obj = parse_super_name(&data[2..], ctx)?; + let timeout_obj = parse_term_arg(&data[2 + obj.len..], ctx)?; + + let timeout = timeout_obj.val.get_as_integer()?; + + let (seconds, nanoseconds) = monotonic(); + let starting_time_ns = nanoseconds + (seconds * 1000000000); + + loop { + match ctx.wait_for_event(obj.val.clone()) { + Err(e) => return Err(e), + Ok(b) => if b { + return Ok(AmlParseType { + val: AmlValue::Integer(0), + len: 2 + obj.len + timeout_obj.len + }) + } else if timeout >= 0xFFFF { + // TODO: Brief sleep here + } else { + let (seconds, nanoseconds) = monotonic(); + let current_time_ns = nanoseconds + (seconds * 1000000000); + + if current_time_ns - starting_time_ns > timeout as u64 * 1000000 { + return Ok(AmlParseType { + val: AmlValue::Integer(1), + len: 2 + obj.len + timeout_obj.len + }); + } + } + } + } +} + +fn parse_def_cond_ref_of(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + parser_opcode_extended!(data, 0x12); - let (operand, operand_len) = parse_super_name(&data[2..])?; - let (target, target_len) = parse_target(&data[2 + operand_len..])?; + let obj = parse_super_name(&data[2..], ctx)?; + let target = parse_target(&data[2 + obj.len..], ctx)?; + + let res = match obj.val { + AmlValue::String(ref s) => { + match ctx.get(AmlValue::String(s.clone()))? { + AmlValue::None => return Ok(AmlParseType { + val: AmlValue::Integer(0), + len: 1 + obj.len + target.len + }), + _ => ObjectReference::Object(s.clone()) + } + }, + AmlValue::ObjectReference(ref o) => o.clone(), + _ => return Err(AmlError::AmlValueError) + }; - Ok((Type2OpCode::DefCondRefOf {operand, target}, 2 + operand_len + target_len)) + ctx.modify(target.val, AmlValue::ObjectReference(res)); + + Ok(AmlParseType { + val: AmlValue::Integer(1), + len: 1 + obj.len + target.len + }) } -fn parse_def_copy_object(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { +fn parse_def_copy_object(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + + // TODO: Compute the result + // TODO: Store the result parser_opcode!(data, 0x9D); - let (source, source_len) = parse_term_arg(&data[1..])?; - let (destination, destination_len) = parse_simple_name(&data[1 + source_len..])?; + let source = parse_term_arg(&data[1..], ctx)?; + let destination = parse_simple_name(&data[1 + source.len..], ctx)?; + + ctx.copy(destination.val, source.val.clone())?; - Ok((Type2OpCode::DefCopyObject {source, destination}, 1 + source_len + destination_len)) + Ok(AmlParseType { + val: source.val, + len: 1 + source.len + destination.len + }) } -fn parse_def_concat(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { +fn parse_def_concat(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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..])?; + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; + + let result = match lhs.val { + AmlValue::Integer(i) => { + let j = AmlValue::Integer(rhs.val.get_as_integer()?); + + let mut first = lhs.val.get_as_buffer()?.clone(); + let mut second = j.get_as_buffer()?.clone(); + + first.append(&mut second); + + AmlValue::Buffer(first) + }, + AmlValue::String(s) => { + let t = if let Ok(t) = rhs.val.get_as_string() { + t + } else { + rhs.val.get_type_string() + }; + + AmlValue::String(format!("{}{}", s, t)) + }, + AmlValue::Buffer(b) => { + let mut b = b.clone(); + let mut c = if let Ok(c) = rhs.val.get_as_buffer() { + c.clone() + } else { + AmlValue::String(rhs.val.get_type_string()).get_as_buffer()?.clone() + }; + + b.append(&mut c); + + AmlValue::Buffer(b) + }, + _ => { + let first = lhs.val.get_type_string(); + let second = if let Ok(second) = rhs.val.get_as_string() { + second + } else { + rhs.val.get_type_string() + }; + + AmlValue::String(format!("{}{}", first, second)) + } + }; + + ctx.modify(target.val, result.clone())?; - Ok((Type2OpCode::DefConcat {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) + Ok(AmlParseType { + val: result, + len: 1 + lhs.len + rhs.len + target.len + }) } -fn parse_def_decrement(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { +fn parse_def_decrement(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + parser_opcode!(data, 0x76); - let (target, target_len) = parse_super_name(&data[1..])?; - - Ok((Type2OpCode::DefDecrement(target), 1 + target_len)) + let obj = parse_super_name(&data[1..], ctx)?; + + let mut namespace = ctx.prelock(); + let value = AmlValue::Integer(ctx.get(obj.val.clone())?.get_as_integer()? - 1); + ctx.modify(obj.val, value.clone()); + + Ok(AmlParseType { + val: value, + len: 1 + obj.len + }) } -fn parse_def_divide(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { +fn parse_def_divide(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + 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..])?; + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + let target_remainder = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; + let target_quotient = parse_target(&data[1 + lhs.len + rhs.len + target_remainder.len..], ctx)?; + + let numerator = lhs.val.get_as_integer()?; + let denominator = rhs.val.get_as_integer()?; + + let remainder = numerator % denominator; + let quotient = (numerator - remainder) / denominator; - Ok((Type2OpCode::DefDivide {dividend, divisor, remainder, quotient}, - 1 + dividend_len + divisor_len + remainder_len + quotient_len)) + ctx.modify(target_remainder.val, AmlValue::Integer(remainder)); + ctx.modify(target_quotient.val, AmlValue::Integer(quotient)); + + Ok(AmlParseType { + val: AmlValue::Integer(quotient), + len: 1 + lhs.len + rhs.len + target_remainder.len + target_quotient.len + }) } -fn parse_def_find_set_left_bit(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { +fn parse_def_find_set_left_bit(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + parser_opcode!(data, 0x81); - let (operand, operand_len) = parse_term_arg(&data[1..])?; - let (target, target_len) = parse_target(&data[1 + operand_len..])?; + let operand = parse_term_arg(&data[2..], ctx)?; + let target = parse_target(&data[2 + operand.len..], ctx)?; - Ok((Type2OpCode::DefFindSetLeftBit {operand, target}, 1 + operand_len + target_len)) -} + let mut first_bit = 32; + let mut test = operand.val.get_as_integer()?; + + while first_bit > 0{ + if test & 0x8000000000000000 > 0 { + break; + } -fn parse_def_find_set_right_bit(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { - if data[0] != 0x82 { - return Err(AmlInternalError::AmlInvalidOpCode); + test <<= 1; + first_bit -= 1; } - 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)) + let result = AmlValue::Integer(first_bit); + ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 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); +fn parse_def_find_set_right_bit(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) } + + parser_opcode!(data, 0x82); + + let operand = parse_term_arg(&data[2..], ctx)?; + let target = parse_target(&data[2 + operand.len..], ctx)?; + + let mut first_bit = 1; + let mut test = operand.val.get_as_integer()?; + + while first_bit <= 32 { + if test & 1 > 0 { + break; + } - 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..])?; + test >>= 1; + first_bit += 1; + } - 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)) + if first_bit == 33 { + first_bit = 0; + } + + let result = AmlValue::Integer(first_bit); + ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 1 + operand.len + target.len + }) } -fn parse_def_match(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { - if data[0] != 0x89 { - return Err(AmlInternalError::AmlInvalidOpCode); +fn parse_def_load_table(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + + // TODO: Clean up + parser_opcode_extended!(data, 0x1F); + + let signature = parse_term_arg(&data[2..], ctx)?; + let oem_id = parse_term_arg(&data[2 + signature.len..], ctx)?; + let oem_table_id = parse_term_arg(&data[2 + signature.len + oem_id.len..], ctx)?; + let root_path = parse_term_arg(&data[2 + signature.len + oem_id.len + oem_table_id.len..], ctx)?; + let parameter_path = parse_term_arg(&data[2 + signature.len + oem_id.len + oem_table_id.len + root_path.len..], ctx)?; + let parameter_data = parse_term_arg(&data[2 + signature.len + oem_id.len + oem_table_id.len + root_path.len + parameter_path.len..], ctx)?; + + if let Some(ref ptrs) = *(SDT_POINTERS.read()) { + let sig_str = unsafe { + let sig = *(signature.val.get_as_string()?.as_bytes().as_ptr() as *const [u8; 4]); + String::from_utf8(sig.to_vec()).expect("Error converting signature to string") + }; + let oem_str = unsafe { + *(oem_id.val.get_as_string()?.as_bytes().as_ptr() as *const [u8; 6]) + }; + let oem_table_str = unsafe { + *(oem_table_id.val.get_as_string()?.as_bytes().as_ptr() as *const [u8; 8]) + }; + + let sdt_signature = (sig_str, oem_str, oem_table_str); + + let sdt = ptrs.get(&sdt_signature); + + if let Some(sdt) = sdt { + let hdl = parse_aml_with_scope(sdt, root_path.val.get_as_string()?)?; + ctx.modify(parameter_path.val, parameter_data.val); + + return Ok(AmlParseType { + val: AmlValue::DDBHandle((hdl, sdt_signature)), + len: 2 + signature.len + oem_id.len + oem_table_id.len + root_path.len + parameter_path.len + parameter_data.len + }); + } } - let (search_pkg, search_pkg_len) = parse_term_arg(&data[1..])?; - let first_operation = match data[1 + search_pkg_len] { + Ok(AmlParseType { + val: AmlValue::IntegerConstant(0), + len: 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], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + + parser_opcode!(data, 0x28); + + let search_pkg = parse_term_arg(&data[1..], ctx)?; + + 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")) + _ => return Err(AmlError::AmlParseError("DefMatch - Invalid Opcode")) }; - let (first_operand, first_operand_len) = parse_term_arg(&data[2 + search_pkg_len..])?; + let first_operand = parse_term_arg(&data[2 + search_pkg.len..], ctx)?; - let second_operation = match data[2 + search_pkg_len + first_operand_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")) + _ => return Err(AmlError::AmlParseError("DefMatch - Invalid Opcode")) }; - let (second_operand, second_operand_len) = - parse_term_arg(&data[3 + search_pkg_len + first_operand_len..])?; + let second_operand = parse_term_arg(&data[3 + search_pkg.len + first_operand.len..], ctx)?; + + let start_index = parse_term_arg(&data[3 + search_pkg.len + first_operand.len + second_operand.len..], ctx)?; + + let pkg = search_pkg.val.get_as_package()?; + let mut idx = start_index.val.get_as_integer()? as usize; + + match first_operand.val { + AmlValue::Integer(i) => { + let j = second_operand.val.get_as_integer()?; + + while idx < pkg.len() { + let val = if let Ok(v) = pkg[idx].get_as_integer() { v } else { idx += 1; continue; }; + idx += 1; + + match first_operation { + MatchOpcode::MTR => (), + MatchOpcode::MEQ => if val != i { continue }, + MatchOpcode::MLE => if val > i { continue }, + MatchOpcode::MLT => if val >= i { continue }, + MatchOpcode::MGE => if val < i { continue }, + MatchOpcode::MGT => if val <= i { continue } + } + + match second_operation { + MatchOpcode::MTR => (), + MatchOpcode::MEQ => if val != j { continue }, + MatchOpcode::MLE => if val > j { continue }, + MatchOpcode::MLT => if val >= j { continue }, + MatchOpcode::MGE => if val < j { continue }, + MatchOpcode::MGT => if val <= j { continue } + } + + return Ok(AmlParseType { + val: AmlValue::Integer(idx as u64), + len: 3 + search_pkg.len + first_operand.len + second_operand.len + start_index.len + }) + } + }, + AmlValue::String(i) => { + let j = second_operand.val.get_as_string()?; + + while idx < pkg.len() { + let val = if let Ok(v) = pkg[idx].get_as_string() { v } else { idx += 1; continue; }; + idx += 1; + + match first_operation { + MatchOpcode::MTR => (), + MatchOpcode::MEQ => if val != i { continue }, + MatchOpcode::MLE => if val > i { continue }, + MatchOpcode::MLT => if val >= i { continue }, + MatchOpcode::MGE => if val < i { continue }, + MatchOpcode::MGT => if val <= i { continue } + } + + match second_operation { + MatchOpcode::MTR => (), + MatchOpcode::MEQ => if val != j { continue }, + MatchOpcode::MLE => if val > j { continue }, + MatchOpcode::MLT => if val >= j { continue }, + MatchOpcode::MGE => if val < j { continue }, + MatchOpcode::MGT => if val <= j { continue } + } + + return Ok(AmlParseType { + val: AmlValue::Integer(idx as u64), + len: 3 + search_pkg.len + first_operand.len + second_operand.len + start_index.len + }) + } + }, + _ => { + let i = first_operand.val.get_as_buffer()?; + let j = second_operand.val.get_as_buffer()?; + + while idx < pkg.len() { + let val = if let Ok(v) = pkg[idx].get_as_buffer() { v } else { idx += 1; continue; }; + idx += 1; + + match first_operation { + MatchOpcode::MTR => (), + MatchOpcode::MEQ => if val != i { continue }, + MatchOpcode::MLE => if val > i { continue }, + MatchOpcode::MLT => if val >= i { continue }, + MatchOpcode::MGE => if val < i { continue }, + MatchOpcode::MGT => if val <= i { continue } + } + + match second_operation { + MatchOpcode::MTR => (), + MatchOpcode::MEQ => if val != j { continue }, + MatchOpcode::MLE => if val > j { continue }, + MatchOpcode::MLT => if val >= j { continue }, + MatchOpcode::MGE => if val < j { continue }, + MatchOpcode::MGT => if val <= j { continue } + } - let (start_index, start_index_len) = - parse_term_arg(&data[3 + search_pkg_len + first_operand_len + second_operand_len..])?; + return Ok(AmlParseType { + val: AmlValue::Integer(idx as u64), + len: 3 + search_pkg.len + first_operand.len + second_operand.len + start_index.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)) + Ok(AmlParseType { + val: AmlValue::IntegerConstant(0xFFFFFFFFFFFFFFFF), + len: 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); +fn parse_def_from_bcd(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) } + + parser_opcode_extended!(data, 0x28); - let (operand, operand_len) = parse_term_arg(&data[2..])?; - let (target, target_len) = parse_target(&data[2 + operand_len..])?; + let operand = parse_term_arg(&data[2..], ctx)?; + let target = parse_target(&data[2 + operand.len..], ctx)?; - Ok((Type2OpCode::DefFromBCD {operand, target}, 2 + operand_len + target_len)) -} + let mut i = operand.val.get_as_integer()?; + let mut result = 0; -fn parse_def_mid(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { - if data[0] != 0x9E { - return Err(AmlInternalError::AmlInvalidOpCode); + while i != 0 { + if i & 0x0F > 10 { + return Err(AmlError::AmlValueError); + } + + result *= 10; + result += i & 0x0F; + i >>= 4; } - 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..])?; + let result = AmlValue::Integer(result); - Ok((Type2OpCode::DefMid {source, index, length, target}, - 1 + source_len + index_len + length_len + target_len)) + ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 2 + operand.len + target.len + }) } -fn parse_def_mod(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { - if data[0] != 0x85 { - return Err(AmlInternalError::AmlInvalidOpCode); +fn parse_def_mid(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) } + + parser_opcode!(data, 0x9E); + + let source = parse_term_arg(&data[1..], ctx)?; + let index = parse_term_arg(&data[1 + source.len..], ctx)?; + let length = parse_term_arg(&data[1 + source.len + index.len..], ctx)?; + let target = parse_target(&data[1 + source.len + index.len + length.len..], ctx)?; + + let idx = index.val.get_as_integer()? as usize; + let mut len = length.val.get_as_integer()? as usize; + + let result = match source.val { + AmlValue::String(s) => { + if idx > s.len() { + AmlValue::String(String::new()) + } else { + let mut res = s.clone().split_off(idx); + + if len < res.len() { + res.split_off(len); + } - 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..])?; + AmlValue::String(res) + } + }, + _ => { + // If it isn't a string already, treat it as a buffer. Must perform that check first, + // as Mid can operate on both strings and buffers, but a string can be cast as a buffer + // implicitly. + // Additionally, any type that can be converted to a buffer can also be converted to a + // string, so no information is lost + let b = source.val.get_as_buffer()?; + + if idx > b.len() { + AmlValue::Buffer(vec!()) + } else { + if idx + len > b.len() { + len = b.len() - idx; + } + + AmlValue::Buffer(b[idx .. idx + len].to_vec()) + } + } + }; + + ctx.modify(target.val, result.clone()); - Ok((Type2OpCode::DefMod {dividend, divisor, target}, 1 + dividend_len + divisor_len + target_len)) + Ok(AmlParseType { + val: result, + len: 1 + source.len + index.len + length.len + target.len + }) } -fn parse_def_multiply(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { - if data[0] != 0x77 { - return Err(AmlInternalError::AmlInvalidOpCode); +fn parse_def_mod(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + + parser_opcode!(data, 0x85); + + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; + + if rhs.val.get_as_integer()? == 0 { + return Err(AmlError::AmlValueError); } - 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..])?; + let result = AmlValue::Integer(lhs.val.get_as_integer()? % rhs.val.get_as_integer()?); - Ok((Type2OpCode::DefMultiply {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) + ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 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); +fn parse_def_multiply(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) } + + // TODO: Handle overflow + parser_opcode!(data, 0x77); + + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; + + let result = AmlValue::Integer(lhs.val.get_as_integer()? * rhs.val.get_as_integer()?); + + ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 1 + lhs.len + rhs.len + target.len + }) +} - 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..])?; +fn parse_def_nand(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) + } + + parser_opcode!(data, 0x7C); - Ok((Type2OpCode::DefNAnd {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; + + let result = AmlValue::Integer(!(lhs.val.get_as_integer()? & rhs.val.get_as_integer()?)); + + ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 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); +fn parse_def_nor(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) } + + parser_opcode!(data, 0x7E); + + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - 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..])?; + let result = AmlValue::Integer(!(lhs.val.get_as_integer()? | rhs.val.get_as_integer()?)); - Ok((Type2OpCode::DefNOr {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) + ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 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); +fn parse_def_not(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) } + + parser_opcode!(data, 0x80); - let (operand, operand_len) = parse_term_arg(&data[1..])?; - let (target, target_len) = parse_target(&data[1 + operand_len..])?; + let operand = parse_term_arg(&data[1..], ctx)?; + let target = parse_target(&data[1 + operand.len..], ctx)?; - Ok((Type2OpCode::DefNot {operand, target}, 1 + operand_len + target_len)) + let result = AmlValue::Integer(!operand.val.get_as_integer()?); + + ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 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) +fn parse_def_timer(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 as usize + }) } - - Ok((Type2OpCode::DefTimer, 2 as usize)) + + parser_opcode_extended!(data, 0x33); + + let (seconds, nanoseconds) = monotonic(); + let monotonic_ns = nanoseconds + (seconds * 1000000000); + + Ok(AmlParseType { + val: AmlValue::Integer(monotonic_ns), + len: 2 as usize + }) } diff --git a/src/acpi/dmar/mod.rs b/src/acpi/dmar/mod.rs index 02aac83d5b59ba18b84a7738ed967c15cb47d7a4..549f6869eab707c8993a7221ab38d0b7fddc9fee 100644 --- a/src/acpi/dmar/mod.rs +++ b/src/acpi/dmar/mod.rs @@ -5,6 +5,8 @@ use self::drhd::Drhd; use memory::Frame; use paging::{entry, ActivePageTable, PhysicalAddress}; +use super::{ACPI_TABLE, SDT_POINTERS, get_sdt, find_sdt, load_table, get_sdt_signature}; + pub mod drhd; /// The DMA Remapping Table @@ -17,6 +19,38 @@ pub struct Dmar { } impl Dmar { + pub fn init(active_table: &mut ActivePageTable) { + let dmar_sdt = find_sdt("DMAR"); + let dmar = if dmar_sdt.len() == 1 { + load_table(get_sdt_signature(dmar_sdt[0])); + Dmar::new(dmar_sdt[0]) + } else { + println!("Unable to find DMAR"); + return; + }; + + if let Some(dmar) = dmar { + println!(" DMAR: {}: {}", dmar.addr_width, dmar.flags); + + for dmar_entry in dmar.iter() { + println!(" {:?}", dmar_entry); + match dmar_entry { + DmarEntry::Drhd(dmar_drhd) => { + let drhd = dmar_drhd.get(active_table); + + println!("VER: {:X}", drhd.version); + println!("CAP: {:X}", drhd.cap); + println!("EXT_CAP: {:X}", drhd.ext_cap); + println!("GCMD: {:X}", drhd.gl_cmd); + println!("GSTS: {:X}", drhd.gl_sts); + println!("RT: {:X}", drhd.root_table); + }, + _ => () + } + } + } + } + pub fn new(sdt: &'static Sdt) -> Option<Dmar> { if &sdt.signature == b"DMAR" && sdt.data_len() >= 12 { //Not valid if no local address and flags let addr_width = unsafe { *(sdt.data_address() as *const u8) }; diff --git a/src/acpi/fadt.rs b/src/acpi/fadt.rs index d40d5a1fc520906a83417c72f73818a7d5f72066..6dd82d867c3bee41e647900226992d2d09a7547e 100644 --- a/src/acpi/fadt.rs +++ b/src/acpi/fadt.rs @@ -1,6 +1,10 @@ use core::{mem, ptr}; +use collections::string::String; use super::sdt::Sdt; +use super::{ACPI_TABLE, SDT_POINTERS, get_sdt, find_sdt, get_sdt_signature, load_table}; + +use paging::ActivePageTable; #[repr(packed)] #[derive(Debug)] @@ -93,4 +97,29 @@ impl Fadt { None } } + + pub fn init(active_table: &mut ActivePageTable) { + let fadt_sdt = find_sdt("FACP"); + let fadt = if fadt_sdt.len() == 1 { + load_table(get_sdt_signature(fadt_sdt[0])); + Fadt::new(fadt_sdt[0]) + } else { + println!("Unable to find FADT"); + return; + }; + + if let Some(fadt) = fadt { + println!(" FACP: {:X}", fadt.dsdt); + + let dsdt_sdt = get_sdt(fadt.dsdt as usize, active_table); + + let signature = get_sdt_signature(dsdt_sdt); + if let Some(ref mut ptrs) = *(SDT_POINTERS.write()) { + ptrs.insert(signature, dsdt_sdt); + } + + let mut fadt_t = ACPI_TABLE.fadt.write(); + *fadt_t = Some(fadt); + } + } } diff --git a/src/acpi/hpet.rs b/src/acpi/hpet.rs index 664b6bb8d69cd8b32a4ee0770ec4f1ef7fefed71..d2e5ecfbde2cc3d7a45ceba2581947a07f2cd07f 100644 --- a/src/acpi/hpet.rs +++ b/src/acpi/hpet.rs @@ -1,6 +1,12 @@ use core::{mem, ptr}; +use core::intrinsics::{volatile_load, volatile_store}; + +use memory::Frame; +use paging::{entry, ActivePageTable, PhysicalAddress, Page, VirtualAddress}; + use super::sdt::Sdt; +use super::{ACPI_TABLE, SDT_POINTERS, get_sdt, find_sdt, load_table, get_sdt_signature}; #[repr(packed)] #[derive(Clone, Copy, Debug, Default)] @@ -29,11 +35,48 @@ pub struct Hpet { } impl Hpet { - pub fn new(sdt: &'static Sdt) -> Option<Hpet> { + pub fn init(active_table: &mut ActivePageTable) { + let hpet_sdt = find_sdt("HPET"); + let hpet = if hpet_sdt.len() == 1 { + load_table(get_sdt_signature(hpet_sdt[0])); + Hpet::new(hpet_sdt[0], active_table) + } else { + println!("Unable to find HPET"); + return; + }; + + if let Some(hpet) = hpet { + println!(" HPET: {:X}", hpet.hpet_number); + + let mut hpet_t = ACPI_TABLE.hpet.write(); + *hpet_t = Some(hpet); + } + } + + pub fn new(sdt: &'static Sdt, active_table: &mut ActivePageTable) -> Option<Hpet> { if &sdt.signature == b"HPET" && sdt.length as usize >= mem::size_of::<Hpet>() { - Some(unsafe { ptr::read((sdt as *const Sdt) as *const Hpet) }) + let s = unsafe { ptr::read((sdt as *const Sdt) as *const Hpet) }; + unsafe { s.base_address.init(active_table) }; + Some(s) } else { None } } } + +impl GenericAddressStructure { + pub unsafe fn init(&self, active_table: &mut ActivePageTable) { + let page = Page::containing_address(VirtualAddress::new(self.address as usize)); + let frame = Frame::containing_address(PhysicalAddress::new(self.address as usize)); + let result = active_table.map_to(page, frame, entry::PRESENT | entry::WRITABLE | entry::NO_EXECUTE); + result.flush(active_table); + } + + pub unsafe fn read_u64(&self, offset: usize) -> u64{ + volatile_load((self.address as usize + offset) as *const u64) + } + + pub unsafe fn write_u64(&mut self, offset: usize, value: u64) { + volatile_store((self.address as usize + offset) as *mut u64, value); + } +} diff --git a/src/acpi/madt.rs b/src/acpi/madt.rs index dac16dc7faf66af5c7e0d9d8ce744d621f58f7f1..c4f922a5a12be83c21f8b05356c4840c02e2422e 100644 --- a/src/acpi/madt.rs +++ b/src/acpi/madt.rs @@ -1,6 +1,27 @@ use core::mem; +use memory::{allocate_frames, Frame}; +use paging::{entry, ActivePageTable, Page, PhysicalAddress, VirtualAddress}; + use super::sdt::Sdt; +use super::{ACPI_TABLE, SDT_POINTERS, AP_STARTUP, TRAMPOLINE, find_sdt, load_table, get_sdt_signature}; + +use core::intrinsics::{atomic_load, atomic_store}; +use core::sync::atomic::Ordering; +use collections::btree_map::BTreeMap; +use collections::string::String; +use collections::vec::Vec; +use alloc::boxed::Box; + +use syscall::io::{Io, Pio}; + +use spin::RwLock; + +use stop::kstop; + +use device::local_apic::LOCAL_APIC; +use interrupt; +use start::{kstart_ap, CPU_COUNT, AP_READY}; /// The Multiple APIC Descriptor Table #[derive(Debug)] @@ -11,6 +32,123 @@ pub struct Madt { } impl Madt { + pub fn init(active_table: &mut ActivePageTable) { + let madt_sdt = find_sdt("APIC"); + let madt = if madt_sdt.len() == 1 { + load_table(get_sdt_signature(madt_sdt[0])); + Madt::new(madt_sdt[0]) + } else { + println!("Unable to find MADT"); + return; + }; + + if let Some(madt) = madt { + println!(" APIC: {:>08X}: {}", madt.local_address, madt.flags); + + let local_apic = unsafe { &mut LOCAL_APIC }; + let me = local_apic.id() as u8; + + if local_apic.x2 { + println!(" X2APIC {}", me); + } else { + println!(" XAPIC {}: {:>08X}", me, local_apic.address); + } + + if cfg!(feature = "multi_core"){ + let trampoline_frame = Frame::containing_address(PhysicalAddress::new(TRAMPOLINE)); + let trampoline_page = Page::containing_address(VirtualAddress::new(TRAMPOLINE)); + + // Map trampoline + let result = active_table.map_to(trampoline_page, trampoline_frame, entry::PRESENT | entry::WRITABLE); + result.flush(active_table); + + for madt_entry in madt.iter() { + println!(" {:?}", madt_entry); + match madt_entry { + MadtEntry::LocalApic(ap_local_apic) => if ap_local_apic.id == me { + println!(" This is my local APIC"); + } else { + if ap_local_apic.flags & 1 == 1 { + // Increase CPU ID + CPU_COUNT.fetch_add(1, Ordering::SeqCst); + + // Allocate a stack + let stack_start = allocate_frames(64).expect("no more frames in acpi stack_start").start_address().get() + ::KERNEL_OFFSET; + let stack_end = stack_start + 64 * 4096; + + let ap_ready = TRAMPOLINE as *mut u64; + let ap_cpu_id = unsafe { ap_ready.offset(1) }; + let ap_page_table = unsafe { ap_ready.offset(2) }; + let ap_stack_start = unsafe { ap_ready.offset(3) }; + let ap_stack_end = unsafe { ap_ready.offset(4) }; + let ap_code = unsafe { ap_ready.offset(5) }; + + // Set the ap_ready to 0, volatile + unsafe { atomic_store(ap_ready, 0) }; + unsafe { atomic_store(ap_cpu_id, ap_local_apic.id as u64) }; + unsafe { atomic_store(ap_page_table, active_table.address() as u64) }; + unsafe { atomic_store(ap_stack_start, stack_start as u64) }; + unsafe { atomic_store(ap_stack_end, stack_end as u64) }; + unsafe { atomic_store(ap_code, kstart_ap as u64) }; + AP_READY.store(false, Ordering::SeqCst); + + print!(" AP {}:", ap_local_apic.id); + + // Send INIT IPI + { + let mut icr = 0x4500; + if local_apic.x2 { + icr |= (ap_local_apic.id as u64) << 32; + } else { + icr |= (ap_local_apic.id as u64) << 56; + } + print!(" IPI..."); + local_apic.set_icr(icr); + } + + // Send START IPI + { + //Start at 0x0800:0000 => 0x8000. Hopefully the bootloader code is still there + let ap_segment = (AP_STARTUP >> 12) & 0xFF; + let mut icr = 0x4600 | ap_segment as u64; + + if local_apic.x2 { + icr |= (ap_local_apic.id as u64) << 32; + } else { + icr |= (ap_local_apic.id as u64) << 56; + } + + print!(" SIPI..."); + local_apic.set_icr(icr); + } + + // Wait for trampoline ready + print!(" Wait..."); + while unsafe { atomic_load(ap_ready) } == 0 { + interrupt::pause(); + } + print!(" Trampoline..."); + while ! AP_READY.load(Ordering::SeqCst) { + interrupt::pause(); + } + println!(" Ready"); + + active_table.flush_all(); + } else { + println!(" CPU Disabled"); + } + }, + _ => () + } + } + + // Unmap trampoline + let (result, _frame) = active_table.unmap_return(trampoline_page, false); + result.flush(active_table); + } + } + } + pub fn new(sdt: &'static Sdt) -> Option<Madt> { if &sdt.signature == b"APIC" && sdt.data_len() >= 8 { //Not valid if no local address and flags let local_address = unsafe { *(sdt.data_address() as *const u32) }; diff --git a/src/acpi/mod.rs b/src/acpi/mod.rs index f2791169c6cbfee2c5158e071f1618538b2286fc..8324f8e03526bdef0a9be818097e28320caea9bd 100644 --- a/src/acpi/mod.rs +++ b/src/acpi/mod.rs @@ -3,8 +3,16 @@ use core::intrinsics::{atomic_load, atomic_store}; use core::sync::atomic::Ordering; +use collections::btree_map::BTreeMap; +use collections::string::String; +use collections::vec::Vec; +use alloc::boxed::Box; -use spin::Mutex; +use syscall::io::{Io, Pio}; + +use spin::RwLock; + +use stop::kstop; use device::local_apic::LOCAL_APIC; use interrupt; @@ -19,8 +27,10 @@ use self::rsdt::Rsdt; use self::sdt::Sdt; use self::xsdt::Xsdt; use self::hpet::Hpet; +use self::rxsdt::Rxsdt; +use self::rsdp::RSDP; -use self::aml::{is_aml_table, parse_aml_table, AmlNamespace, AmlError}; +use self::aml::{is_aml_table, parse_aml_table, AmlError, AmlValue}; pub mod hpet; mod dmar; @@ -30,6 +40,8 @@ mod rsdt; mod sdt; mod xsdt; mod aml; +mod rxsdt; +mod rsdp; const TRAMPOLINE: usize = 0x7E00; const AP_STARTUP: usize = TRAMPOLINE + 512; @@ -62,256 +74,196 @@ fn get_sdt(sdt_address: usize, active_table: &mut ActivePageTable) -> &'static S sdt } -fn parse_sdt(sdt: &'static Sdt, active_table: &mut ActivePageTable) { - print!(" "); - for &c in sdt.signature.iter() { - print!("{}", c as char); - } - - if let Some(fadt) = Fadt::new(sdt) { - println!(": {:X}", fadt.dsdt); - 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(madt) = Madt::new(sdt) { - println!(": {:>08X}: {}", madt.local_address, madt.flags); - - let local_apic = unsafe { &mut LOCAL_APIC }; - - let me = local_apic.id() as u8; - - if local_apic.x2 { - println!(" X2APIC {}", me); - } else { - println!(" XAPIC {}: {:>08X}", me, local_apic.address); +fn init_aml_table(sdt: &'static Sdt) { + match parse_aml_table(sdt) { + Ok(_) => println!(": Parsed"), + Err(AmlError::AmlParseError(e)) => println!(": {}", e), + Err(AmlError::AmlInvalidOpCode) => println!(": Invalid opcode"), + Err(AmlError::AmlValueError) => println!(": Type constraints or value bounds not met"), + Err(AmlError::AmlDeferredLoad) => println!(": Deferred load reached top level"), + Err(AmlError::AmlFatalError(_, _, _)) => { + println!(": Fatal error occurred"); + unsafe { kstop(); } + }, + Err(AmlError::AmlHardFatal) => { + println!(": Fatal error occurred"); + unsafe { kstop(); } } + } +} - if cfg!(feature = "multi_core"){ - let trampoline_frame = Frame::containing_address(PhysicalAddress::new(TRAMPOLINE)); - let trampoline_page = Page::containing_address(VirtualAddress::new(TRAMPOLINE)); - - // Map trampoline - let result = active_table.map_to(trampoline_page, trampoline_frame, entry::PRESENT | entry::WRITABLE); - result.flush(active_table); - - for madt_entry in madt.iter() { - println!(" {:?}", madt_entry); - match madt_entry { - MadtEntry::LocalApic(ap_local_apic) => if ap_local_apic.id == me { - println!(" This is my local APIC"); - } else { - if ap_local_apic.flags & 1 == 1 { - // Increase CPU ID - CPU_COUNT.fetch_add(1, Ordering::SeqCst); - - // Allocate a stack - let stack_start = allocate_frames(64).expect("no more frames in acpi stack_start").start_address().get() + ::KERNEL_OFFSET; - let stack_end = stack_start + 64 * 4096; - - let ap_ready = TRAMPOLINE as *mut u64; - let ap_cpu_id = unsafe { ap_ready.offset(1) }; - let ap_page_table = unsafe { ap_ready.offset(2) }; - let ap_stack_start = unsafe { ap_ready.offset(3) }; - let ap_stack_end = unsafe { ap_ready.offset(4) }; - let ap_code = unsafe { ap_ready.offset(5) }; - - // Set the ap_ready to 0, volatile - unsafe { atomic_store(ap_ready, 0) }; - unsafe { atomic_store(ap_cpu_id, ap_local_apic.id as u64) }; - unsafe { atomic_store(ap_page_table, active_table.address() as u64) }; - unsafe { atomic_store(ap_stack_start, stack_start as u64) }; - unsafe { atomic_store(ap_stack_end, stack_end as u64) }; - unsafe { atomic_store(ap_code, kstart_ap as u64) }; - AP_READY.store(false, Ordering::SeqCst); - - print!(" AP {}:", ap_local_apic.id); - - // Send INIT IPI - { - let mut icr = 0x4500; - if local_apic.x2 { - icr |= (ap_local_apic.id as u64) << 32; - } else { - icr |= (ap_local_apic.id as u64) << 56; - } - print!(" IPI..."); - local_apic.set_icr(icr); - } - - // Send START IPI - { - //Start at 0x0800:0000 => 0x8000. Hopefully the bootloader code is still there - let ap_segment = (AP_STARTUP >> 12) & 0xFF; - let mut icr = 0x4600 | ap_segment as u64; - - if local_apic.x2 { - icr |= (ap_local_apic.id as u64) << 32; - } else { - icr |= (ap_local_apic.id as u64) << 56; - } - - print!(" SIPI..."); - local_apic.set_icr(icr); - } - - // Wait for trampoline ready - print!(" Wait..."); - while unsafe { atomic_load(ap_ready) } == 0 { - interrupt::pause(); - } - print!(" Trampoline..."); - while ! AP_READY.load(Ordering::SeqCst) { - interrupt::pause(); - } - println!(" Ready"); - - active_table.flush_all(); - } else { - println!(" CPU Disabled"); - } - }, - _ => () - } - } - - // Unmap trampoline - let (result, _frame) = active_table.unmap_return(trampoline_page, false); - result.flush(active_table); - } - } else if let Some(dmar) = Dmar::new(sdt) { - println!(": {}: {}", dmar.addr_width, dmar.flags); - - for dmar_entry in dmar.iter() { - println!(" {:?}", dmar_entry); - match dmar_entry { - DmarEntry::Drhd(dmar_drhd) => { - let drhd = dmar_drhd.get(active_table); - - println!("VER: {:X}", drhd.version); - println!("CAP: {:X}", drhd.cap); - println!("EXT_CAP: {:X}", drhd.ext_cap); - println!("GCMD: {:X}", drhd.gl_cmd); - println!("GSTS: {:X}", drhd.gl_sts); - println!("RT: {:X}", drhd.root_table); - }, - _ => () - } - } - } else if let Some(hpet) = Hpet::new(sdt) { - println!(": {}", hpet.hpet_number); - ACPI_TABLE.lock().hpet = Some(hpet); - } 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 - } - }; +fn init_namespace() { + { + let mut namespace = ACPI_TABLE.namespace.write(); + *namespace = Some(BTreeMap::new()); + } + + let dsdt = find_sdt("DSDT"); + if dsdt.len() == 1 { + print!(" DSDT"); + load_table(get_sdt_signature(dsdt[0])); + init_aml_table(dsdt[0]); } else { - println!(": Unknown"); + println!("Unable to find DSDT"); + return; + }; + + let ssdts = find_sdt("SSDT"); + + for ssdt in ssdts { + print!(" SSDT"); + load_table(get_sdt_signature(ssdt)); + init_aml_table(ssdt); } } /// Parse the ACPI tables to gather CPU, interrupt, and timer information pub unsafe fn init(active_table: &mut ActivePageTable) { - let start_addr = 0xE0000; - let end_addr = 0xFFFFF; - - // Map all of the ACPI RSDP space { - let start_frame = Frame::containing_address(PhysicalAddress::new(start_addr)); - let end_frame = Frame::containing_address(PhysicalAddress::new(end_addr)); - for frame in Frame::range_inclusive(start_frame, end_frame) { - let page = Page::containing_address(VirtualAddress::new(frame.start_address().get())); - let result = active_table.map_to(page, frame, entry::PRESENT | entry::NO_EXECUTE); - result.flush(active_table); - } + let mut sdt_ptrs = SDT_POINTERS.write(); + *sdt_ptrs = Some(BTreeMap::new()); } + { + let mut order = SDT_ORDER.write(); + *order = Some(vec!()); + } + // Search for RSDP - if let Some(rsdp) = RSDP::search(start_addr, end_addr) { + if let Some(rsdp) = RSDP::get_rsdp(active_table) { let rxsdt = get_sdt(rsdp.sdt_address(), active_table); for &c in rxsdt.signature.iter() { print!("{}", c as char); } println!(":"); - if let Some(rsdt) = Rsdt::new(rxsdt) { - for sdt_address in rsdt.iter() { - let sdt = get_sdt(sdt_address, active_table); - parse_sdt(sdt, active_table); - } + + let rxsdt: Box<Rxsdt + Send + Sync> = if let Some(rsdt) = Rsdt::new(rxsdt) { + Box::new(rsdt) } else if let Some(xsdt) = Xsdt::new(rxsdt) { - for sdt_address in xsdt.iter() { - let sdt = get_sdt(sdt_address, active_table); - parse_sdt(sdt, active_table); - } + Box::new(xsdt) } else { println!("UNKNOWN RSDT OR XSDT SIGNATURE"); + return; + }; + + rxsdt.map_all(active_table); + + for sdt_address in rxsdt.iter() { + let sdt = unsafe { &*(sdt_address as *const Sdt) }; + + let signature = get_sdt_signature(sdt); + if let Some(ref mut ptrs) = *(SDT_POINTERS.write()) { + ptrs.insert(signature, sdt); + } } + + Fadt::init(active_table); + Madt::init(active_table); + Dmar::init(active_table); + Hpet::init(active_table); + init_namespace(); } else { println!("NO RSDP FOUND"); } +} - /* TODO: Cleanup mapping when looking for RSDP - // Unmap all of the ACPI RSDP space - { - let start_frame = Frame::containing_address(PhysicalAddress::new(start_addr)); - let end_frame = Frame::containing_address(PhysicalAddress::new(end_addr)); - for frame in Frame::range_inclusive(start_frame, end_frame) { - let page = Page::containing_address(VirtualAddress::new(frame.start_address().get())); - let result = active_table.unmap(page); - result.flush(active_table); +pub fn set_global_s_state(state: u8) { + if state == 5 { + let fadt = ACPI_TABLE.fadt.read(); + + if let Some(ref fadt) = *fadt { + let port = fadt.pm1a_control_block as u16; + let mut val = 1 << 13; + + let namespace = ACPI_TABLE.namespace.read(); + + if let Some(ref namespace) = *namespace { + if let Some(s) = namespace.get("\\_S5") { + if let Ok(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); + } + } + } } } - */ } -pub struct Acpi { - pub fadt: Option<Fadt>, - pub namespace: Option<AmlNamespace>, - pub hpet: Option<Hpet> +type SdtSignature = (String, [u8; 6], [u8; 8]); +pub static SDT_POINTERS: RwLock<Option<BTreeMap<SdtSignature, &'static Sdt>>> = RwLock::new(None); +pub static SDT_ORDER: RwLock<Option<Vec<SdtSignature>>> = RwLock::new(None); + +pub fn find_sdt(name: &str) -> Vec<&'static Sdt> { + let mut sdts: Vec<&'static Sdt> = vec!(); + + if let Some(ref ptrs) = *(SDT_POINTERS.read()) { + for (signature, sdt) in ptrs { + if signature.0 == name { + sdts.push(sdt); + } + } + } + + sdts } -pub static ACPI_TABLE: Mutex<Acpi> = Mutex::new(Acpi { fadt: None, namespace: None, hpet: None }); - -/// RSDP -#[derive(Copy, Clone, Debug)] -#[repr(packed)] -pub struct RSDP { - signature: [u8; 8], - checksum: u8, - oemid: [u8; 6], - revision: u8, - rsdt_address: u32, - length: u32, - xsdt_address: u64, - extended_checksum: u8, - reserved: [u8; 3] +pub fn get_sdt_signature(sdt: &'static Sdt) -> SdtSignature { + let signature = String::from_utf8(sdt.signature.to_vec()).expect("Error converting signature to string"); + (signature, sdt.oem_id, sdt.oem_table_id) } -impl RSDP { - /// Search for the RSDP - pub fn search(start_addr: usize, end_addr: usize) -> Option<RSDP> { - for i in 0 .. (end_addr + 1 - start_addr)/16 { - let rsdp = unsafe { &*((start_addr + i * 16) as *const RSDP) }; - if &rsdp.signature == b"RSD PTR " { - return Some(*rsdp); - } +pub fn load_table(signature: SdtSignature) { + let mut order = SDT_ORDER.write(); + + if let Some(ref mut o) = *order { + o.push(signature); + } +} + +pub fn get_signature_from_index(index: usize) -> Option<SdtSignature> { + if let Some(ref order) = *(SDT_ORDER.read()) { + if index < order.len() { + Some(order[index].clone()) + } else { + None } + } else { None } +} - /// Get the RSDT or XSDT address - pub fn sdt_address(&self) -> usize { - if self.revision >= 2 { - self.xsdt_address as usize - } else { - self.rsdt_address as usize +pub fn get_index_from_signature(signature: SdtSignature) -> Option<usize> { + if let Some(ref order) = *(SDT_ORDER.read()) { + let mut i = order.len(); + while i > 0 { + i -= 1; + + if order[i] == signature { + return Some(i); + } } } + + None } + +pub struct Acpi { + pub fadt: RwLock<Option<Fadt>>, + pub namespace: RwLock<Option<BTreeMap<String, AmlValue>>>, + pub hpet: RwLock<Option<Hpet>>, + pub next_ctx: RwLock<u64>, +} + +pub static ACPI_TABLE: Acpi = Acpi { + fadt: RwLock::new(None), + namespace: RwLock::new(None), + hpet: RwLock::new(None), + next_ctx: RwLock::new(0), +}; diff --git a/src/acpi/rsdp.rs b/src/acpi/rsdp.rs new file mode 100644 index 0000000000000000000000000000000000000000..3e25ec05203cecd0f4e701a63797232b05eabcf8 --- /dev/null +++ b/src/acpi/rsdp.rs @@ -0,0 +1,57 @@ +use memory::{allocate_frames, Frame}; +use paging::{entry, ActivePageTable, Page, PhysicalAddress, VirtualAddress}; + +/// RSDP +#[derive(Copy, Clone, Debug)] +#[repr(packed)] +pub struct RSDP { + signature: [u8; 8], + checksum: u8, + oemid: [u8; 6], + revision: u8, + rsdt_address: u32, + length: u32, + xsdt_address: u64, + extended_checksum: u8, + reserved: [u8; 3] +} + +impl RSDP { + /// Search for the RSDP + pub fn get_rsdp(active_table: &mut ActivePageTable) -> Option<RSDP> { + let start_addr = 0xE0000; + let end_addr = 0xFFFFF; + + // Map all of the ACPI RSDP space + { + let start_frame = Frame::containing_address(PhysicalAddress::new(start_addr)); + let end_frame = Frame::containing_address(PhysicalAddress::new(end_addr)); + for frame in Frame::range_inclusive(start_frame, end_frame) { + let page = Page::containing_address(VirtualAddress::new(frame.start_address().get())); + let result = active_table.map_to(page, frame, entry::PRESENT | entry::NO_EXECUTE); + result.flush(active_table); + } + } + + RSDP::search(start_addr, end_addr) + } + + fn search(start_addr: usize, end_addr: usize) -> Option<RSDP> { + for i in 0 .. (end_addr + 1 - start_addr)/16 { + let rsdp = unsafe { &*((start_addr + i * 16) as *const RSDP) }; + if &rsdp.signature == b"RSD PTR " { + return Some(*rsdp); + } + } + None + } + + /// Get the RSDT or XSDT address + pub fn sdt_address(&self) -> usize { + if self.revision >= 2 { + self.xsdt_address as usize + } else { + self.rsdt_address as usize + } + } +} diff --git a/src/acpi/rsdt.rs b/src/acpi/rsdt.rs index fa391c0c678ca9eb31be84c54fc084ebb95a9ac8..7877a061801c4557c709bf222b2d0b07740cfa68 100644 --- a/src/acpi/rsdt.rs +++ b/src/acpi/rsdt.rs @@ -1,6 +1,8 @@ use core::mem; +use alloc::boxed::Box; use super::sdt::Sdt; +use super::rxsdt::Rxsdt; #[derive(Debug)] pub struct Rsdt(&'static Sdt); @@ -13,12 +15,14 @@ impl Rsdt { None } } +} - pub fn iter(&self) -> RsdtIter { - RsdtIter { +impl Rxsdt for Rsdt { + fn iter(&self) -> Box<Iterator<Item = usize>> { + Box::new(RsdtIter { sdt: self.0, i: 0 - } + }) } } diff --git a/src/acpi/rxsdt.rs b/src/acpi/rxsdt.rs new file mode 100644 index 0000000000000000000000000000000000000000..8c7278be60204f4ce13201b88abf2aa64278a639 --- /dev/null +++ b/src/acpi/rxsdt.rs @@ -0,0 +1,28 @@ +use alloc::boxed::Box; + +use paging::ActivePageTable; + +use super::sdt::Sdt; +use super::get_sdt; + +pub trait Rxsdt { + fn iter(&self) -> Box<Iterator<Item = usize>>; + + fn map_all(&self, active_table: &mut ActivePageTable) { + for sdt in self.iter() { + get_sdt(sdt, active_table); + } + } + + fn find(&self, signature: [u8; 4], oem_id: [u8; 6], oem_table_id: [u8; 8]) -> Option<&'static Sdt> { + for sdt in self.iter() { + let sdt = unsafe { &*(sdt as *const Sdt) }; + + if sdt.match_pattern(signature, oem_id, oem_table_id) { + return Some(sdt); + } + } + + return None; + } +} diff --git a/src/acpi/sdt.rs b/src/acpi/sdt.rs index 62d55cf472bb0e97ce31e68dc6f6d23be494a5a0..67dee89ba26e989a64eaf80cb4758c4c3c4db488 100644 --- a/src/acpi/sdt.rs +++ b/src/acpi/sdt.rs @@ -17,12 +17,12 @@ pub struct Sdt { impl Sdt { /// Get the address of this tables data - pub fn data_address(&'static self) -> usize { + pub fn data_address(&self) -> usize { self as *const _ as usize + mem::size_of::<Sdt>() } /// Get the length of this tables data - pub fn data_len(&'static self) -> usize { + pub fn data_len(&self) -> usize { let total_size = self.length as usize; let header_size = mem::size_of::<Sdt>(); if total_size >= header_size { @@ -32,7 +32,11 @@ impl Sdt { } } - pub fn data(&'static self) -> &[u8] { + pub fn data(&self) -> &[u8] { unsafe { slice::from_raw_parts(self.data_address() as *const u8, self.data_len()) } } + + pub fn match_pattern(&self, signature: [u8; 4], oem_id: [u8; 6], oem_table_id: [u8; 8]) -> bool{ + self.signature == signature && self.oem_id == oem_id && self.oem_table_id == oem_table_id + } } diff --git a/src/acpi/xsdt.rs b/src/acpi/xsdt.rs index 5ec60361c43ac00fdec7293f2df342fe61ecf9d8..7339ce01e9577f5a800d743c5c9396d1e5306f05 100644 --- a/src/acpi/xsdt.rs +++ b/src/acpi/xsdt.rs @@ -1,6 +1,8 @@ use core::mem; +use alloc::boxed::Box; use super::sdt::Sdt; +use super::rxsdt::Rxsdt; #[derive(Debug)] pub struct Xsdt(&'static Sdt); @@ -13,12 +15,14 @@ impl Xsdt { None } } +} - pub fn iter(&self) -> XsdtIter { - XsdtIter { +impl Rxsdt for Xsdt { + fn iter(&self) -> Box<Iterator<Item = usize>> { + Box::new(XsdtIter { sdt: self.0, i: 0 - } + }) } } diff --git a/src/arch/x86_64/device/hpet.rs b/src/arch/x86_64/device/hpet.rs index 3f88f36896f473f5d651ead3c4a503977a145b0d..3490dee5b1697ededa3bc7fdbb3c4783b7ef06ba 100644 --- a/src/arch/x86_64/device/hpet.rs +++ b/src/arch/x86_64/device/hpet.rs @@ -1,19 +1,5 @@ -use core::intrinsics::{volatile_load, volatile_store}; - -use memory::Frame; -use paging::{entry, ActivePageTable, PhysicalAddress, Page, VirtualAddress}; - use acpi::hpet::Hpet; -pub static mut HPET: HpetDevice = HpetDevice { - capability_addr: 0, - general_config_addr: 0, - general_interrupt_addr: 0, - main_counter_addr: 0, - t0_config_capability_addr: 0, - t0_comparator_addr: 0 -}; - static LEG_RT_CNF: u64 = 2; static ENABLE_CNF: u64 = 1; @@ -21,62 +7,24 @@ static TN_VAL_SET_CNF: u64 = 0x40; static TN_TYPE_CNF: u64 = 0x08; static TN_INT_ENB_CNF: u64 = 0x04; -pub struct HpetDevice { - capability_addr: usize, - general_config_addr: usize, - general_interrupt_addr: usize, - main_counter_addr: usize, - t0_config_capability_addr: usize, - t0_comparator_addr: usize -} - -pub unsafe fn init(hpet: &Hpet, active_table: &mut ActivePageTable) { - HPET.init(hpet, active_table); -} - -impl HpetDevice { - unsafe fn init(&mut self, hpet: &Hpet, active_table: &mut ActivePageTable) { - let base_address = hpet.base_address.address as usize; - - self.capability_addr = base_address; - self.general_config_addr = base_address + 0x10; - self.general_interrupt_addr = base_address + 0x20; - self.main_counter_addr = base_address + 0xF0; - - self.t0_config_capability_addr = base_address + 0x100; - self.t0_comparator_addr = base_address + 0x108; - - { - let page = Page::containing_address(VirtualAddress::new(base_address)); - let frame = Frame::containing_address(PhysicalAddress::new(base_address)); - let result = active_table.map_to(page, frame, entry::PRESENT | entry::WRITABLE | entry::NO_EXECUTE); - result.flush(active_table); - } - - println!("HPET mapped"); - - let counter_clk_period_fs = self.get_counter_clock_period(); - let desired_fs_period: u64 = 2250286 * 1000000; - - let clk_periods_per_kernel_tick: u64 = desired_fs_period / counter_clk_period_fs; - - let enable_word: u64 = volatile_load(self.general_config_addr as *const u64) - | LEG_RT_CNF | ENABLE_CNF; +static CAPABILITY_OFFSET: usize = 0x00; +static GENERAL_CONFIG_OFFSET: usize = 0x10; +// static GENERAL_INTERRUPT_OFFSET: usize = 0x20; +// static MAIN_COUNTER_OFFSET: usize = 0xF0; +static T0_CONFIG_CAPABILITY_OFFSET: usize = 0x100; +static T0_COMPARATOR_OFFSET: usize = 0x108; - volatile_store(self.general_config_addr as *mut u64, enable_word); - // Enable interrupts from the HPET +pub unsafe fn init(hpet: &mut Hpet) { + let counter_clk_period_fs = hpet.base_address.read_u64(CAPABILITY_OFFSET) >> 32; + let desired_fs_period: u64 = 2250286 * 1000000; - let t0_config_word: u64 = TN_VAL_SET_CNF | TN_TYPE_CNF | TN_INT_ENB_CNF; - volatile_store(self.t0_config_capability_addr as *mut u64, t0_config_word); + let clk_periods_per_kernel_tick: u64 = desired_fs_period / counter_clk_period_fs; - volatile_store(self.t0_comparator_addr as *mut u64, clk_periods_per_kernel_tick); - } + let enable_word: u64 = hpet.base_address.read_u64(GENERAL_CONFIG_OFFSET) | LEG_RT_CNF | ENABLE_CNF; + hpet.base_address.write_u64(GENERAL_CONFIG_OFFSET, enable_word); + // Enable interrupts from the HPET - pub fn get_counter_clock_period(&self) -> u64 { - unsafe { volatile_load(self.capability_addr as *const u64) >> 32 } - } - - pub fn get_main_counter(&self) -> u64 { - unsafe { volatile_load(self.main_counter_addr as *const u64) } - } + let t0_config_word: u64 = TN_VAL_SET_CNF | TN_TYPE_CNF | TN_INT_ENB_CNF; + hpet.base_address.write_u64(T0_CONFIG_CAPABILITY_OFFSET, t0_config_word); + hpet.base_address.write_u64(T0_COMPARATOR_OFFSET, clk_periods_per_kernel_tick); } diff --git a/src/arch/x86_64/device/mod.rs b/src/arch/x86_64/device/mod.rs index 965e0834e121d52c50230daaf1cbd271ed3b6bb8..b7b9ceac67d648dc5b5e7bf3667ba6c02dda5e6d 100644 --- a/src/arch/x86_64/device/mod.rs +++ b/src/arch/x86_64/device/mod.rs @@ -1,6 +1,5 @@ use paging::ActivePageTable; use acpi::ACPI_TABLE; -use syscall::io::{Pio, Io}; pub mod cpu; pub mod local_apic; @@ -15,10 +14,10 @@ pub unsafe fn init(active_table: &mut ActivePageTable){ local_apic::init(active_table); } -pub unsafe fn init_noncore(active_table: &mut ActivePageTable) { +pub unsafe fn init_noncore() { { - if let Some(ref hpet) = ACPI_TABLE.lock().hpet { - hpet::init(hpet, active_table); + if let Some(ref mut hpet) = *ACPI_TABLE.hpet.write() { + hpet::init(hpet); } else { pit::init(); } diff --git a/src/arch/x86_64/start.rs b/src/arch/x86_64/start.rs index cd3c0c44b27c06cd445d32eedc3bc1cc3a53cf33..d2995e654edfb5b838cbc1802c78682f7f02792c 100644 --- a/src/arch/x86_64/start.rs +++ b/src/arch/x86_64/start.rs @@ -15,6 +15,8 @@ use memory; use paging::{self, entry, Page, VirtualAddress}; use paging::mapper::MapperFlushAll; +use stop; + /// Test of zero values in BSS. static BSS_TEST_ZERO: usize = 0; /// Test of non-zero values in data. @@ -107,7 +109,7 @@ pub unsafe extern fn kstart(kernel_base: usize, kernel_size: usize, stack_base: acpi::init(&mut active_table); // Initialize all of the non-core devices not otherwise needed to complete initialization - device::init_noncore(&mut active_table); + device::init_noncore(); // Initialize memory functions after core has loaded memory::init_noncore(); diff --git a/src/arch/x86_64/stop.rs b/src/arch/x86_64/stop.rs index 45b8d7d8f6b94c8d435f5c4e4838757922b83d84..c65768cc104b7387f4e9b0b1cfb2e00740ab1019 100644 --- a/src/arch/x86_64/stop.rs +++ b/src/arch/x86_64/stop.rs @@ -21,29 +21,7 @@ pub unsafe extern fn kreset() -> ! { #[no_mangle] pub unsafe extern fn kstop() -> ! { println!("kstop"); - - // ACPI shutdown - { - let acpi = acpi::ACPI_TABLE.lock(); - if let Some(ref fadt) = acpi.fadt { - let port = fadt.pm1a_control_block as u16; - let mut val = 1 << 13; - 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); - } - } + acpi::set_global_s_state(5); // Magic shutdown code for bochs and qemu (older versions). for c in "Shutdown".bytes() { diff --git a/src/lib.rs b/src/lib.rs index 33e746aec4273fe8f0b5c5e8442d3b3edc9a76c1..d0a1a2250082e03926418557cda24410a56e3920 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,7 @@ #![feature(never_type)] #![feature(thread_local)] #![feature(unique)] +#![feature(conservative_impl_trait)] #![no_std] extern crate alloc_kernel as allocator;