Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • redox-os/kernel
  • deepaksirone/kernel
  • microcolonel/kernel
  • jD91mZM2/kernel
  • liamnprg/kernel
  • ids1024/kernel
  • luojia/kernel
  • efikarl/kernel
  • jferard/kernel
  • rosehuds/kernel
  • xTibor/kernel
  • Ano-Nymus/kernel
  • carrot93/kernel
  • noam93k/kernel
  • corvus_corax/kernel
  • antares/kernel
  • nrdxp/kernel
  • SoyaOhnishi/kernel
  • potatogim/kernel
  • bsjung/kernel
  • batzor/kernel
  • retrocoder68/kernel
  • kal/kernel
  • jabedude/kernel
  • 4lDO2/kernel
  • cherusk/kernel
  • sudoamin/kernel
  • chetankhilosiya/kernel
  • t-nil/kernel
  • Majoneza/kernel
  • wiredtv/kernel
  • tijlleenders/kernel
  • Mottl/kernel
  • usapmz/kernel
  • kamirr/kernel
  • CodingRays/kernel
  • Ivan/kernel
  • zacklukem/kernel
  • devnexen/kernel
  • uuuvn/kernel
  • rw_van/kernel
  • freewilll/kernel
  • ebalalic/kernel
  • henritel/kernel
  • dahc/kernel
  • Forest0923/kernel
  • andrey.turkin/kernel
  • amidamaru/kernel
  • gmacd/kernel
  • jinb-park/kernel
  • bjorn3/kernel
  • neallred/kernel
  • hmcmillan/kernel
  • jmaine/kernel
  • wt/kernel
  • aaronjanse/kernel
  • Skallwar/kernel
  • NateDogg1232/kernel
  • maxtnuk/kernel
  • Vladimare/kernel
  • ylz0923/kernel
  • wheatfox/kernel
  • mjdr/kernel
  • adi-g15/kernel
  • heghe/kernel
  • enygmator/kernel
  • vincent/kernel
  • StaringAtEditor/redox-os-kernel
  • zhaozhao/kernel
  • arthurpaulino/kernel
  • andypython/kernel
  • LLeny/kernel
  • Seti/kernel
  • darley/kernel
  • Ibuki.O/kernel
