Merge pull request #48 from CWood1/master
Fully implemented AML parser, some amendments to ACPI infrastructure
This commit is contained in:
@@ -1,131 +1,134 @@
|
||||
use collections::vec::Vec;
|
||||
use collections::string::String;
|
||||
|
||||
use super::{AmlInternalError, AmlExecutable, AmlValue, AmlNamespace, get_namespace_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,
|
||||
DefBuffer, DefPackage, DefVarPackage};
|
||||
use super::termlist::{parse_term_arg, TermArg};
|
||||
use super::namestring::{parse_super_name, SuperName};
|
||||
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;
|
||||
|
||||
#[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)
|
||||
}
|
||||
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 DataObj {
|
||||
fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option<AmlValue> {
|
||||
match *self {
|
||||
DataObj::ComputationalData(ref cd) => cd.execute(namespace, scope),
|
||||
DataObj::DefPackage(ref pkg) => pkg.execute(namespace, scope),
|
||||
_ => Some(AmlValue::Integer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AmlExecutable for ComputationalData {
|
||||
fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option<AmlValue> {
|
||||
match *self {
|
||||
ComputationalData::Byte(b) => Some(AmlValue::IntegerConstant(b as u64)),
|
||||
ComputationalData::Word(w) => Some(AmlValue::IntegerConstant(w as u64)),
|
||||
ComputationalData::DWord(d) => Some(AmlValue::IntegerConstant(d as u64)),
|
||||
ComputationalData::QWord(q) => Some(AmlValue::IntegerConstant(q as u64)),
|
||||
ComputationalData::Zero => Some(AmlValue::IntegerConstant(0)),
|
||||
ComputationalData::One => Some(AmlValue::IntegerConstant(1)),
|
||||
ComputationalData::Ones => Some(AmlValue::IntegerConstant(0xFFFFFFFFFFFFFFFF)),
|
||||
_ => Some(AmlValue::Integer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_data_obj(data: &[u8]) -> Result<(DataObj, usize), AmlInternalError> {
|
||||
|
||||
parser_selector! {
|
||||
data,
|
||||
parser_wrap!(DataObj::ComputationalData, parse_computational_data),
|
||||
parser_wrap!(DataObj::DefPackage, parse_def_package),
|
||||
parser_wrap!(DataObj::DefVarPackage, parse_def_var_package)
|
||||
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)
|
||||
}
|
||||
|
||||
pub fn parse_arg_obj(data: &[u8]) -> Result<(ArgObj, usize), AmlInternalError> {
|
||||
match data[0] {
|
||||
0x68 ... 0x6E => Ok((ArgObj(data[0] - 0x68), 1 as usize)),
|
||||
_ => Err(AmlInternalError::AmlInvalidOpCode)
|
||||
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_local_obj(data: &[u8]) -> Result<(LocalObj, 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] {
|
||||
0x60 ... 0x67 => Ok((LocalObj(data[0] - 0x60), 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)
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_computational_data(data: &[u8]) -> Result<(ComputationalData, 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] {
|
||||
0x0A => Ok((ComputationalData::Byte(data[1]), 2 as usize)),
|
||||
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 as usize
|
||||
})
|
||||
}
|
||||
|
||||
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((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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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(Debug, Clone)]
|
||||
#[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(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)
|
||||
}
|
||||
}
|
||||
|
||||
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 mut 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 AmlNamespace {
|
||||
pub fn new_namespace(name: &String) -> AmlNamespace {
|
||||
AmlNamespace {
|
||||
name: name.clone(),
|
||||
contents: AmlNamespaceContents::Namespace(vec!())
|
||||
impl Method {
|
||||
pub fn execute(&self, scope: String, parameters: Vec<AmlValue>) -> AmlValue {
|
||||
let mut ctx = AmlExecutionContext::new(scope);
|
||||
ctx.init_arg_vars(parameters);
|
||||
|
||||
parse_term_list(&self.term_list[..], &mut ctx);
|
||||
ctx.clean_namespace();
|
||||
|
||||
match ctx.state {
|
||||
ExecutionState::RETURN(v) => v,
|
||||
_ => AmlValue::IntegerConstant(0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_str(&self, scope_str: &str) -> Option<AmlValue> {
|
||||
let scope_string = String::from_str(scope_str).unwrap();
|
||||
self.find(scope_string)
|
||||
}
|
||||
|
||||
pub fn find(&self, scope_string: String) -> Option<AmlValue> {
|
||||
if scope_string.len() == 0 {
|
||||
match self.contents {
|
||||
AmlNamespaceContents::Value(ref v) => return Some(v.clone()),
|
||||
_ => return None
|
||||
}
|
||||
}
|
||||
|
||||
let mut scope_string = scope_string.clone();
|
||||
|
||||
if scope_string.starts_with("\\") {
|
||||
if self.name != "\\" {
|
||||
return None;
|
||||
}
|
||||
|
||||
scope_string.remove(0);
|
||||
}
|
||||
|
||||
if scope_string.starts_with(".") {
|
||||
scope_string.remove(0);
|
||||
}
|
||||
|
||||
if scope_string.len() == 0 {
|
||||
match self.contents {
|
||||
AmlNamespaceContents::Value(ref v) => return Some(v.clone()),
|
||||
_ => return None
|
||||
}
|
||||
}
|
||||
|
||||
let (current, nextset) = match scope_string.find(".") {
|
||||
Some(s) => {
|
||||
let (x, mut y) = scope_string.split_at(s);
|
||||
y = &y[1..];
|
||||
|
||||
(String::from_str(x).unwrap(), String::from_str(y).unwrap())
|
||||
},
|
||||
None => if scope_string.len() <= 4 {
|
||||
(scope_string, String::from_str("").unwrap())
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
match self.contents {
|
||||
AmlNamespaceContents::Namespace(ref namespace) => {
|
||||
// TODO: Remove this while loop here, there has to be a more elegant way
|
||||
let mut current_index = 0;
|
||||
while current_index < namespace.len() {
|
||||
match namespace[current_index] {
|
||||
AmlNamespaceContents::SubNamespace(ref ns) => if ns.name == current {
|
||||
return ns.find(nextset);
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
|
||||
current_index += 1;
|
||||
}
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn push(&mut self, val: AmlNamespaceContents) {
|
||||
match self.contents {
|
||||
AmlNamespaceContents::Namespace(ref mut v) => v.push(val),
|
||||
_ => () // TODO: Error this
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_to(&mut self, scope_string: String, contents: AmlNamespaceContents) {
|
||||
if scope_string.len() == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut scope_string = scope_string.clone();
|
||||
|
||||
if scope_string.starts_with("\\") {
|
||||
if self.name != "\\" {
|
||||
return;
|
||||
// TODO: Error this
|
||||
}
|
||||
|
||||
scope_string.remove(0);
|
||||
}
|
||||
|
||||
if scope_string.starts_with(".") {
|
||||
scope_string.remove(0);
|
||||
}
|
||||
|
||||
if scope_string.len() == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let (current, nextset) = match scope_string.find(".") {
|
||||
Some(s) => {
|
||||
let (x, mut y) = scope_string.split_at(s);
|
||||
y = &y[1..];
|
||||
|
||||
(String::from_str(x).unwrap(), String::from_str(y).unwrap())
|
||||
},
|
||||
None => if scope_string.len() <= 4 {
|
||||
(scope_string, String::from_str("").unwrap())
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
match self.contents {
|
||||
AmlNamespaceContents::Namespace(ref mut namespace) => {
|
||||
// TODO: Remove this while loop here, there has to be a more elegant way
|
||||
let mut current_index = 0;
|
||||
while current_index < namespace.len() {
|
||||
match namespace[current_index] {
|
||||
AmlNamespaceContents::SubNamespace(ref mut ns) => if ns.name == current {
|
||||
ns.push_to(nextset, contents);
|
||||
return;
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
|
||||
current_index += 1;
|
||||
}
|
||||
|
||||
let mut next = AmlNamespace {
|
||||
name: current,
|
||||
contents: contents
|
||||
};
|
||||
|
||||
namespace.push(AmlNamespaceContents::SubNamespace(Box::new(next)));
|
||||
}
|
||||
_ => () // TODO: Error this
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_subordinate_namespace(&mut self, scope_string: String) {
|
||||
self.push_to(scope_string, AmlNamespaceContents::Namespace(vec!()));
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -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};
|
||||
use super::termlist::parse_term_list;
|
||||
use super::dataobj::parse_data_ref_obj;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum NamespaceModifier {
|
||||
Name {
|
||||
name: String,
|
||||
data_ref_obj: DataRefObj
|
||||
},
|
||||
Scope {
|
||||
name: String,
|
||||
terms: Vec<TermObj>
|
||||
},
|
||||
Alias {
|
||||
source_name: String,
|
||||
alias_name: String
|
||||
},
|
||||
DeferredLoad(Vec<u8>)
|
||||
}
|
||||
|
||||
impl AmlExecutable for NamespaceModifier {
|
||||
fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option<AmlValue> {
|
||||
match *self {
|
||||
NamespaceModifier::Scope { name: ref name, terms: ref terms } => {
|
||||
let local_scope_string = get_namespace_string(scope, name.clone());
|
||||
namespace.push_subordinate_namespace(local_scope_string.clone());
|
||||
|
||||
terms.execute(namespace, local_scope_string);
|
||||
},
|
||||
NamespaceModifier::Name { ref name, ref data_ref_obj } => {
|
||||
let local_scope_string = get_namespace_string(scope.clone(), name.clone());
|
||||
let dro = match data_ref_obj.execute(namespace, scope) {
|
||||
Some(s) => s,
|
||||
None => return None
|
||||
};
|
||||
|
||||
namespace.push_to(local_scope_string, AmlNamespaceContents::Value(dro));
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
|
||||
None
|
||||
pub fn parse_namespace_modifier(data: &[u8],
|
||||
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..])?;
|
||||
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)?;
|
||||
|
||||
Ok((NamespaceModifier::Alias {source_name, alias_name}, 1 + source_name_len + alias_name_len))
|
||||
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 = 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)?;
|
||||
|
||||
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))
|
||||
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)
|
||||
};
|
||||
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((NamespaceModifier::Scope {name, terms}, pkg_length + 1))
|
||||
Ok(AmlParseType {
|
||||
val: AmlValue::None,
|
||||
len: 1 + pkg_length
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,27 +1,22 @@
|
||||
use collections::vec::Vec;
|
||||
use collections::string::String;
|
||||
|
||||
use super::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;
|
||||
|
||||
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> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
553
src/acpi/aml/parser.rs
Normal file
553
src/acpi/aml/parser.rs
Normal file
@@ -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
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
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
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl AmlExecutable for TermArg {
|
||||
fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option<AmlValue> {
|
||||
match *self {
|
||||
TermArg::LocalObj(ref l) => Some(AmlValue::Integer),
|
||||
TermArg::DataObj(ref d) => d.execute(namespace, scope),
|
||||
TermArg::ArgObj(ref a) => Some(AmlValue::Integer),
|
||||
TermArg::Type2Opcode(ref o) => Some(AmlValue::Integer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AmlExecutable for TermObj {
|
||||
fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option<AmlValue> {
|
||||
match *self {
|
||||
TermObj::NamespaceModifier(ref res) => res.execute(namespace, scope.clone()),
|
||||
TermObj::NamedObj(ref res) => res.execute(namespace, scope.clone()),
|
||||
TermObj::Type1Opcode(ref res) => res.execute(namespace, scope.clone()),
|
||||
TermObj::Type2Opcode(ref res) => res.execute(namespace, scope.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_term_list(data: &[u8]) -> Result<Vec<TermObj>, AmlInternalError> {
|
||||
let mut terms: Vec<TermObj> = vec!();
|
||||
|
||||
let mut current_offset: usize = 0;
|
||||
|
||||
while current_offset < data.len() {
|
||||
let (res, len) = parse_term_obj(&data[current_offset..])?;
|
||||
terms.push(res);
|
||||
current_offset += len;
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -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};
|
||||
use super::termlist::{parse_term_arg, parse_term_list};
|
||||
use super::namestring::{parse_name_string, parse_super_name};
|
||||
|
||||
#[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>)
|
||||
}
|
||||
use time::monotonic;
|
||||
|
||||
impl AmlExecutable for Type1OpCode {
|
||||
fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option<AmlValue> {
|
||||
None
|
||||
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
|
||||
})
|
||||
}
|
||||
|
||||
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(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 as usize
|
||||
})
|
||||
}
|
||||
|
||||
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 as usize
|
||||
})
|
||||
}
|
||||
|
||||
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 as usize
|
||||
})
|
||||
}
|
||||
|
||||
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, fatal_arg_len) = parse_term_arg(&data[5..])?;
|
||||
let fatal_code: u16 = (data[3] as u16) + ((data[4] as u16) << 8);
|
||||
let fatal_arg = parse_term_arg(&data[5..], ctx)?;
|
||||
|
||||
Ok((Type1OpCode::DefFatal {fatal_type, fatal_code, fatal_arg}, fatal_arg_len + 5))
|
||||
Err(AmlError::AmlFatalError(fatal_type, fatal_code, fatal_arg.val))
|
||||
}
|
||||
|
||||
fn parse_def_load(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> {
|
||||
if data[0] != 0x5B || data[1] != 0x20 {
|
||||
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, name_len) = parse_name_string(&data[2..])?;
|
||||
let (ddb_handle_object, ddb_handle_object_len) = parse_super_name(&data[2 + name_len..])?;
|
||||
let name = parse_name_string(&data[2..], ctx)?;
|
||||
let ddb_handle_object = parse_super_name(&data[2 + name.len..], ctx)?;
|
||||
|
||||
Ok((Type1OpCode::DefLoad {name, ddb_handle_object}, 2 + name_len + ddb_handle_object_len))
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_def_notify(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> {
|
||||
if data[0] != 0x86 {
|
||||
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[1..])?;
|
||||
let (value, value_len) = parse_term_arg(&data[1 + object_len..])?;
|
||||
let object = parse_super_name(&data[1..], ctx)?;
|
||||
let value = parse_term_arg(&data[1 + object.len..], ctx)?;
|
||||
|
||||
Ok((Type1OpCode::DefNotify {object, value}, 1 + object_len + value_len))
|
||||
}
|
||||
let number = value.val.get_as_integer()? as u8;
|
||||
|
||||
fn parse_def_release(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> {
|
||||
if data[0] != 0x5B || data[1] != 0x27 {
|
||||
return Err(AmlInternalError::AmlInvalidOpCode);
|
||||
}
|
||||
|
||||
let (object, object_len) = parse_super_name(&data[2..])?;
|
||||
|
||||
Ok((Type1OpCode::DefRelease(object), 2 + object_len))
|
||||
}
|
||||
|
||||
fn parse_def_reset(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> {
|
||||
if data[0] != 0x5B || data[1] != 0x26 {
|
||||
return Err(AmlInternalError::AmlInvalidOpCode);
|
||||
}
|
||||
|
||||
let (object, object_len) = parse_super_name(&data[2..])?;
|
||||
|
||||
Ok((Type1OpCode::DefReset(object), 2 + object_len))
|
||||
}
|
||||
|
||||
fn parse_def_signal(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> {
|
||||
if data[0] != 0x5B || data[1] != 0x24 {
|
||||
return Err(AmlInternalError::AmlInvalidOpCode);
|
||||
}
|
||||
|
||||
let (object, object_len) = parse_super_name(&data[2..])?;
|
||||
|
||||
Ok((Type1OpCode::DefSignal(object), 2 + object_len))
|
||||
}
|
||||
|
||||
fn parse_def_sleep(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> {
|
||||
if data[0] != 0x5B || data[1] != 0x22 {
|
||||
return Err(AmlInternalError::AmlInvalidOpCode);
|
||||
}
|
||||
|
||||
let (time, time_len) = parse_term_arg(&data[2..])?;
|
||||
|
||||
Ok((Type1OpCode::DefSleep(time), 2 + time_len))
|
||||
}
|
||||
|
||||
fn parse_def_stall(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> {
|
||||
if data[0] != 0x5B || data[1] != 0x21 {
|
||||
return Err(AmlInternalError::AmlInvalidOpCode);
|
||||
}
|
||||
|
||||
let (time, time_len) = parse_term_arg(&data[2..])?;
|
||||
|
||||
Ok((Type1OpCode::DefStall(time), 2 + time_len))
|
||||
}
|
||||
|
||||
fn parse_def_unload(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> {
|
||||
if data[0] != 0x5B || data[1] != 0x2A {
|
||||
return Err(AmlInternalError::AmlInvalidOpCode);
|
||||
}
|
||||
|
||||
let (object, object_len) = parse_super_name(&data[2..])?;
|
||||
|
||||
Ok((Type1OpCode::DefUnload(object), 2 + object_len))
|
||||
}
|
||||
|
||||
fn parse_def_if_else(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> {
|
||||
if data[0] != 0xA0 {
|
||||
return Err(AmlInternalError::AmlInvalidOpCode);
|
||||
}
|
||||
|
||||
let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?;
|
||||
|
||||
let if_block = match parse_term_arg(&data[1 + pkg_length_len..]) {
|
||||
Ok((predicate, predicate_len)) => {
|
||||
match parse_term_list(&data[1 + pkg_length_len + predicate_len .. 1 + pkg_length]) {
|
||||
Ok(if_block) => IfBlock::If {predicate, if_block},
|
||||
Err(AmlInternalError::AmlDeferredLoad) =>
|
||||
IfBlock::DeferredLoad(data[0 .. 1 + pkg_length].to_vec()),
|
||||
Err(e) => return Err(e)
|
||||
match ctx.get(object.val)? {
|
||||
AmlValue::Device(d) => {
|
||||
if let Some(methods) = d.notify_methods.get(&number) {
|
||||
for method in methods {
|
||||
method();
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(AmlInternalError::AmlDeferredLoad) =>
|
||||
IfBlock::DeferredLoad(data[0 .. 1 + pkg_length].to_vec()),
|
||||
Err(e) => return Err(e)
|
||||
};
|
||||
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 (else_block, else_block_len) = parse_def_else(&data[1 + pkg_length..])?;
|
||||
|
||||
return Ok((Type1OpCode::DefIfElse {if_block, else_block},
|
||||
pkg_length + else_block_len + 1));
|
||||
Ok(AmlParseType {
|
||||
val: AmlValue::None,
|
||||
len: 1 + object.len + value.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_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_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()?;
|
||||
|
||||
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 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
|
||||
})
|
||||
}
|
||||
|
||||
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(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 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;
|
||||
}
|
||||
}
|
||||
|
||||
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 as usize
|
||||
})
|
||||
}
|
||||
|
||||
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 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)?;
|
||||
|
||||
fn parse_def_return(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> {
|
||||
if data[0] != 0xA4 {
|
||||
return Err(AmlInternalError::AmlInvalidOpCode);
|
||||
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
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let (arg_object, arg_object_len) = parse_term_arg(&data[1..])?;
|
||||
|
||||
Ok((Type1OpCode::DefReturn(arg_object), 1 + arg_object_len))
|
||||
|
||||
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 as usize
|
||||
})
|
||||
}
|
||||
|
||||
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
|
||||
})
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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) };
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
138
src/acpi/madt.rs
138
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) };
|
||||
|
||||
396
src/acpi/mod.rs
396
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);
|
||||
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 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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
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 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)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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: Option<Fadt>,
|
||||
pub namespace: Option<AmlNamespace>,
|
||||
pub hpet: Option<Hpet>
|
||||
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: 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]
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
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 static ACPI_TABLE: Acpi = Acpi {
|
||||
fadt: RwLock::new(None),
|
||||
namespace: RwLock::new(None),
|
||||
hpet: RwLock::new(None),
|
||||
next_ctx: RwLock::new(0),
|
||||
};
|
||||
|
||||
57
src/acpi/rsdp.rs
Normal file
57
src/acpi/rsdp.rs
Normal file
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
28
src/acpi/rxsdt.rs
Normal file
28
src/acpi/rxsdt.rs
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
volatile_store(self.general_config_addr as *mut u64, enable_word);
|
||||
// Enable interrupts from the HPET
|
||||
|
||||
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);
|
||||
|
||||
volatile_store(self.t0_comparator_addr as *mut u64, clk_periods_per_kernel_tick);
|
||||
}
|
||||
|
||||
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) }
|
||||
}
|
||||
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;
|
||||
|
||||
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 clk_periods_per_kernel_tick: u64 = desired_fs_period / counter_clk_period_fs;
|
||||
|
||||
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
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#![feature(never_type)]
|
||||
#![feature(thread_local)]
|
||||
#![feature(unique)]
|
||||
#![feature(conservative_impl_trait)]
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc_kernel as allocator;
|
||||
|
||||
Reference in New Issue
Block a user