Rolled parsing and execution steps into one for namespace modifiers

This commit is contained in:
Connor Wood
2017-06-23 14:02:40 +01:00
parent 5213d59237
commit f131cc6f1f
5 changed files with 95 additions and 98 deletions

View File

@@ -22,22 +22,16 @@ mod namedobj;
mod dataobj;
mod type1opcode;
mod type2opcode;
mod parser;
use self::parser::{ParseResult, AmlInternalError};
use self::termlist::{parse_term_list, TermObj};
pub use self::namespace::{get_namespace_string, AmlValue};
// TODO: This should be able to take parameters, and may also return multiple values
pub trait AmlExecutable {
fn execute(&self, namespace: &mut BTreeMap<String, AmlValue>, scope: String) -> Option<AmlValue>;
}
// TODO: make private
pub enum AmlInternalError {
AmlParseError(&'static str),
AmlInvalidOpCode,
AmlDeferredLoad
}
pub enum AmlError {
AmlParseError(&'static str)
}

View File

@@ -9,55 +9,11 @@ use super::namestring::{parse_name_string, SuperName};
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 BTreeMap<String, AmlValue>, scope: String) -> Option<AmlValue> {
match *self {
NamespaceModifier::Scope { name: ref name, terms: ref terms } => {
let local_scope_string = get_namespace_string(scope, name.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.insert(local_scope_string, dro);
},
NamespaceModifier::Alias { ref source_name, ref alias_name } => {
let local_scope_string = get_namespace_string(scope.clone(), source_name.clone());
let local_alias_string = get_namespace_string(scope.clone(), alias_name.clone());
namespace.insert(local_scope_string, AmlValue::ObjectReference(SuperName::NameString(local_alias_string)));
},
_ => ()
}
None
}
}
pub fn parse_namespace_modifier(data: &[u8]) -> Result<(NamespaceModifier, usize), AmlInternalError> {
pub fn parse_namespace_modifier(data: &[u8],
namespace: &mut BTreeMap<String, AmlValue>,
scope: String) -> ParseResult {
parser_selector! {
data,
data, namespace, scope,
parse_alias_op,
parse_scope_op,
parse_name_op
@@ -66,42 +22,57 @@ pub fn parse_namespace_modifier(data: &[u8]) -> Result<(NamespaceModifier, usize
Err(AmlInternalError::AmlInvalidOpCode)
}
fn parse_alias_op(data: &[u8]) -> Result<(NamespaceModifier, usize), AmlInternalError> {
fn parse_alias_op(data: &[u8],
namespace: &mut BTreeMap<String, AmlValue>,
scope: String) -> ParseResult {
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..])?;
let source_name = parse_name_string(&data[1..], namespace, scope)?;
let alias_name = parse_name_string(&data[1 + source_name_len..], namespace, scope)?;
let local_scope_string = get_namespace_string(scope.clone(), parser_verify_value!(source_name));
let local_alias_string = get_namespace_string(scope.clone(), parser_verify_value!(alias_name));
Ok((NamespaceModifier::Alias {source_name, alias_name}, 1 + source_name_len + alias_name_len))
namespace.insert(local_scope_string, AmlValue::ObjectReference(
SuperName::NameString(local_alias_string)));
Ok(AmlParseType {
val: 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],
namespace: &mut BTreeMap<String, AmlValue>,
scope: String) -> ParseResult {
parser_opcode!(data, 0x08);
let name = parse_name_string(&data[1..], namespace, scope)?;
let data_ref_obj = parse_data_ref_obj(&data[1 + name_len..], namespace, scope)?;
let local_scope_string = get_namespace_string(scope.clone(), parser_verify_value!(name));
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))
namespace.insert(local_scope_string, parser_verify_value!(data_ref_obj));
Ok(AmlParseType {
val: 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],
namespace: &mut BTreeMap<String, AmlValue>,
scope: String) -> ParseResult {
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..], namespace, scope)?;
let local_scope_string = get_namespace_string(scope, parser_verify_value!(name));
parse_term_list(&data[1 + pkg_length_len + name_len..], namespace, local_scope_string)?;
Ok(AmlParseType {
val: None,
len: 1 + pkg_length
})
}

16
src/acpi/aml/parser.rs Normal file
View File

@@ -0,0 +1,16 @@
use super::AmlValue;
pub type ParseResult = Result<AmlParseType, AmlInternalError>;
pub struct AmlParseType {
val: Option<AmlValue>,
len: usize
}
// TODO: make private
pub enum AmlInternalError {
AmlParseError(&'static str),
AmlInvalidOpCode,
AmlValueError,
AmlDeferredLoad
}

View File

@@ -1,15 +1,15 @@
#[macro_export]
macro_rules! parser_selector {
{$data:expr, $func:expr} => {
match $func($data) {
{$data:expr, $namespace:expr, $scope:expr, $func:expr} => {
match $func($data, $namespace, $scope) {
Ok(res) => return Ok(res),
Err(AmlInternalError::AmlInvalidOpCode) => (),
Err(e) => return Err(e)
}
};
{$data:expr, $func:expr, $($funcs:expr),+} => {
parser_selector! {$data, $func};
parser_selector! {$data, $($funcs),*};
{$data:expr, $namespace:expr, $scope:expr, $func:expr, $($funcs:expr),+} => {
parser_selector! {$data, $namespace, $scope, $func};
parser_selector! {$data, $namespace, $scope, $($funcs),*};
};
}
@@ -47,3 +47,14 @@ macro_rules! parser_opcode_extended {
}
};
}
#[macro_export]
macro_rules! parser_verify_value {
($val:expr) => {
match $val.val {
Some(s) => s,
None => return Err(AmlInternalError::AmlValueError)
}
};
}

View File

@@ -89,17 +89,20 @@ impl AmlExecutable for TermObj {
}
}
pub fn parse_term_list(data: &[u8]) -> Result<Vec<TermObj>, AmlInternalError> {
let mut terms: Vec<TermObj> = vec!();
pub fn parse_term_list(data: &[u8],
namespace: &mut BTreeMap<String, AmlValue>,
scope: String) -> ParseResult {
let mut current_offset: usize = 0;
while current_offset < data.len() {
let (res, len) = parse_term_obj(&data[current_offset..])?;
terms.push(res);
let (res, len) = parse_term_obj(&data[current_offset..], namespace, scope)?;
current_offset += len;
}
Ok(terms)
Ok(AmlParseType {
val: None,
len: data.len()
})
}
pub fn parse_term_arg(data: &[u8]) -> Result<(TermArg, usize), AmlInternalError> {
@@ -142,13 +145,15 @@ pub fn parse_method_invocation(data: &[u8]) -> Result<(MethodInvocation, usize),
Err(AmlInternalError::AmlDeferredLoad)
}
fn parse_term_obj(data: &[u8]) -> Result<(TermObj, usize), AmlInternalError> {
fn parse_term_obj(data: &[u8],
namespace: &mut BTreeMap<String, AmlValue>,
scope: String) -> ParseResult {
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, namespace, scope,
parse_namespace_modifier,
parse_named_obj,
parse_type1_opcode,
parse_type2_opcode
};
Err(AmlInternalError::AmlInvalidOpCode)