Verified Commit bea67476 authored by 4lDO2's avatar 4lDO2 🖖
Browse files

Move all AML code to userspace.

Currently, there are some things that need to be set up by userspace
that the kernel previously did. These include telling firmware when the
I/O APIC is used, and most importantly, shutting down the system.

The former is not particularly important, but for the latter I think
that we could implement this using a "shutdown pipe". Essentially it
will be a file that triggers an event shutting down, which would be used
to notify to acpid that the kernel is requesting a shutdown.
parent 28d1d7e8
......@@ -168,7 +168,7 @@ dependencies = [
[[package]]
name = "redox_syscall"
version = "0.2.8"
version = "0.2.6"
dependencies = [
"bitflags",
]
......
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)
}