75 results
Show changes
Showing
with 247 additions and 5892 deletions
use alloc::vec::Vec;
use alloc::string::String;
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
})
}
parser_selector! {
data, ctx,
parse_computational_data,
parse_def_package,
parse_def_var_package
};
Err(AmlError::AmlInvalidOpCode)
}
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
})
}
parser_selector! {
data, ctx,
parse_data_obj,
parse_term_arg
};
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],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
match data[0] {
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],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
match data[0] {
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],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
match data[0] {
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(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(AmlParseType {
val: AmlValue::Integer(res as u64),
len: 5 as usize
})
},
0x0D => {
let mut cur_ptr: usize = 1;
let mut cur_string: Vec<u8> = vec!();
while data[cur_ptr] != 0x00 {
cur_string.push(data[cur_ptr]);
cur_ptr += 1;
}
match String::from_utf8(cur_string) {
Ok(s) => Ok(AmlParseType {
val: AmlValue::String(s.clone()),
len: s.clone().len() + 2
}),
Err(_) => Err(AmlError::AmlParseError("String data - invalid string"))
}
},
0x0E => {
let res = (data[1] as u64) +
((data[2] as u64) << 8) +
((data[3] as u64) << 16) +
((data[4] as u64) << 24) +
((data[5] as u64) << 32) +
((data[6] as u64) << 40) +
((data[7] as u64) << 48) +
((data[8] as u64) << 56);
Ok(AmlParseType {
val: AmlValue::Integer(res as u64),
len: 9 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(AmlParseType {
val: AmlValue::IntegerConstant(2017_0630 as u64),
len: 2 as usize
})
} else {
Err(AmlError::AmlInvalidOpCode)
},
0xFF => Ok(AmlParseType {
val: AmlValue::IntegerConstant(0xFFFF_FFFF_FFFF_FFFF),
len: 1 as usize
}),
_ => parse_def_buffer(data, ctx)
}
}
//! # AML
//! Code to parse and execute AML tables
use alloc::string::String;
use alloc::vec::Vec;
use core::str::FromStr;
use super::sdt::Sdt;
#[macro_use]
mod parsermacros;
mod namespace;
mod termlist;
mod namespacemodifier;
mod pkglength;
mod namestring;
mod namedobj;
mod dataobj;
mod type1opcode;
mod type2opcode;
mod parser;
use self::parser::AmlExecutionContext;
use self::termlist::parse_term_list;
pub use self::namespace::AmlValue;
#[derive(Debug)]
pub enum AmlError {
AmlParseError(&'static str),
AmlInvalidOpCode,
AmlValueError,
AmlDeferredLoad,
AmlFatalError(u8, u16, AmlValue),
AmlHardFatal
}
pub fn parse_aml_table(sdt: &Sdt) -> Result<Vec<String>, AmlError> {
parse_aml_with_scope(sdt, String::from_str("\\").unwrap())
}
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)?;
Ok(ctx.namespace_delta)
}
pub fn is_aml_table(sdt: &Sdt) -> bool {
if &sdt.signature == b"DSDT" || &sdt.signature == b"SSDT" {
true
} else {
false
}
}
This diff is collapsed.
use alloc::boxed::Box;
use alloc::string::String;
use alloc::string::ToString;
use alloc::vec::Vec;
use alloc::collections::BTreeMap;
use core::fmt::Debug;
use core::str::FromStr;
use super::termlist::parse_term_list;
use super::namedobj::{ RegionSpace, FieldFlags };
use super::parser::{AmlExecutionContext, ExecutionState};
use super::AmlError;
use crate::acpi::{SdtSignature, get_signature_from_index, get_index_from_signature};
#[derive(Clone, Debug)]
pub enum FieldSelector {
Region(String),
Bank {
region: String,
bank_register: String,
bank_selector: Box<AmlValue>
},
Index {
index_selector: String,
data_selector: String
}
}
#[derive(Clone, Debug)]
pub enum ObjectReference {
ArgObj(u8),
LocalObj(u8),
Object(String),
Index(Box<AmlValue>, Box<AmlValue>)
}
#[derive(Clone, Debug)]
pub struct Method {
pub arg_count: u8,
pub serialized: bool,
pub sync_level: u8,
pub term_list: Vec<u8>
}
#[derive(Clone, Debug)]
pub struct BufferField {
pub source_buf: Box<AmlValue>,
pub index: Box<AmlValue>,
pub length: Box<AmlValue>
}
#[derive(Clone, Debug)]
pub struct FieldUnit {
pub selector: FieldSelector,
pub connection: Box<AmlValue>,
pub flags: FieldFlags,
pub offset: usize,
pub length: usize
}
#[derive(Clone, Debug)]
pub struct Device {
pub obj_list: Vec<String>,
pub notify_methods: BTreeMap<u8, Vec<fn()>>
}
#[derive(Clone, Debug)]
pub struct ThermalZone {
pub obj_list: Vec<String>,
pub notify_methods: BTreeMap<u8, Vec<fn()>>
}
#[derive(Clone, Debug)]
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, Debug)]
pub struct OperationRegion {
pub region: RegionSpace,
pub offset: Box<AmlValue>,
pub len: Box<AmlValue>,
pub accessor: Accessor,
pub accessed_by: Option<u64>
}
#[derive(Clone, Debug)]
pub struct PowerResource {
pub system_level: u8,
pub resource_order: u16,
pub obj_list: Vec<String>
}
#[derive(Debug)]
pub struct Accessor {
pub read: fn(usize) -> u64,
pub write: fn(usize, u64)
}
impl Clone for Accessor {
fn clone(&self) -> Accessor {
Accessor {
read: (*self).read,
write: (*self).write
}
}
}
#[derive(Clone, Debug)]
pub enum AmlValue {
None,
Uninitialized,
Alias(String),
Buffer(Vec<u8>),
BufferField(BufferField),
DDBHandle((Vec<String>, SdtSignature)),
DebugObject,
Device(Device),
Event(u64),
FieldUnit(FieldUnit),
Integer(u64),
IntegerConstant(u64),
Method(Method),
Mutex((u8, Option<u64>)),
ObjectReference(ObjectReference),
OperationRegion(OperationRegion),
Package(Vec<AmlValue>),
String(String),
PowerResource(PowerResource),
Processor(Processor),
RawDataBuffer(Vec<u8>),
ThermalZone(ThermalZone)
}
impl AmlValue {
pub fn get_type_string(&self) -> String {
match *self {
AmlValue::Uninitialized => String::from_str("[Uninitialized Object]").unwrap(),
AmlValue::Integer(_) => String::from_str("[Integer]").unwrap(),
AmlValue::String(_) => String::from_str("[String]").unwrap(),
AmlValue::Buffer(_) => String::from_str("[Buffer]").unwrap(),
AmlValue::Package(_) => String::from_str("[Package]").unwrap(),
AmlValue::FieldUnit(_) => String::from_str("[Field]").unwrap(),
AmlValue::Device(_) => String::from_str("[Device]").unwrap(),
AmlValue::Event(_) => String::from_str("[Event]").unwrap(),
AmlValue::Method(_) => String::from_str("[Control Method]").unwrap(),
AmlValue::Mutex(_) => String::from_str("[Mutex]").unwrap(),
AmlValue::OperationRegion(_) => String::from_str("[Operation Region]").unwrap(),
AmlValue::PowerResource(_) => String::from_str("[Power Resource]").unwrap(),
AmlValue::Processor(_) => String::from_str("[Processor]").unwrap(),
AmlValue::ThermalZone(_) => String::from_str("[Thermal Zone]").unwrap(),
AmlValue::BufferField(_) => String::from_str("[Buffer Field]").unwrap(),
AmlValue::DDBHandle(_) => String::from_str("[DDB Handle]").unwrap(),
AmlValue::DebugObject => String::from_str("[Debug Object]").unwrap(),
_ => String::new()
}
}
pub fn get_as_type(&self, 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_buffer(&self) -> Result<Vec<u8>, AmlError> {
match *self {
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)
}
}
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 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 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)
}
}
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);
}
let mut i: u64 = 0;
while b.len() > 0 {
i <<= 8;
i += b.pop().expect("Won't happen") as u64;
}
Ok(i)
},
AmlValue::BufferField(_) => {
let mut b = self.get_as_buffer()?;
if b.len() > 8 {
return Err(AmlError::AmlValueError);
}
let mut i: u64 = 0;
while b.len() > 0 {
i <<= 8;
i += b.pop().expect("Won't happen") as u64;
}
Ok(i)
},
AmlValue::DDBHandle(ref v) => if let Some(idx) = get_index_from_signature(v.1.clone()) {
Ok(idx as u64)
} else {
Err(AmlError::AmlValueError)
},
AmlValue::String(ref s) => {
let s = s.clone()[0..8].to_string().to_uppercase();
let mut i: u64 = 0;
for c in s.chars() {
if !c.is_digit(16) {
break;
}
i <<= 8;
i += c.to_digit(16).unwrap() as u64;
}
Ok(i)
},
_ => Err(AmlError::AmlValueError)
}
}
pub fn get_as_integer_constant(&self) -> Result<u64, AmlError> {
match *self {
AmlValue::IntegerConstant(ref i) => Ok(i.clone()),
_ => Err(AmlError::AmlValueError)
}
}
pub fn get_as_method(&self) -> Result<Method, AmlError> {
match *self {
AmlValue::Method(ref m) => Ok(m.clone()),
_ => Err(AmlError::AmlValueError)
}
}
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 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)
}
}
}
impl Method {
pub fn execute(&self, scope: String, parameters: Vec<AmlValue>) -> AmlValue {
let mut ctx = AmlExecutionContext::new(scope);
ctx.init_arg_vars(parameters);
let _ = parse_term_list(&self.term_list[..], &mut ctx);
ctx.clean_namespace();
match ctx.state {
ExecutionState::RETURN(v) => v,
_ => AmlValue::IntegerConstant(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 modifier.len() == 0 {
return Ok(current);
}
if modifier.starts_with("\\") {
return Ok(modifier);
}
let mut namespace = current.clone();
if modifier.starts_with("^") {
while modifier.starts_with("^") {
modifier = modifier[1..].to_string();
if namespace.ends_with("\\") {
return Err(AmlError::AmlValueError);
}
loop {
if namespace.ends_with(".") {
namespace.pop();
break;
}
if namespace.pop() == None {
return Err(AmlError::AmlValueError);
}
}
}
}
if !namespace.ends_with("\\") {
namespace.push('.');
}
Ok(namespace + &modifier)
}
use super::AmlError;
use super::parser::{AmlParseType, ParseResult, AmlExecutionContext, ExecutionState};
use super::namespace::{AmlValue, get_namespace_string};
use super::pkglength::parse_pkg_length;
use super::namestring::parse_name_string;
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
})
}
parser_selector! {
data, ctx,
parse_alias_op,
parse_scope_op,
parse_name_op
};
Err(AmlError::AmlInvalidOpCode)
}
fn parse_alias_op(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode!(data, 0x06);
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],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode!(data, 0x08);
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],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode!(data, 0x10);
let (pkg_length, pkg_length_len) = parse_pkg_length(&data[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
})
}
use alloc::vec::Vec;
use alloc::string::String;
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
})
}
let mut characters: Vec<u8> = vec!();
let mut starting_index: usize = 0;
if data[0] == 0x5C {
characters.push(data[0]);
starting_index = 1;
} else if data[0] == 0x5E {
while data[starting_index] == 0x5E {
characters.push(data[starting_index]);
starting_index += 1;
}
}
let sel = |data| {
parser_selector_simple! {
data,
parse_dual_name_path,
parse_multi_name_path,
parse_null_name,
parse_name_seg
};
Err(AmlError::AmlInvalidOpCode)
};
let (mut chr, len) = sel(&data[starting_index..])?;
characters.append(&mut chr);
let name_string = String::from_utf8(characters);
match name_string {
Ok(s) => Ok(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), AmlError> {
parser_opcode!(data, 0x00);
Ok((vec!(), 1 ))
}
pub fn parse_name_seg(data: &[u8]) -> Result<(Vec<u8>, usize), AmlError> {
match data[0] {
0x41 ..= 0x5A | 0x5F => (),
_ => return Err(AmlError::AmlInvalidOpCode)
}
match data[1] {
0x30 ..= 0x39 | 0x41 ..= 0x5A | 0x5F => (),
_ => return Err(AmlError::AmlInvalidOpCode)
}
match data[2] {
0x30 ..= 0x39 | 0x41 ..= 0x5A | 0x5F => (),
_ => return Err(AmlError::AmlInvalidOpCode)
}
match data[3] {
0x30 ..= 0x39 | 0x41 ..= 0x5A | 0x5F => (),
_ => return Err(AmlError::AmlInvalidOpCode)
}
let mut name_seg = vec!(data[0], data[1], data[2], data[3]);
while *(name_seg.last().unwrap()) == 0x5F {
name_seg.pop();
}
Ok((name_seg, 4))
}
fn parse_dual_name_path(data: &[u8]) -> Result<(Vec<u8>, usize), AmlError> {
parser_opcode!(data, 0x2E);
let mut characters: Vec<u8> = vec!();
let mut dual_len: usize = 1;
match parse_name_seg(&data[1..5]) {
Ok((mut v, len)) => {
characters.append(&mut v);
dual_len += len;
},
Err(e) => return Err(e)
}
characters.push(0x2E);
match parse_name_seg(&data[5..9]) {
Ok((mut v, len)) => {
characters.append(&mut v);
dual_len += len;
},
Err(e) => return Err(e)
}
Ok((characters, dual_len))
}
fn parse_multi_name_path(data: &[u8]) -> Result<(Vec<u8>, usize), AmlError> {
parser_opcode!(data, 0x2F);
let seg_count = data[1];
if seg_count == 0x00 {
return Err(AmlError::AmlParseError("MultiName Path - can't have zero name segments"));
}
let mut current_seg = 0;
let mut characters: Vec<u8> = vec!();
let mut multi_len: usize = 2;
while current_seg < seg_count {
match parse_name_seg(&data[(current_seg as usize * 4) + 2 ..]) {
Ok((mut v, len)) => {
characters.append(&mut v);
multi_len += len;
},
Err(e) => return Err(e)
}
characters.push(0x2E);
current_seg += 1;
}
characters.pop();
Ok((characters, multi_len))
}
pub fn parse_super_name(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_selector! {
data, ctx,
parse_simple_name,
parse_type6_opcode,
parse_debug_obj
};
Err(AmlError::AmlInvalidOpCode)
}
fn parse_debug_obj(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode_extended!(data, 0x31);
Ok(AmlParseType {
val: AmlValue::DebugObject,
len: 2
})
}
pub fn parse_simple_name(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_selector! {
data, ctx,
parse_name_string,
parse_arg_obj,
parse_local_obj
};
Err(AmlError::AmlInvalidOpCode)
}
pub fn parse_target(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
if data[0] == 0x00 {
Ok(AmlParseType {
val: AmlValue::None,
len: 1
})
} else {
parse_super_name(data, ctx)
}
}
use alloc::string::String;
use alloc::collections::BTreeMap;
use alloc::vec::Vec;
use alloc::boxed::Box;
use spin::RwLockWriteGuard;
use super::namespace::{ AmlValue, ObjectReference };
use super::AmlError;
use crate::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 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 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 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 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 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()?;
let _ = 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))
},
_ => 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 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
})
}
}
#[macro_export]
macro_rules! parser_selector {
{$data:expr, $ctx:expr, $func:expr} => {
match $func($data, $ctx) {
Ok(res) => return Ok(res),
Err(AmlError::AmlInvalidOpCode) => (),
Err(e) => return Err(e)
}
};
{$data:expr, $ctx:expr, $func:expr, $($funcs:expr),+} => {
parser_selector! {$data, $ctx, $func};
parser_selector! {$data, $ctx, $($funcs),*};
};
}
#[macro_export]
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(AmlError::AmlInvalidOpCode);
}
};
($data:expr, $opcode:expr, $alternate_opcode:expr) => {
if $data[0] != $opcode && $data[0] != $alternate_opcode {
return Err(AmlError::AmlInvalidOpCode);
}
};
}
#[macro_export]
macro_rules! parser_opcode_extended {
($data:expr, $opcode:expr) => {
if $data[0] != 0x5B || $data[1] != $opcode {
return Err(AmlError::AmlInvalidOpCode);
}
};
}
use super::AmlError;
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;
if count_bytes == 0 {
return Ok(((lead_byte & 0x3F) as usize, 1 as usize));
}
let upper_two = (lead_byte >> 4) & 0x03;
if upper_two != 0 {
return Err(AmlError::AmlParseError("Invalid package length"));
}
let mut current_byte = 0;
let mut pkg_len: usize = (lead_byte & 0x0F) as usize;
while current_byte < count_bytes {
pkg_len += (data[1 + current_byte] as u32 * 16 * (256 as u32).pow(current_byte as u32)) as usize;
current_byte += 1;
}
Ok((pkg_len, count_bytes + 1))
}
use alloc::vec::Vec;
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;
pub fn parse_term_list(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
let mut current_offset: usize = 0;
while current_offset < data.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(AmlParseType {
val: AmlValue::None,
len: data.len()
})
}
pub fn parse_term_arg(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_selector! {
data, ctx,
parse_local_obj,
parse_data_obj,
parse_arg_obj,
parse_type2_opcode
};
Err(AmlError::AmlInvalidOpCode)
}
pub fn parse_object_list(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
let mut current_offset: usize = 0;
while current_offset < data.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(AmlParseType {
val: AmlValue::None,
len: data.len()
})
}
fn parse_object(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_selector! {
data, ctx,
parse_namespace_modifier,
parse_named_obj
};
Err(AmlError::AmlInvalidOpCode)
}
pub fn parse_method_invocation(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
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],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_selector! {
data, ctx,
parse_namespace_modifier,
parse_named_obj,
parse_type1_opcode,
parse_type2_opcode
};
Err(AmlError::AmlInvalidOpCode)
}
use super::AmlError;
use super::parser::{AmlParseType, ParseResult, AmlExecutionContext, ExecutionState};
use super::namespace::AmlValue;
use super::pkglength::parse_pkg_length;
use super::termlist::{parse_term_arg, parse_term_list};
use super::namestring::{parse_name_string, parse_super_name};
use crate::time::monotonic;
use crate::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
})
}
parser_selector! {
data, ctx,
parse_def_break,
parse_def_breakpoint,
parse_def_continue,
parse_def_noop,
parse_def_fatal,
parse_def_if_else,
parse_def_load,
parse_def_notify,
parse_def_release,
parse_def_reset,
parse_def_signal,
parse_def_sleep,
parse_def_stall,
parse_def_return,
parse_def_unload,
parse_def_while
};
Err(AmlError::AmlInvalidOpCode)
}
fn parse_def_break(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode!(data, 0xA5);
ctx.state = ExecutionState::BREAK;
Ok(AmlParseType {
val: AmlValue::None,
len: 1 as usize
})
}
fn parse_def_breakpoint(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode!(data, 0xCC);
Ok(AmlParseType {
val: AmlValue::None,
len: 1 as usize
})
}
fn parse_def_continue(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode!(data, 0x9F);
ctx.state = ExecutionState::CONTINUE;
Ok(AmlParseType {
val: AmlValue::None,
len: 1 as usize
})
}
fn parse_def_noop(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode!(data, 0xA3);
Ok(AmlParseType {
val: AmlValue::None,
len: 1 as usize
})
}
fn parse_def_fatal(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode_extended!(data, 0x32);
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)?;
Err(AmlError::AmlFatalError(fatal_type, fatal_code, fatal_arg.val))
}
fn parse_def_load(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
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)?;
let _ = 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)
}
}
fn parse_def_notify(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode!(data, 0x86);
let object = parse_super_name(&data[1..], ctx)?;
let value = parse_term_arg(&data[1 + object.len..], ctx)?;
let number = value.val.get_as_integer()? as u8;
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)
}
Ok(AmlParseType {
val: AmlValue::None,
len: 1 + object.len + value.len
})
}
fn parse_def_release(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode_extended!(data, 0x27);
let obj = parse_super_name(&data[2..], ctx)?;
let _ = ctx.release_mutex(obj.val);
Ok(AmlParseType {
val: AmlValue::None,
len: 2 + obj.len
})
}
fn parse_def_reset(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode_extended!(data, 0x26);
let object = parse_super_name(&data[2..], ctx)?;
ctx.get(object.val.clone())?.get_as_event()?;
let _ = ctx.modify(object.val.clone(), AmlValue::Event(0));
Ok(AmlParseType {
val: AmlValue::None,
len: 2 + object.len
})
}
fn parse_def_signal(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
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
})
}
fn parse_def_sleep(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
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 * 1_000_000_000);
loop {
let (seconds, nanoseconds) = monotonic();
let current_time_ns = nanoseconds + (seconds * 1_000_000_000);
if current_time_ns - starting_time_ns > timeout as u64 * 1_000_000 {
break;
}
}
Ok(AmlParseType {
val: AmlValue::None,
len: 2 + time.len
})
}
fn parse_def_stall(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
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 * 1_000_000_000);
loop {
let (seconds, nanoseconds) = monotonic();
let current_time_ns = nanoseconds + (seconds * 1_000_000_000);
if current_time_ns - starting_time_ns > timeout as u64 * 1000 {
break;
}
}
Ok(AmlParseType {
val: AmlValue::None,
len: 2 + time.len
})
}
fn parse_def_unload(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode_extended!(data, 0x2A);
let object = parse_super_name(&data[2..], ctx)?;
let delta = ctx.get(object.val)?.get_as_ddb_handle()?;
let mut namespace = ctx.prelock();
if let Some(ref mut ns) = *namespace {
for o in delta.0 {
ns.remove(&o);
}
}
Ok(AmlParseType {
val: AmlValue::None,
len: 2 + object.len
})
}
fn parse_def_if_else(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode!(data, 0xA0);
let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?;
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],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode!(data, 0xA2);
let (pkg_length, pkg_length_len) = parse_pkg_length(&data[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
})
}
}
Ok(AmlParseType {
val: AmlValue::None,
len: 1 + pkg_length
})
}
fn parse_def_return(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode!(data, 0xA4);
let arg_object = parse_term_arg(&data[1..], ctx)?;
ctx.state = ExecutionState::RETURN(arg_object.val);
Ok(AmlParseType {
val: AmlValue::None,
len: 1 + arg_object.len
})
}
This diff is collapsed.
#[repr(packed)]
pub struct DrhdFault {
pub sts: u32,
pub ctrl: u32,
pub data: u32,
pub addr: [u32; 2],
_rsv: [u64; 2],
pub log: u64,
}
#[repr(packed)]
pub struct DrhdProtectedMemory {
pub en: u32,
pub low_base: u32,
pub low_limit: u32,
pub high_base: u64,
pub high_limit: u64,
}
#[repr(packed)]
pub struct DrhdInvalidation {
pub queue_head: u64,
pub queue_tail: u64,
pub queue_addr: u64,
_rsv: u32,
pub cmpl_sts: u32,
pub cmpl_ctrl: u32,
pub cmpl_data: u32,
pub cmpl_addr: [u32; 2],
}
#[repr(packed)]
pub struct DrhdPageRequest {
pub queue_head: u64,
pub queue_tail: u64,
pub queue_addr: u64,
_rsv: u32,
pub sts: u32,
pub ctrl: u32,
pub data: u32,
pub addr: [u32; 2],
}
#[repr(packed)]
pub struct DrhdMtrrVariable {
pub base: u64,
pub mask: u64,
}
#[repr(packed)]
pub struct DrhdMtrr {
pub cap: u64,
pub def_type: u64,
pub fixed: [u64; 11],
pub variable: [DrhdMtrrVariable; 10],
}
#[repr(packed)]
pub struct Drhd {
pub version: u32,
_rsv: u32,
pub cap: u64,
pub ext_cap: u64,
pub gl_cmd: u32,
pub gl_sts: u32,
pub root_table: u64,
pub ctx_cmd: u64,
_rsv1: u32,
pub fault: DrhdFault,
_rsv2: u32,
pub pm: DrhdProtectedMemory,
pub invl: DrhdInvalidation,
_rsv3: u64,
pub intr_table: u64,
pub page_req: DrhdPageRequest,
pub mtrr: DrhdMtrr,
}
This diff is collapsed.
This diff is collapsed.
use alloc::boxed::Box;
use core::mem;
use super::{find_sdt, sdt::Sdt};
use crate::{
device::generic_timer::GenericTimer,
dtb::irqchip::{register_irq, IRQ_CHIP},
};
#[derive(Clone, Copy, Debug)]
#[repr(C, packed)]
pub struct Gtdt {
pub header: Sdt,
pub cnt_control_base: u64,
_reserved: u32,
pub secure_el1_timer_gsiv: u32,
pub secure_el1_timer_flags: u32,
pub non_secure_el1_timer_gsiv: u32,
pub non_secure_el1_timer_flags: u32,
pub virtual_el1_timer_gsiv: u32,
pub virtual_el1_timer_flags: u32,
pub el2_timer_gsiv: u32,
pub el2_timer_flags: u32,
pub cnt_read_base: u64,
pub platform_timer_count: u32,
pub platform_timer_offset: u32,
/*TODO: we don't need these yet, and they cause short tables to fail parsing
pub virtual_el2_timer_gsiv: u32,
pub virtual_el2_timer_flags: u32,
*/
//TODO: platform timer structure (at platform timer offset, with platform timer count)
}
impl Gtdt {
pub fn init() {
let gtdt_sdt = find_sdt("GTDT");
let gtdt = if gtdt_sdt.len() == 1 {
match Gtdt::new(gtdt_sdt[0]) {
Some(gtdt) => gtdt,
None => {
log::warn!("Failed to parse GTDT");
return;
}
}
} else {
log::warn!("Unable to find GTDT");
return;
};
let gsiv = gtdt.non_secure_el1_timer_gsiv;
log::info!("generic_timer gsiv = {}", gsiv);
let mut timer = GenericTimer {
clk_freq: 0,
reload_count: 0,
};
timer.init();
register_irq(gsiv, Box::new(timer));
unsafe { IRQ_CHIP.irq_enable(gsiv as u32) };
}
pub fn new(sdt: &'static Sdt) -> Option<&'static Gtdt> {
if &sdt.signature == b"GTDT" && sdt.length as usize >= mem::size_of::<Gtdt>() {
Some(unsafe { &*((sdt as *const Sdt) as *const Gtdt) })
} else {
None
}
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
use super::Madt;
pub(super) fn init(madt: Madt) {
for madt_entry in madt.iter() {
println!(" {:#x?}", madt_entry);
}
log::warn!("MADT not yet handled on this platform");
}