Merge pull request #48 from CWood1/master

Fully implemented AML parser, some amendments to ACPI infrastructure
This commit is contained in:
Jeremy Soller
2017-08-31 17:53:16 -06:00
committed by GitHub
27 changed files with 4575 additions and 2207 deletions

View File

@@ -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)
}
}

View File

@@ -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

View File

@@ -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)
}

View File

@@ -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
})
}

View File

@@ -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
View 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
})
}
}

View File

@@ -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);
}
};
}

View File

@@ -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;

View File

@@ -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)
}

View File

@@ -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

View File

@@ -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) };

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}

View File

@@ -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) };

View File

@@ -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
View 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
}
}
}

View File

@@ -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
View 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;
}
}

View File

@@ -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
}
}

View File

@@ -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
}
})
}
}

View File

@@ -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);
}

View File

@@ -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();
}

View File

@@ -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();

View File

@@ -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() {

View File

@@ -19,6 +19,7 @@
#![feature(never_type)]
#![feature(thread_local)]
#![feature(unique)]
#![feature(conservative_impl_trait)]
#![no_std]
extern crate alloc_kernel as allocator;