Merge branch 'outsource-most-acpi' into 'master'

Move most of ACPI to userspace

See merge request redox-os/kernel!175
This commit is contained in:
Jeremy Soller
2021-05-06 18:36:06 +00:00
28 changed files with 359 additions and 6124 deletions

View File

@@ -1,187 +0,0 @@
use alloc::vec::Vec;
use alloc::string::String;
use super::AmlError;
use super::parser::{ AmlParseType, ParseResult, AmlExecutionContext, ExecutionState };
use super::namespace::{ AmlValue, ObjectReference };
use super::type2opcode::{parse_def_buffer, parse_def_package, parse_def_var_package};
use super::termlist::parse_term_arg;
use super::namestring::parse_super_name;
pub fn parse_data_obj(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_selector! {
data, ctx,
parse_computational_data,
parse_def_package,
parse_def_var_package
};
Err(AmlError::AmlInvalidOpCode)
}
pub fn parse_data_ref_obj(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_selector! {
data, ctx,
parse_data_obj,
parse_term_arg
};
match parse_super_name(data, ctx) {
Ok(res) => match res.val {
AmlValue::String(s) => Ok(AmlParseType {
val: AmlValue::ObjectReference(ObjectReference::Object(s)),
len: res.len
}),
_ => Ok(res)
},
Err(e) => Err(e)
}
}
pub fn parse_arg_obj(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
match data[0] {
0x68 ..= 0x6E => Ok(AmlParseType {
val: AmlValue::ObjectReference(ObjectReference::ArgObj(data[0] - 0x68)),
len: 1 as usize
}),
_ => Err(AmlError::AmlInvalidOpCode)
}
}
pub fn parse_local_obj(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
match data[0] {
0x68 ..= 0x6E => Ok(AmlParseType {
val: AmlValue::ObjectReference(ObjectReference::LocalObj(data[0] - 0x60)),
len: 1 as usize
}),
_ => Err(AmlError::AmlInvalidOpCode)
}
}
fn parse_computational_data(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
match data[0] {
0x0A => Ok(AmlParseType {
val: AmlValue::Integer(data[1] as u64),
len: 2 as usize
}),
0x0B => {
let res = (data[1] as u16) +
((data[2] as u16) << 8);
Ok(AmlParseType {
val: AmlValue::Integer(res as u64),
len: 3 as usize
})
},
0x0C => {
let res = (data[1] as u32) +
((data[2] as u32) << 8) +
((data[3] as u32) << 16) +
((data[4] as u32) << 24);
Ok(AmlParseType {
val: AmlValue::Integer(res as u64),
len: 5 as usize
})
},
0x0D => {
let mut cur_ptr: usize = 1;
let mut cur_string: Vec<u8> = vec!();
while data[cur_ptr] != 0x00 {
cur_string.push(data[cur_ptr]);
cur_ptr += 1;
}
match String::from_utf8(cur_string) {
Ok(s) => Ok(AmlParseType {
val: AmlValue::String(s.clone()),
len: s.clone().len() + 2
}),
Err(_) => Err(AmlError::AmlParseError("String data - invalid string"))
}
},
0x0E => {
let res = (data[1] as u64) +
((data[2] as u64) << 8) +
((data[3] as u64) << 16) +
((data[4] as u64) << 24) +
((data[5] as u64) << 32) +
((data[6] as u64) << 40) +
((data[7] as u64) << 48) +
((data[8] as u64) << 56);
Ok(AmlParseType {
val: AmlValue::Integer(res as u64),
len: 9 as usize
})
},
0x00 => Ok(AmlParseType {
val: AmlValue::IntegerConstant(0 as u64),
len: 1 as usize
}),
0x01 => Ok(AmlParseType {
val: AmlValue::IntegerConstant(1 as u64),
len: 1 as usize
}),
0x5B => if data[1] == 0x30 {
Ok(AmlParseType {
val: AmlValue::IntegerConstant(2017_0630 as u64),
len: 2 as usize
})
} else {
Err(AmlError::AmlInvalidOpCode)
},
0xFF => Ok(AmlParseType {
val: AmlValue::IntegerConstant(0xFFFF_FFFF_FFFF_FFFF),
len: 1 as usize
}),
_ => parse_def_buffer(data, ctx)
}
}

View File

@@ -1,57 +0,0 @@
//! # AML
//! Code to parse and execute AML tables
use alloc::string::String;
use alloc::vec::Vec;
use core::str::FromStr;
use super::sdt::Sdt;
#[macro_use]
mod parsermacros;
mod namespace;
mod termlist;
mod namespacemodifier;
mod pkglength;
mod namestring;
mod namedobj;
mod dataobj;
mod type1opcode;
mod type2opcode;
mod parser;
use self::parser::AmlExecutionContext;
use self::termlist::parse_term_list;
pub use self::namespace::AmlValue;
#[derive(Debug)]
pub enum AmlError {
AmlParseError(&'static str),
AmlInvalidOpCode,
AmlValueError,
AmlDeferredLoad,
AmlFatalError(u8, u16, AmlValue),
AmlHardFatal
}
pub fn parse_aml_table(sdt: &Sdt) -> Result<Vec<String>, AmlError> {
parse_aml_with_scope(sdt, String::from_str("\\").unwrap())
}
pub fn parse_aml_with_scope(sdt: &Sdt, scope: String) -> Result<Vec<String>, AmlError> {
let data = sdt.data();
let mut ctx = AmlExecutionContext::new(scope);
parse_term_list(data, &mut ctx)?;
Ok(ctx.namespace_delta)
}
pub fn is_aml_table(sdt: &Sdt) -> bool {
if &sdt.signature == b"DSDT" || &sdt.signature == b"SSDT" {
true
} else {
false
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,490 +0,0 @@
use alloc::boxed::Box;
use alloc::string::String;
use alloc::string::ToString;
use alloc::vec::Vec;
use alloc::collections::BTreeMap;
use core::fmt::Debug;
use core::str::FromStr;
use super::termlist::parse_term_list;
use super::namedobj::{ RegionSpace, FieldFlags };
use super::parser::{AmlExecutionContext, ExecutionState};
use super::AmlError;
use crate::acpi::{SdtSignature, get_signature_from_index, get_index_from_signature};
#[derive(Clone, Debug)]
pub enum FieldSelector {
Region(String),
Bank {
region: String,
bank_register: String,
bank_selector: Box<AmlValue>
},
Index {
index_selector: String,
data_selector: String
}
}
#[derive(Clone, Debug)]
pub enum ObjectReference {
ArgObj(u8),
LocalObj(u8),
Object(String),
Index(Box<AmlValue>, Box<AmlValue>)
}
#[derive(Clone, Debug)]
pub struct Method {
pub arg_count: u8,
pub serialized: bool,
pub sync_level: u8,
pub term_list: Vec<u8>
}
#[derive(Clone, Debug)]
pub struct BufferField {
pub source_buf: Box<AmlValue>,
pub index: Box<AmlValue>,
pub length: Box<AmlValue>
}
#[derive(Clone, Debug)]
pub struct FieldUnit {
pub selector: FieldSelector,
pub connection: Box<AmlValue>,
pub flags: FieldFlags,
pub offset: usize,
pub length: usize
}
#[derive(Clone, Debug)]
pub struct Device {
pub obj_list: Vec<String>,
pub notify_methods: BTreeMap<u8, Vec<fn()>>
}
#[derive(Clone, Debug)]
pub struct ThermalZone {
pub obj_list: Vec<String>,
pub notify_methods: BTreeMap<u8, Vec<fn()>>
}
#[derive(Clone, Debug)]
pub struct Processor {
pub proc_id: u8,
pub p_blk: Option<u32>,
pub obj_list: Vec<String>,
pub notify_methods: BTreeMap<u8, Vec<fn()>>
}
#[derive(Clone, Debug)]
pub struct OperationRegion {
pub region: RegionSpace,
pub offset: Box<AmlValue>,
pub len: Box<AmlValue>,
pub accessor: Accessor,
pub accessed_by: Option<u64>
}
#[derive(Clone, Debug)]
pub struct PowerResource {
pub system_level: u8,
pub resource_order: u16,
pub obj_list: Vec<String>
}
#[derive(Debug)]
pub struct Accessor {
pub read: fn(usize) -> u64,
pub write: fn(usize, u64)
}
impl Clone for Accessor {
fn clone(&self) -> Accessor {
Accessor {
read: (*self).read,
write: (*self).write
}
}
}
#[derive(Clone, Debug)]
pub enum AmlValue {
None,
Uninitialized,
Alias(String),
Buffer(Vec<u8>),
BufferField(BufferField),
DDBHandle((Vec<String>, SdtSignature)),
DebugObject,
Device(Device),
Event(u64),
FieldUnit(FieldUnit),
Integer(u64),
IntegerConstant(u64),
Method(Method),
Mutex((u8, Option<u64>)),
ObjectReference(ObjectReference),
OperationRegion(OperationRegion),
Package(Vec<AmlValue>),
String(String),
PowerResource(PowerResource),
Processor(Processor),
RawDataBuffer(Vec<u8>),
ThermalZone(ThermalZone)
}
impl AmlValue {
pub fn get_type_string(&self) -> String {
match *self {
AmlValue::Uninitialized => String::from_str("[Uninitialized Object]").unwrap(),
AmlValue::Integer(_) => String::from_str("[Integer]").unwrap(),
AmlValue::String(_) => String::from_str("[String]").unwrap(),
AmlValue::Buffer(_) => String::from_str("[Buffer]").unwrap(),
AmlValue::Package(_) => String::from_str("[Package]").unwrap(),
AmlValue::FieldUnit(_) => String::from_str("[Field]").unwrap(),
AmlValue::Device(_) => String::from_str("[Device]").unwrap(),
AmlValue::Event(_) => String::from_str("[Event]").unwrap(),
AmlValue::Method(_) => String::from_str("[Control Method]").unwrap(),
AmlValue::Mutex(_) => String::from_str("[Mutex]").unwrap(),
AmlValue::OperationRegion(_) => String::from_str("[Operation Region]").unwrap(),
AmlValue::PowerResource(_) => String::from_str("[Power Resource]").unwrap(),
AmlValue::Processor(_) => String::from_str("[Processor]").unwrap(),
AmlValue::ThermalZone(_) => String::from_str("[Thermal Zone]").unwrap(),
AmlValue::BufferField(_) => String::from_str("[Buffer Field]").unwrap(),
AmlValue::DDBHandle(_) => String::from_str("[DDB Handle]").unwrap(),
AmlValue::DebugObject => String::from_str("[Debug Object]").unwrap(),
_ => String::new()
}
}
pub fn get_as_type(&self, t: AmlValue) -> Result<AmlValue, AmlError> {
match t {
AmlValue::None => Ok(AmlValue::None),
AmlValue::Uninitialized => Ok(self.clone()),
AmlValue::Alias(_) => match *self {
AmlValue::Alias(_) => Ok(self.clone()),
_ => Err(AmlError::AmlValueError)
},
AmlValue::Buffer(_) => Ok(AmlValue::Buffer(self.get_as_buffer()?)),
AmlValue::BufferField(_) => Ok(AmlValue::BufferField(self.get_as_buffer_field()?)),
AmlValue::DDBHandle(_) => Ok(AmlValue::DDBHandle(self.get_as_ddb_handle()?)),
AmlValue::DebugObject => match *self {
AmlValue::DebugObject => Ok(self.clone()),
_ => Err(AmlError::AmlValueError)
},
AmlValue::Device(_) => Ok(AmlValue::Device(self.get_as_device()?)),
AmlValue::Event(_) => Ok(AmlValue::Event(self.get_as_event()?)),
AmlValue::FieldUnit(_) => Ok(AmlValue::FieldUnit(self.get_as_field_unit()?)),
AmlValue::Integer(_) => Ok(AmlValue::Integer(self.get_as_integer()?)),
AmlValue::IntegerConstant(_) => Ok(AmlValue::IntegerConstant(self.get_as_integer_constant()?)),
AmlValue::Method(_) => Ok(AmlValue::Method(self.get_as_method()?)),
AmlValue::Mutex(_) => Ok(AmlValue::Mutex(self.get_as_mutex()?)),
AmlValue::ObjectReference(_) => Ok(AmlValue::ObjectReference(self.get_as_object_reference()?)),
AmlValue::OperationRegion(_) => match *self {
AmlValue::OperationRegion(_) => Ok(self.clone()),
_ => Err(AmlError::AmlValueError)
},
AmlValue::Package(_) => Ok(AmlValue::Package(self.get_as_package()?)),
AmlValue::String(_) => Ok(AmlValue::String(self.get_as_string()?)),
AmlValue::PowerResource(_) => Ok(AmlValue::PowerResource(self.get_as_power_resource()?)),
AmlValue::Processor(_) => Ok(AmlValue::Processor(self.get_as_processor()?)),
AmlValue::RawDataBuffer(_) => Ok(AmlValue::RawDataBuffer(self.get_as_raw_data_buffer()?)),
AmlValue::ThermalZone(_) => Ok(AmlValue::ThermalZone(self.get_as_thermal_zone()?))
}
}
pub fn get_as_buffer(&self) -> Result<Vec<u8>, AmlError> {
match *self {
AmlValue::Buffer(ref b) => Ok(b.clone()),
AmlValue::Integer(ref i) => {
let mut v: Vec<u8> = vec!();
let mut i = i.clone();
while i != 0 {
v.push((i & 0xFF) as u8);
i >>= 8;
}
while v.len() < 8 {
v.push(0);
}
Ok(v)
},
AmlValue::String(ref s) => {
Ok(s.clone().into_bytes())
},
AmlValue::BufferField(ref b) => {
let buf = b.source_buf.get_as_buffer()?;
let idx = b.index.get_as_integer()? as usize;
let len = b.length.get_as_integer()? as usize;
if idx + len > buf.len() {
return Err(AmlError::AmlValueError);
}
Ok(buf[idx .. idx + len].to_vec())
},
_ => Err(AmlError::AmlValueError)
}
}
pub fn get_as_buffer_field(&self) -> Result<BufferField, AmlError> {
match *self {
AmlValue::BufferField(ref b) => Ok(b.clone()),
_ => {
let raw_buf = self.get_as_buffer()?;
let buf = Box::new(AmlValue::Buffer(raw_buf.clone()));
let idx = Box::new(AmlValue::IntegerConstant(0));
let len = Box::new(AmlValue::Integer(raw_buf.len() as u64));
Ok(BufferField {
source_buf: buf,
index: idx,
length: len
})
}
}
}
pub fn get_as_ddb_handle(&self) -> Result<(Vec<String>, SdtSignature), AmlError> {
match *self {
AmlValue::DDBHandle(ref v) => Ok(v.clone()),
AmlValue::Integer(i) => if let Some(sig) = get_signature_from_index(i as usize) {
Ok((vec!(), sig))
} else {
Err(AmlError::AmlValueError)
},
_ => Err(AmlError::AmlValueError)
}
}
pub fn get_as_device(&self) -> Result<Device, AmlError> {
match *self {
AmlValue::Device(ref s) => Ok(s.clone()),
_ => Err(AmlError::AmlValueError)
}
}
pub fn get_as_event(&self) -> Result<u64, AmlError> {
match *self {
AmlValue::Event(ref e) => Ok(e.clone()),
_ => Err(AmlError::AmlValueError)
}
}
pub fn get_as_field_unit(&self) -> Result<FieldUnit, AmlError> {
match *self {
AmlValue::FieldUnit(ref e) => Ok(e.clone()),
_ => Err(AmlError::AmlValueError)
}
}
pub fn get_as_integer(&self) -> Result<u64, AmlError> {
match *self {
AmlValue::IntegerConstant(ref i) => Ok(i.clone()),
AmlValue::Integer(ref i) => Ok(i.clone()),
AmlValue::Buffer(ref b) => {
let mut b = b.clone();
if b.len() > 8 {
return Err(AmlError::AmlValueError);
}
let mut i: u64 = 0;
while b.len() > 0 {
i <<= 8;
i += b.pop().expect("Won't happen") as u64;
}
Ok(i)
},
AmlValue::BufferField(_) => {
let mut b = self.get_as_buffer()?;
if b.len() > 8 {
return Err(AmlError::AmlValueError);
}
let mut i: u64 = 0;
while b.len() > 0 {
i <<= 8;
i += b.pop().expect("Won't happen") as u64;
}
Ok(i)
},
AmlValue::DDBHandle(ref v) => if let Some(idx) = get_index_from_signature(v.1.clone()) {
Ok(idx as u64)
} else {
Err(AmlError::AmlValueError)
},
AmlValue::String(ref s) => {
let s = s.clone()[0..8].to_string().to_uppercase();
let mut i: u64 = 0;
for c in s.chars() {
if !c.is_digit(16) {
break;
}
i <<= 8;
i += c.to_digit(16).unwrap() as u64;
}
Ok(i)
},
_ => Err(AmlError::AmlValueError)
}
}
pub fn get_as_integer_constant(&self) -> Result<u64, AmlError> {
match *self {
AmlValue::IntegerConstant(ref i) => Ok(i.clone()),
_ => Err(AmlError::AmlValueError)
}
}
pub fn get_as_method(&self) -> Result<Method, AmlError> {
match *self {
AmlValue::Method(ref m) => Ok(m.clone()),
_ => Err(AmlError::AmlValueError)
}
}
pub fn get_as_mutex(&self) -> Result<(u8, Option<u64>), AmlError> {
match *self {
AmlValue::Mutex(ref m) => Ok(m.clone()),
_ => Err(AmlError::AmlValueError)
}
}
pub fn get_as_object_reference(&self) -> Result<ObjectReference, AmlError> {
match *self {
AmlValue::ObjectReference(ref m) => Ok(m.clone()),
_ => Err(AmlError::AmlValueError)
}
}
/*
pub fn get_as_operation_region(&self) -> Result<OperationRegion, AmlError> {
match *self {
AmlValue::OperationRegion(ref p) => Ok(p.clone()),
_ => Err(AmlError::AmlValueError)
}
}
*/
pub fn get_as_package(&self) -> Result<Vec<AmlValue>, AmlError> {
match *self {
AmlValue::Package(ref p) => Ok(p.clone()),
_ => Err(AmlError::AmlValueError)
}
}
pub fn get_as_string(&self) -> Result<String, AmlError> {
match *self {
AmlValue::String(ref s) => Ok(s.clone()),
AmlValue::Integer(ref i) => Ok(format!("{:X}", i)),
AmlValue::IntegerConstant(ref i) => Ok(format!("{:X}", i)),
AmlValue::Buffer(ref b) => Ok(String::from_utf8(b.clone()).expect("Invalid UTF-8")),
AmlValue::BufferField(_) => {
let b = self.get_as_buffer()?;
Ok(String::from_utf8(b).expect("Invalid UTF-8"))
},
_ => Err(AmlError::AmlValueError)
}
}
pub fn get_as_power_resource(&self) -> Result<PowerResource, AmlError> {
match *self {
AmlValue::PowerResource(ref p) => Ok(p.clone()),
_ => Err(AmlError::AmlValueError)
}
}
pub fn get_as_processor(&self) -> Result<Processor, AmlError> {
match *self {
AmlValue::Processor(ref p) => Ok(p.clone()),
_ => Err(AmlError::AmlValueError)
}
}
pub fn get_as_raw_data_buffer(&self) -> Result<Vec<u8>, AmlError> {
match *self {
AmlValue::RawDataBuffer(ref p) => Ok(p.clone()),
_ => Err(AmlError::AmlValueError)
}
}
pub fn get_as_thermal_zone(&self) -> Result<ThermalZone, AmlError> {
match *self {
AmlValue::ThermalZone(ref p) => Ok(p.clone()),
_ => Err(AmlError::AmlValueError)
}
}
}
impl Method {
pub fn execute(&self, scope: String, parameters: Vec<AmlValue>) -> AmlValue {
let mut ctx = AmlExecutionContext::new(scope);
ctx.init_arg_vars(parameters);
let _ = parse_term_list(&self.term_list[..], &mut ctx);
ctx.clean_namespace();
match ctx.state {
ExecutionState::RETURN(v) => v,
_ => AmlValue::IntegerConstant(0)
}
}
}
pub fn get_namespace_string(current: String, modifier_v: AmlValue) -> Result<String, AmlError> {
let mut modifier = modifier_v.get_as_string()?;
if current.len() == 0 {
return Ok(modifier);
}
if modifier.len() == 0 {
return Ok(current);
}
if modifier.starts_with("\\") {
return Ok(modifier);
}
let mut namespace = current.clone();
if modifier.starts_with("^") {
while modifier.starts_with("^") {
modifier = modifier[1..].to_string();
if namespace.ends_with("\\") {
return Err(AmlError::AmlValueError);
}
loop {
if namespace.ends_with(".") {
namespace.pop();
break;
}
if namespace.pop() == None {
return Err(AmlError::AmlValueError);
}
}
}
}
if !namespace.ends_with("\\") {
namespace.push('.');
}
Ok(namespace + &modifier)
}

View File

@@ -1,106 +0,0 @@
use super::AmlError;
use super::parser::{AmlParseType, ParseResult, AmlExecutionContext, ExecutionState};
use super::namespace::{AmlValue, get_namespace_string};
use super::pkglength::parse_pkg_length;
use super::namestring::parse_name_string;
use super::termlist::parse_term_list;
use super::dataobj::parse_data_ref_obj;
pub fn parse_namespace_modifier(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_selector! {
data, ctx,
parse_alias_op,
parse_scope_op,
parse_name_op
};
Err(AmlError::AmlInvalidOpCode)
}
fn parse_alias_op(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode!(data, 0x06);
let source_name = parse_name_string(&data[1..], ctx)?;
let alias_name = parse_name_string(&data[1 + source_name.len..], ctx)?;
let local_scope_string = get_namespace_string(ctx.scope.clone(), source_name.val)?;
let local_alias_string = get_namespace_string(ctx.scope.clone(), alias_name.val)?;
ctx.add_to_namespace(local_scope_string, AmlValue::Alias(local_alias_string))?;
Ok(AmlParseType {
val: AmlValue::None,
len: 1 + source_name.len + alias_name.len
})
}
fn parse_name_op(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode!(data, 0x08);
let name = parse_name_string(&data[1..], ctx)?;
let data_ref_obj = parse_data_ref_obj(&data[1 + name.len..], ctx)?;
let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?;
ctx.add_to_namespace(local_scope_string, data_ref_obj.val)?;
Ok(AmlParseType {
val: AmlValue::None,
len: 1 + name.len + data_ref_obj.len
})
}
fn parse_scope_op(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode!(data, 0x10);
let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?;
let name = parse_name_string(&data[1 + pkg_length_len..], ctx)?;
let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val.clone())?;
let containing_scope_string = ctx.scope.clone();
ctx.scope = local_scope_string;
parse_term_list(&data[1 + pkg_length_len + name.len .. 1 + pkg_length], ctx)?;
ctx.scope = containing_scope_string;
Ok(AmlParseType {
val: AmlValue::None,
len: 1 + pkg_length
})
}

View File

@@ -1,226 +0,0 @@
use alloc::vec::Vec;
use alloc::string::String;
use super::AmlError;
use super::parser::{AmlParseType, ParseResult, AmlExecutionContext, ExecutionState};
use super::namespace::AmlValue;
use super::dataobj::{parse_arg_obj, parse_local_obj};
use super::type2opcode::parse_type6_opcode;
pub fn parse_name_string(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
let mut characters: Vec<u8> = vec!();
let mut starting_index: usize = 0;
if data[0] == 0x5C {
characters.push(data[0]);
starting_index = 1;
} else if data[0] == 0x5E {
while data[starting_index] == 0x5E {
characters.push(data[starting_index]);
starting_index += 1;
}
}
let sel = |data| {
parser_selector_simple! {
data,
parse_dual_name_path,
parse_multi_name_path,
parse_null_name,
parse_name_seg
};
Err(AmlError::AmlInvalidOpCode)
};
let (mut chr, len) = sel(&data[starting_index..])?;
characters.append(&mut chr);
let name_string = String::from_utf8(characters);
match name_string {
Ok(s) => Ok(AmlParseType {
val: AmlValue::String(s.clone()),
len: len + starting_index
}),
Err(_) => Err(AmlError::AmlParseError("Namestring - Name is invalid"))
}
}
fn parse_null_name(data: &[u8]) -> Result<(Vec<u8>, usize), AmlError> {
parser_opcode!(data, 0x00);
Ok((vec!(), 1 ))
}
pub fn parse_name_seg(data: &[u8]) -> Result<(Vec<u8>, usize), AmlError> {
match data[0] {
0x41 ..= 0x5A | 0x5F => (),
_ => return Err(AmlError::AmlInvalidOpCode)
}
match data[1] {
0x30 ..= 0x39 | 0x41 ..= 0x5A | 0x5F => (),
_ => return Err(AmlError::AmlInvalidOpCode)
}
match data[2] {
0x30 ..= 0x39 | 0x41 ..= 0x5A | 0x5F => (),
_ => return Err(AmlError::AmlInvalidOpCode)
}
match data[3] {
0x30 ..= 0x39 | 0x41 ..= 0x5A | 0x5F => (),
_ => return Err(AmlError::AmlInvalidOpCode)
}
let mut name_seg = vec!(data[0], data[1], data[2], data[3]);
while *(name_seg.last().unwrap()) == 0x5F {
name_seg.pop();
}
Ok((name_seg, 4))
}
fn parse_dual_name_path(data: &[u8]) -> Result<(Vec<u8>, usize), AmlError> {
parser_opcode!(data, 0x2E);
let mut characters: Vec<u8> = vec!();
let mut dual_len: usize = 1;
match parse_name_seg(&data[1..5]) {
Ok((mut v, len)) => {
characters.append(&mut v);
dual_len += len;
},
Err(e) => return Err(e)
}
characters.push(0x2E);
match parse_name_seg(&data[5..9]) {
Ok((mut v, len)) => {
characters.append(&mut v);
dual_len += len;
},
Err(e) => return Err(e)
}
Ok((characters, dual_len))
}
fn parse_multi_name_path(data: &[u8]) -> Result<(Vec<u8>, usize), AmlError> {
parser_opcode!(data, 0x2F);
let seg_count = data[1];
if seg_count == 0x00 {
return Err(AmlError::AmlParseError("MultiName Path - can't have zero name segments"));
}
let mut current_seg = 0;
let mut characters: Vec<u8> = vec!();
let mut multi_len: usize = 2;
while current_seg < seg_count {
match parse_name_seg(&data[(current_seg as usize * 4) + 2 ..]) {
Ok((mut v, len)) => {
characters.append(&mut v);
multi_len += len;
},
Err(e) => return Err(e)
}
characters.push(0x2E);
current_seg += 1;
}
characters.pop();
Ok((characters, multi_len))
}
pub fn parse_super_name(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_selector! {
data, ctx,
parse_simple_name,
parse_type6_opcode,
parse_debug_obj
};
Err(AmlError::AmlInvalidOpCode)
}
fn parse_debug_obj(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode_extended!(data, 0x31);
Ok(AmlParseType {
val: AmlValue::DebugObject,
len: 2
})
}
pub fn parse_simple_name(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_selector! {
data, ctx,
parse_name_string,
parse_arg_obj,
parse_local_obj
};
Err(AmlError::AmlInvalidOpCode)
}
pub fn parse_target(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
if data[0] == 0x00 {
Ok(AmlParseType {
val: AmlValue::None,
len: 1
})
} else {
parse_super_name(data, ctx)
}
}

View File

@@ -1,552 +0,0 @@
use alloc::string::String;
use alloc::collections::BTreeMap;
use alloc::vec::Vec;
use alloc::boxed::Box;
use spin::RwLockWriteGuard;
use super::namespace::{ AmlValue, ObjectReference };
use super::AmlError;
use crate::acpi::ACPI_TABLE;
pub type ParseResult = Result<AmlParseType, AmlError>;
pub type AmlParseType = AmlParseTypeGeneric<AmlValue>;
pub struct AmlParseTypeGeneric<T> {
pub val: T,
pub len: usize
}
pub enum ExecutionState {
EXECUTING,
CONTINUE,
BREAK,
RETURN(AmlValue)
}
pub struct AmlExecutionContext {
pub scope: String,
pub local_vars: [AmlValue; 8],
pub arg_vars: [AmlValue; 8],
pub state: ExecutionState,
pub namespace_delta: Vec<String>,
pub ctx_id: u64,
pub sync_level: u8
}
impl AmlExecutionContext {
pub fn new(scope: String) -> AmlExecutionContext {
let mut idptr = ACPI_TABLE.next_ctx.write();
let id: u64 = *idptr;
*idptr += 1;
AmlExecutionContext {
scope: scope,
local_vars: [AmlValue::Uninitialized,
AmlValue::Uninitialized,
AmlValue::Uninitialized,
AmlValue::Uninitialized,
AmlValue::Uninitialized,
AmlValue::Uninitialized,
AmlValue::Uninitialized,
AmlValue::Uninitialized],
arg_vars: [AmlValue::Uninitialized,
AmlValue::Uninitialized,
AmlValue::Uninitialized,
AmlValue::Uninitialized,
AmlValue::Uninitialized,
AmlValue::Uninitialized,
AmlValue::Uninitialized,
AmlValue::Uninitialized],
state: ExecutionState::EXECUTING,
namespace_delta: vec!(),
ctx_id: id,
sync_level: 0
}
}
pub fn wait_for_event(&mut self, event_ptr: AmlValue) -> Result<bool, AmlError> {
let mut namespace_ptr = self.prelock();
let namespace = match *namespace_ptr {
Some(ref mut n) => n,
None => return Err(AmlError::AmlHardFatal)
};
let mutex_idx = match event_ptr {
AmlValue::String(ref s) => s.clone(),
AmlValue::ObjectReference(ref o) => match *o {
ObjectReference::Object(ref s) => s.clone(),
_ => return Err(AmlError::AmlValueError)
},
_ => return Err(AmlError::AmlValueError)
};
let mutex = match namespace.get(&mutex_idx) {
Some(s) => s.clone(),
None => return Err(AmlError::AmlValueError)
};
match mutex {
AmlValue::Event(count) => {
if count > 0 {
namespace.insert(mutex_idx, AmlValue::Event(count - 1));
return Ok(true);
}
},
_ => return Err(AmlError::AmlValueError)
}
Ok(false)
}
pub fn signal_event(&mut self, event_ptr: AmlValue) -> Result<(), AmlError> {
let mut namespace_ptr = self.prelock();
let namespace = match *namespace_ptr {
Some(ref mut n) => n,
None => return Err(AmlError::AmlHardFatal)
};
let mutex_idx = match event_ptr {
AmlValue::String(ref s) => s.clone(),
AmlValue::ObjectReference(ref o) => match *o {
ObjectReference::Object(ref s) => s.clone(),
_ => return Err(AmlError::AmlValueError)
},
_ => return Err(AmlError::AmlValueError)
};
let mutex = match namespace.get(&mutex_idx) {
Some(s) => s.clone(),
None => return Err(AmlError::AmlValueError)
};
match mutex {
AmlValue::Event(count) => {
namespace.insert(mutex_idx, AmlValue::Event(count + 1));
},
_ => return Err(AmlError::AmlValueError)
}
Ok(())
}
pub fn release_mutex(&mut self, mutex_ptr: AmlValue) -> Result<(), AmlError> {
let id = self.ctx_id;
let mut namespace_ptr = self.prelock();
let namespace = match *namespace_ptr {
Some(ref mut n) => n,
None => return Err(AmlError::AmlHardFatal)
};
let mutex_idx = match mutex_ptr {
AmlValue::String(ref s) => s.clone(),
AmlValue::ObjectReference(ref o) => match *o {
ObjectReference::Object(ref s) => s.clone(),
_ => return Err(AmlError::AmlValueError)
},
_ => return Err(AmlError::AmlValueError)
};
let mutex = match namespace.get(&mutex_idx) {
Some(s) => s.clone(),
None => return Err(AmlError::AmlValueError)
};
match mutex {
AmlValue::Mutex((sync_level, owner)) => {
if let Some(o) = owner {
if o == id {
if sync_level == self.sync_level {
namespace.insert(mutex_idx, AmlValue::Mutex((sync_level, None)));
return Ok(());
} else {
return Err(AmlError::AmlValueError);
}
} else {
return Err(AmlError::AmlHardFatal);
}
}
},
AmlValue::OperationRegion(ref region) => {
if let Some(o) = region.accessed_by {
if o == id {
let mut new_region = region.clone();
new_region.accessed_by = None;
namespace.insert(mutex_idx, AmlValue::OperationRegion(new_region));
return Ok(());
} else {
return Err(AmlError::AmlHardFatal);
}
}
},
_ => return Err(AmlError::AmlValueError)
}
Ok(())
}
pub fn acquire_mutex(&mut self, mutex_ptr: AmlValue) -> Result<bool, AmlError> {
let id = self.ctx_id;
let mut namespace_ptr = self.prelock();
let namespace = match *namespace_ptr {
Some(ref mut n) => n,
None => return Err(AmlError::AmlHardFatal)
};
let mutex_idx = match mutex_ptr {
AmlValue::String(ref s) => s.clone(),
AmlValue::ObjectReference(ref o) => match *o {
ObjectReference::Object(ref s) => s.clone(),
_ => return Err(AmlError::AmlValueError)
},
_ => return Err(AmlError::AmlValueError)
};
let mutex = match namespace.get(&mutex_idx) {
Some(s) => s.clone(),
None => return Err(AmlError::AmlValueError)
};
match mutex {
AmlValue::Mutex((sync_level, owner)) => {
if owner == None {
if sync_level < self.sync_level {
return Err(AmlError::AmlValueError);
}
namespace.insert(mutex_idx, AmlValue::Mutex((sync_level, Some(id))));
self.sync_level = sync_level;
return Ok(true);
}
},
AmlValue::OperationRegion(ref o) => {
if o.accessed_by == None {
let mut new_region = o.clone();
new_region.accessed_by = Some(id);
namespace.insert(mutex_idx, AmlValue::OperationRegion(new_region));
return Ok(true);
}
},
_ => return Err(AmlError::AmlValueError)
}
Ok(false)
}
pub fn add_to_namespace(&mut self, name: String, value: AmlValue) -> Result<(), AmlError> {
let mut namespace = ACPI_TABLE.namespace.write();
if let Some(ref mut namespace) = *namespace {
if let Some(obj) = namespace.get(&name) {
match *obj {
AmlValue::Uninitialized => (),
AmlValue::Method(ref m) => {
if m.term_list.len() != 0 {
return Err(AmlError::AmlValueError);
}
},
_ => return Err(AmlError::AmlValueError)
}
}
self.namespace_delta.push(name.clone());
namespace.insert(name, value);
Ok(())
} else {
Err(AmlError::AmlValueError)
}
}
pub fn clean_namespace(&mut self) {
let mut namespace = ACPI_TABLE.namespace.write();
if let Some(ref mut namespace) = *namespace {
for k in &self.namespace_delta {
namespace.remove(k);
}
}
}
pub fn init_arg_vars(&mut self, parameters: Vec<AmlValue>) {
if parameters.len() > 8 {
return;
}
let mut cur = 0;
while cur < parameters.len() {
self.arg_vars[cur] = parameters[cur].clone();
cur += 1;
}
}
pub fn prelock(&mut self) -> RwLockWriteGuard<'static, Option<BTreeMap<String, AmlValue>>> {
ACPI_TABLE.namespace.write()
}
fn modify_local_obj(&mut self, local: usize, value: AmlValue) -> Result<(), AmlError> {
self.local_vars[local] = value.get_as_type(self.local_vars[local].clone())?;
Ok(())
}
fn modify_object(&mut self, name: String, value: AmlValue) -> Result<(), AmlError> {
if let Some(ref mut namespace) = *ACPI_TABLE.namespace.write() {
let coercion_obj = {
let obj = namespace.get(&name);
if let Some(o) = obj {
o.clone()
} else {
AmlValue::Uninitialized
}
};
namespace.insert(name, value.get_as_type(coercion_obj)?);
Ok(())
} else {
Err(AmlError::AmlHardFatal)
}
}
fn modify_index_final(&mut self, name: String, value: AmlValue, indices: Vec<u64>) -> Result<(), AmlError> {
if let Some(ref mut namespace) = *ACPI_TABLE.namespace.write() {
let mut obj = if let Some(s) = namespace.get(&name) {
s.clone()
} else {
return Err(AmlError::AmlValueError);
};
obj = self.modify_index_core(obj, value, indices)?;
namespace.insert(name, obj);
Ok(())
} else {
Err(AmlError::AmlValueError)
}
}
fn modify_index_core(&mut self, obj: AmlValue, value: AmlValue, indices: Vec<u64>) -> Result<AmlValue, AmlError> {
match obj {
AmlValue::String(ref string) => {
if indices.len() != 1 {
return Err(AmlError::AmlValueError);
}
let mut bytes = string.clone().into_bytes();
bytes[indices[0] as usize] = value.get_as_integer()? as u8;
let string = String::from_utf8(bytes).unwrap();
Ok(AmlValue::String(string))
},
AmlValue::Buffer(ref b) => {
if indices.len() != 1 {
return Err(AmlError::AmlValueError);
}
let mut b = b.clone();
b[indices[0] as usize] = value.get_as_integer()? as u8;
Ok(AmlValue::Buffer(b))
},
AmlValue::BufferField(ref b) => {
if indices.len() != 1 {
return Err(AmlError::AmlValueError);
}
let mut idx = indices[0];
idx += b.index.get_as_integer()?;
let _ = self.modify(AmlValue::ObjectReference(ObjectReference::Index(b.source_buf.clone(), Box::new(AmlValue::Integer(idx.clone())))), value);
Ok(AmlValue::BufferField(b.clone()))
},
AmlValue::Package(ref p) => {
if indices.len() == 0 {
return Err(AmlError::AmlValueError);
}
let mut p = p.clone();
if indices.len() == 1 {
p[indices[0] as usize] = value;
} else {
p[indices[0] as usize] = self.modify_index_core(p[indices[0] as usize].clone(), value, indices[1..].to_vec())?;
}
Ok(AmlValue::Package(p))
},
_ => Err(AmlError::AmlValueError)
}
}
pub fn modify_index(&mut self, name: AmlValue, value: AmlValue, indices: Vec<u64>) -> Result<(), AmlError>{
match name {
AmlValue::ObjectReference(r) => match r {
ObjectReference::Object(s) => self.modify_index_final(s, value, indices),
ObjectReference::Index(c, v) => {
let mut indices = indices.clone();
indices.push(v.get_as_integer()?);
self.modify_index(*c, value, indices)
},
ObjectReference::ArgObj(_) => Err(AmlError::AmlValueError),
ObjectReference::LocalObj(i) => {
let v = self.local_vars[i as usize].clone();
self.local_vars[i as usize] = self.modify_index_core(v, value, indices)?;
Ok(())
}
},
_ => Err(AmlError::AmlValueError)
}
}
pub fn modify(&mut self, name: AmlValue, value: AmlValue) -> Result<(), AmlError> {
match name {
AmlValue::ObjectReference(r) => match r {
ObjectReference::ArgObj(_) => Err(AmlError::AmlValueError),
ObjectReference::LocalObj(i) => self.modify_local_obj(i as usize, value),
ObjectReference::Object(s) => self.modify_object(s, value),
ObjectReference::Index(c, v) => self.modify_index(*c, value, vec!(v.get_as_integer()?))
},
AmlValue::String(s) => self.modify_object(s, value),
_ => Err(AmlError::AmlValueError)
}
}
fn copy_local_obj(&mut self, local: usize, value: AmlValue) -> Result<(), AmlError> {
self.local_vars[local] = value;
Ok(())
}
fn copy_object(&mut self, name: String, value: AmlValue) -> Result<(), AmlError> {
if let Some(ref mut namespace) = *ACPI_TABLE.namespace.write() {
namespace.insert(name, value);
Ok(())
} else {
Err(AmlError::AmlHardFatal)
}
}
pub fn copy(&mut self, name: AmlValue, value: AmlValue) -> Result<(), AmlError> {
match name {
AmlValue::ObjectReference(r) => match r {
ObjectReference::ArgObj(_) => Err(AmlError::AmlValueError),
ObjectReference::LocalObj(i) => self.copy_local_obj(i as usize, value),
ObjectReference::Object(s) => self.copy_object(s, value),
ObjectReference::Index(c, v) => self.modify_index(*c, value, vec!(v.get_as_integer()?))
},
AmlValue::String(s) => self.copy_object(s, value),
_ => Err(AmlError::AmlValueError)
}
}
fn get_index_final(&self, name: String, indices: Vec<u64>) -> Result<AmlValue, AmlError> {
if let Some(ref namespace) = *ACPI_TABLE.namespace.read() {
let obj = if let Some(s) = namespace.get(&name) {
s.clone()
} else {
return Err(AmlError::AmlValueError);
};
self.get_index_core(obj, indices)
} else {
Err(AmlError::AmlValueError)
}
}
fn get_index_core(&self, obj: AmlValue, indices: Vec<u64>) -> Result<AmlValue, AmlError> {
match obj {
AmlValue::String(ref string) => {
if indices.len() != 1 {
return Err(AmlError::AmlValueError);
}
let bytes = string.clone().into_bytes();
Ok(AmlValue::Integer(bytes[indices[0] as usize] as u64))
},
AmlValue::Buffer(ref b) => {
if indices.len() != 1 {
return Err(AmlError::AmlValueError);
}
Ok(AmlValue::Integer(b[indices[0] as usize] as u64))
},
AmlValue::BufferField(ref b) => {
if indices.len() != 1 {
return Err(AmlError::AmlValueError);
}
let mut idx = indices[0];
idx += b.index.get_as_integer()?;
Ok(AmlValue::Integer(b.source_buf.get_as_buffer()?[idx as usize] as u64))
},
AmlValue::Package(ref p) => {
if indices.len() == 0 {
return Err(AmlError::AmlValueError);
}
if indices.len() == 1 {
Ok(p[indices[0] as usize].clone())
} else {
self.get_index_core(p[indices[0] as usize].clone(), indices[1..].to_vec())
}
},
_ => Err(AmlError::AmlValueError)
}
}
pub fn get_index(&self, name: AmlValue, indices: Vec<u64>) -> Result<AmlValue, AmlError>{
match name {
AmlValue::ObjectReference(r) => match r {
ObjectReference::Object(s) => self.get_index_final(s, indices),
ObjectReference::Index(c, v) => {
let mut indices = indices.clone();
indices.push(v.get_as_integer()?);
self.get_index(*c, indices)
},
ObjectReference::ArgObj(_) => Err(AmlError::AmlValueError),
ObjectReference::LocalObj(i) => {
let v = self.local_vars[i as usize].clone();
self.get_index_core(v, indices)
}
},
_ => Err(AmlError::AmlValueError)
}
}
pub fn get(&self, name: AmlValue) -> Result<AmlValue, AmlError> {
Ok(match name {
AmlValue::ObjectReference(r) => match r {
ObjectReference::ArgObj(i) => self.arg_vars[i as usize].clone(),
ObjectReference::LocalObj(i) => self.local_vars[i as usize].clone(),
ObjectReference::Object(ref s) => if let Some(ref namespace) = *ACPI_TABLE.namespace.read() {
if let Some(o) = namespace.get(s) {
o.clone()
} else {
AmlValue::None
}
} else { AmlValue::None },
ObjectReference::Index(c, v) => self.get_index(*c, vec!(v.get_as_integer()?))?,
},
AmlValue::String(ref s) => if let Some(ref namespace) = *ACPI_TABLE.namespace.read() {
if let Some(o) = namespace.get(s) {
o.clone()
} else {
AmlValue::None
}
} else { AmlValue::None },
_ => AmlValue::None
})
}
}

View File

@@ -1,52 +0,0 @@
#[macro_export]
macro_rules! parser_selector {
{$data:expr, $ctx:expr, $func:expr} => {
match $func($data, $ctx) {
Ok(res) => return Ok(res),
Err(AmlError::AmlInvalidOpCode) => (),
Err(e) => return Err(e)
}
};
{$data:expr, $ctx:expr, $func:expr, $($funcs:expr),+} => {
parser_selector! {$data, $ctx, $func};
parser_selector! {$data, $ctx, $($funcs),*};
};
}
#[macro_export]
macro_rules! parser_selector_simple {
{$data:expr, $func:expr} => {
match $func($data) {
Ok(res) => return Ok(res),
Err(AmlError::AmlInvalidOpCode) => (),
Err(e) => return Err(e)
}
};
{$data:expr, $func:expr, $($funcs:expr),+} => {
parser_selector_simple! {$data, $func};
parser_selector_simple! {$data, $($funcs),*};
};
}
#[macro_export]
macro_rules! parser_opcode {
($data:expr, $opcode:expr) => {
if $data[0] != $opcode {
return Err(AmlError::AmlInvalidOpCode);
}
};
($data:expr, $opcode:expr, $alternate_opcode:expr) => {
if $data[0] != $opcode && $data[0] != $alternate_opcode {
return Err(AmlError::AmlInvalidOpCode);
}
};
}
#[macro_export]
macro_rules! parser_opcode_extended {
($data:expr, $opcode:expr) => {
if $data[0] != 0x5B || $data[1] != $opcode {
return Err(AmlError::AmlInvalidOpCode);
}
};
}

View File

@@ -1,25 +0,0 @@
use super::AmlError;
pub fn parse_pkg_length(data: &[u8]) -> Result<(usize, usize), AmlError> {
let lead_byte = data[0];
let count_bytes: usize = (lead_byte >> 6) as usize;
if count_bytes == 0 {
return Ok(((lead_byte & 0x3F) as usize, 1 as usize));
}
let upper_two = (lead_byte >> 4) & 0x03;
if upper_two != 0 {
return Err(AmlError::AmlParseError("Invalid package length"));
}
let mut current_byte = 0;
let mut pkg_len: usize = (lead_byte & 0x0F) as usize;
while current_byte < count_bytes {
pkg_len += (data[1 + current_byte] as u32 * 16 * (256 as u32).pow(current_byte as u32)) as usize;
current_byte += 1;
}
Ok((pkg_len, count_bytes + 1))
}

View File

@@ -1,174 +0,0 @@
use alloc::vec::Vec;
use super::AmlError;
use super::parser::{ AmlParseType, ParseResult, AmlExecutionContext, ExecutionState };
use super::namespace::{AmlValue, get_namespace_string};
use super::namespacemodifier::parse_namespace_modifier;
use super::namedobj::parse_named_obj;
use super::dataobj::{parse_data_obj, parse_arg_obj, parse_local_obj};
use super::type1opcode::parse_type1_opcode;
use super::type2opcode::parse_type2_opcode;
use super::namestring::parse_name_string;
pub fn parse_term_list(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
let mut current_offset: usize = 0;
while current_offset < data.len() {
let res = parse_term_obj(&data[current_offset..], ctx)?;
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: data.len()
})
}
current_offset += res.len;
}
Ok(AmlParseType {
val: AmlValue::None,
len: data.len()
})
}
pub fn parse_term_arg(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_selector! {
data, ctx,
parse_local_obj,
parse_data_obj,
parse_arg_obj,
parse_type2_opcode
};
Err(AmlError::AmlInvalidOpCode)
}
pub fn parse_object_list(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
let mut current_offset: usize = 0;
while current_offset < data.len() {
let res = parse_object(&data[current_offset..], ctx)?;
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: data.len()
})
}
current_offset += res.len;
}
Ok(AmlParseType {
val: AmlValue::None,
len: data.len()
})
}
fn parse_object(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_selector! {
data, ctx,
parse_namespace_modifier,
parse_named_obj
};
Err(AmlError::AmlInvalidOpCode)
}
pub fn parse_method_invocation(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
let name = parse_name_string(data, ctx)?;
let method = ctx.get(name.val.clone())?;
let method = match method {
AmlValue::None => return Err(AmlError::AmlDeferredLoad),
_ => method.get_as_method()?
};
let mut cur = 0;
let mut params: Vec<AmlValue> = vec!();
let mut current_offset = name.len;
while cur < method.arg_count {
let res = parse_term_arg(&data[current_offset..], ctx)?;
current_offset += res.len;
cur += 1;
params.push(res.val);
}
Ok(AmlParseType {
val: method.execute(get_namespace_string(ctx.scope.clone(), name.val)?, params),
len: current_offset
})
}
fn parse_term_obj(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_selector! {
data, ctx,
parse_namespace_modifier,
parse_named_obj,
parse_type1_opcode,
parse_type2_opcode
};
Err(AmlError::AmlInvalidOpCode)
}

View File

@@ -1,472 +0,0 @@
use super::AmlError;
use super::parser::{AmlParseType, ParseResult, AmlExecutionContext, ExecutionState};
use super::namespace::AmlValue;
use super::pkglength::parse_pkg_length;
use super::termlist::{parse_term_arg, parse_term_list};
use super::namestring::{parse_name_string, parse_super_name};
use crate::time::monotonic;
use crate::acpi::{Sdt, load_table, get_sdt_signature};
use super::{parse_aml_table, is_aml_table};
pub fn parse_type1_opcode(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_selector! {
data, ctx,
parse_def_break,
parse_def_breakpoint,
parse_def_continue,
parse_def_noop,
parse_def_fatal,
parse_def_if_else,
parse_def_load,
parse_def_notify,
parse_def_release,
parse_def_reset,
parse_def_signal,
parse_def_sleep,
parse_def_stall,
parse_def_return,
parse_def_unload,
parse_def_while
};
Err(AmlError::AmlInvalidOpCode)
}
fn parse_def_break(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode!(data, 0xA5);
ctx.state = ExecutionState::BREAK;
Ok(AmlParseType {
val: AmlValue::None,
len: 1 as usize
})
}
fn parse_def_breakpoint(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode!(data, 0xCC);
Ok(AmlParseType {
val: AmlValue::None,
len: 1 as usize
})
}
fn parse_def_continue(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode!(data, 0x9F);
ctx.state = ExecutionState::CONTINUE;
Ok(AmlParseType {
val: AmlValue::None,
len: 1 as usize
})
}
fn parse_def_noop(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode!(data, 0xA3);
Ok(AmlParseType {
val: AmlValue::None,
len: 1 as usize
})
}
fn parse_def_fatal(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode_extended!(data, 0x32);
let fatal_type = data[2];
let fatal_code: u16 = (data[3] as u16) + ((data[4] as u16) << 8);
let fatal_arg = parse_term_arg(&data[5..], ctx)?;
Err(AmlError::AmlFatalError(fatal_type, fatal_code, fatal_arg.val))
}
fn parse_def_load(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode_extended!(data, 0x20);
let name = parse_name_string(&data[2..], ctx)?;
let ddb_handle_object = parse_super_name(&data[2 + name.len..], ctx)?;
let tbl = ctx.get(name.val)?.get_as_buffer()?;
let sdt = unsafe { &*(tbl.as_ptr() as *const Sdt) };
if is_aml_table(sdt) {
load_table(get_sdt_signature(sdt));
let delta = parse_aml_table(sdt)?;
let _ = ctx.modify(ddb_handle_object.val, AmlValue::DDBHandle((delta, get_sdt_signature(sdt))));
Ok(AmlParseType {
val: AmlValue::None,
len: 2 + name.len + ddb_handle_object.len
})
} else {
Err(AmlError::AmlValueError)
}
}
fn parse_def_notify(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode!(data, 0x86);
let object = parse_super_name(&data[1..], ctx)?;
let value = parse_term_arg(&data[1 + object.len..], ctx)?;
let number = value.val.get_as_integer()? as u8;
match ctx.get(object.val)? {
AmlValue::Device(d) => {
if let Some(methods) = d.notify_methods.get(&number) {
for method in methods {
method();
}
}
},
AmlValue::Processor(d) => {
if let Some(methods) = d.notify_methods.get(&number) {
for method in methods {
method();
}
}
},
AmlValue::ThermalZone(d) => {
if let Some(methods) = d.notify_methods.get(&number) {
for method in methods {
method();
}
}
},
_ => return Err(AmlError::AmlValueError)
}
Ok(AmlParseType {
val: AmlValue::None,
len: 1 + object.len + value.len
})
}
fn parse_def_release(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode_extended!(data, 0x27);
let obj = parse_super_name(&data[2..], ctx)?;
let _ = ctx.release_mutex(obj.val);
Ok(AmlParseType {
val: AmlValue::None,
len: 2 + obj.len
})
}
fn parse_def_reset(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode_extended!(data, 0x26);
let object = parse_super_name(&data[2..], ctx)?;
ctx.get(object.val.clone())?.get_as_event()?;
let _ = ctx.modify(object.val.clone(), AmlValue::Event(0));
Ok(AmlParseType {
val: AmlValue::None,
len: 2 + object.len
})
}
fn parse_def_signal(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode_extended!(data, 0x24);
let object = parse_super_name(&data[2..], ctx)?;
ctx.signal_event(object.val)?;
Ok(AmlParseType {
val: AmlValue::None,
len: 2 + object.len
})
}
fn parse_def_sleep(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode_extended!(data, 0x22);
let time = parse_term_arg(&data[2..], ctx)?;
let timeout = time.val.get_as_integer()?;
let (seconds, nanoseconds) = monotonic();
let starting_time_ns = nanoseconds + (seconds * 1_000_000_000);
loop {
let (seconds, nanoseconds) = monotonic();
let current_time_ns = nanoseconds + (seconds * 1_000_000_000);
if current_time_ns - starting_time_ns > timeout as u64 * 1_000_000 {
break;
}
}
Ok(AmlParseType {
val: AmlValue::None,
len: 2 + time.len
})
}
fn parse_def_stall(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode_extended!(data, 0x21);
let time = parse_term_arg(&data[2..], ctx)?;
let timeout = time.val.get_as_integer()?;
let (seconds, nanoseconds) = monotonic();
let starting_time_ns = nanoseconds + (seconds * 1_000_000_000);
loop {
let (seconds, nanoseconds) = monotonic();
let current_time_ns = nanoseconds + (seconds * 1_000_000_000);
if current_time_ns - starting_time_ns > timeout as u64 * 1000 {
break;
}
}
Ok(AmlParseType {
val: AmlValue::None,
len: 2 + time.len
})
}
fn parse_def_unload(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode_extended!(data, 0x2A);
let object = parse_super_name(&data[2..], ctx)?;
let delta = ctx.get(object.val)?.get_as_ddb_handle()?;
let mut namespace = ctx.prelock();
if let Some(ref mut ns) = *namespace {
for o in delta.0 {
ns.remove(&o);
}
}
Ok(AmlParseType {
val: AmlValue::None,
len: 2 + object.len
})
}
fn parse_def_if_else(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode!(data, 0xA0);
let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?;
let if_condition = parse_term_arg(&data[1 + pkg_length_len .. 1 + pkg_length], ctx)?;
let (else_length, else_length_len) = if data.len() > 1 + pkg_length && data[1 + pkg_length] == 0xA1 {
parse_pkg_length(&data[2 + pkg_length..])?
} else {
(0 as usize, 0 as usize)
};
if if_condition.val.get_as_integer()? > 0 {
parse_term_list(&data[1 + pkg_length_len + if_condition.len .. 1 + pkg_length], ctx)?;
} else if else_length > 0 {
parse_term_list(&data[2 + pkg_length + else_length_len .. 2 + pkg_length + else_length], ctx)?;
}
Ok(AmlParseType {
val: AmlValue::None,
len: 1 + pkg_length + if else_length > 0 { 1 + else_length } else { 0 }
})
}
fn parse_def_while(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode!(data, 0xA2);
let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?;
loop {
let predicate = parse_term_arg(&data[1 + pkg_length_len..], ctx)?;
if predicate.val.get_as_integer()? == 0 {
break;
}
parse_term_list(&data[1 + pkg_length_len + predicate.len .. 1 + pkg_length], ctx)?;
match ctx.state {
ExecutionState::EXECUTING => (),
ExecutionState::BREAK => {
ctx.state = ExecutionState::EXECUTING;
break;
},
ExecutionState::CONTINUE => ctx.state = ExecutionState::EXECUTING,
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
}
Ok(AmlParseType {
val: AmlValue::None,
len: 1 + pkg_length
})
}
fn parse_def_return(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode!(data, 0xA4);
let arg_object = parse_term_arg(&data[1..], ctx)?;
ctx.state = ExecutionState::RETURN(arg_object.val);
Ok(AmlParseType {
val: AmlValue::None,
len: 1 + arg_object.len
})
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,77 +0,0 @@
#[repr(packed)]
pub struct DrhdFault {
pub sts: u32,
pub ctrl: u32,
pub data: u32,
pub addr: [u32; 2],
_rsv: [u64; 2],
pub log: u64,
}
#[repr(packed)]
pub struct DrhdProtectedMemory {
pub en: u32,
pub low_base: u32,
pub low_limit: u32,
pub high_base: u64,
pub high_limit: u64,
}
#[repr(packed)]
pub struct DrhdInvalidation {
pub queue_head: u64,
pub queue_tail: u64,
pub queue_addr: u64,
_rsv: u32,
pub cmpl_sts: u32,
pub cmpl_ctrl: u32,
pub cmpl_data: u32,
pub cmpl_addr: [u32; 2],
}
#[repr(packed)]
pub struct DrhdPageRequest {
pub queue_head: u64,
pub queue_tail: u64,
pub queue_addr: u64,
_rsv: u32,
pub sts: u32,
pub ctrl: u32,
pub data: u32,
pub addr: [u32; 2],
}
#[repr(packed)]
pub struct DrhdMtrrVariable {
pub base: u64,
pub mask: u64,
}
#[repr(packed)]
pub struct DrhdMtrr {
pub cap: u64,
pub def_type: u64,
pub fixed: [u64; 11],
pub variable: [DrhdMtrrVariable; 10],
}
#[repr(packed)]
pub struct Drhd {
pub version: u32,
_rsv: u32,
pub cap: u64,
pub ext_cap: u64,
pub gl_cmd: u32,
pub gl_sts: u32,
pub root_table: u64,
pub ctx_cmd: u64,
_rsv1: u32,
pub fault: DrhdFault,
_rsv2: u32,
pub pm: DrhdProtectedMemory,
pub invl: DrhdInvalidation,
_rsv3: u64,
pub intr_table: u64,
pub page_req: DrhdPageRequest,
pub mtrr: DrhdMtrr,
}

View File

@@ -1,215 +0,0 @@
use core::mem;
use super::sdt::Sdt;
use self::drhd::Drhd;
use crate::memory::Frame;
use crate::paging::{ActivePageTable, PageFlags, PhysicalAddress};
use super::{find_sdt, load_table, get_sdt_signature};
pub mod drhd;
/// The DMA Remapping Table
#[derive(Debug)]
pub struct Dmar {
sdt: &'static Sdt,
pub addr_width: u8,
pub flags: u8,
_rsv: [u8; 10],
}
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) };
let flags = unsafe { *(sdt.data_address() as *const u8).offset(1) };
let rsv: [u8; 10] = unsafe { *((sdt.data_address() as *const u8).offset(2) as *const [u8; 10]) };
Some(Dmar {
sdt: sdt,
addr_width: addr_width,
flags: flags,
_rsv: rsv,
})
} else {
None
}
}
pub fn iter(&self) -> DmarIter {
DmarIter {
sdt: self.sdt,
i: 12 // Skip address width and flags
}
}
}
/// DMAR DMA Remapping Hardware Unit Definition
// TODO: Implement iterator on DmarDrhd scope
#[derive(Clone, Copy, Debug)]
#[repr(packed)]
pub struct DmarDrhd {
kind: u16,
length: u16,
flags: u8,
_rsv: u8,
segment: u16,
base: u64,
}
impl DmarDrhd {
pub fn get(&self, active_table: &mut ActivePageTable) -> &'static mut Drhd {
let result = active_table.identity_map(Frame::containing_address(PhysicalAddress::new(self.base as usize)), PageFlags::new().write(true));
result.flush();
unsafe { &mut *(self.base as *mut Drhd) }
}
}
/// DMAR Reserved Memory Region Reporting
// TODO: Implement iterator on DmarRmrr scope
#[derive(Clone, Copy, Debug)]
#[repr(packed)]
pub struct DmarRmrr {
kind: u16,
length: u16,
_rsv: u16,
segment: u16,
base: u64,
limit: u64,
}
/// DMAR Root Port ATS Capability Reporting
// TODO: Implement iterator on DmarAtsr scope
#[derive(Clone, Copy, Debug)]
#[repr(packed)]
pub struct DmarAtsr {
kind: u16,
length: u16,
flags: u8,
_rsv: u8,
segment: u16,
}
/// DMAR Remapping Hardware Static Affinity
#[derive(Clone, Copy, Debug)]
#[repr(packed)]
pub struct DmarRhsa {
kind: u16,
length: u16,
_rsv: u32,
base: u64,
domain: u32,
}
/// DMAR ACPI Name-space Device Declaration
// TODO: Implement iterator on DmarAndd object name
#[derive(Clone, Copy, Debug)]
#[repr(packed)]
pub struct DmarAndd {
kind: u16,
length: u16,
_rsv: [u8; 3],
acpi_dev: u8,
}
/// DMAR Entries
#[derive(Debug)]
pub enum DmarEntry {
Drhd(&'static DmarDrhd),
InvalidDrhd(usize),
Rmrr(&'static DmarRmrr),
InvalidRmrr(usize),
Atsr(&'static DmarAtsr),
InvalidAtsr(usize),
Rhsa(&'static DmarRhsa),
InvalidRhsa(usize),
Andd(&'static DmarAndd),
InvalidAndd(usize),
Unknown(u16)
}
pub struct DmarIter {
sdt: &'static Sdt,
i: usize
}
impl Iterator for DmarIter {
type Item = DmarEntry;
fn next(&mut self) -> Option<Self::Item> {
if self.i + 4 <= self.sdt.data_len() {
let entry_type = unsafe { *((self.sdt.data_address() as *const u8).add(self.i) as *const u16) };
let entry_len = unsafe { *((self.sdt.data_address() as *const u8).add(self.i + 2) as *const u16) } as usize;
if self.i + entry_len <= self.sdt.data_len() {
let item = match entry_type {
0 => if entry_len >= mem::size_of::<DmarDrhd>() {
DmarEntry::Drhd(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarDrhd) })
} else {
DmarEntry::InvalidDrhd(entry_len)
},
1 => if entry_len >= mem::size_of::<DmarRmrr>() {
DmarEntry::Rmrr(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarRmrr) })
} else {
DmarEntry::InvalidRmrr(entry_len)
},
2 => if entry_len >= mem::size_of::<DmarAtsr>() {
DmarEntry::Atsr(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarAtsr) })
} else {
DmarEntry::InvalidAtsr(entry_len)
},
3 => if entry_len == mem::size_of::<DmarRhsa>() {
DmarEntry::Rhsa(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarRhsa) })
} else {
DmarEntry::InvalidRhsa(entry_len)
},
4 => if entry_len >= mem::size_of::<DmarAndd>() {
DmarEntry::Andd(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarAndd) })
} else {
DmarEntry::InvalidAndd(entry_len)
},
_ => DmarEntry::Unknown(entry_type)
};
self.i += entry_len;
Some(item)
} else {
None
}
} else {
None
}
}
}

View File

@@ -1,124 +0,0 @@
use core::{mem, ptr};
use super::sdt::Sdt;
use super::{ACPI_TABLE, SDT_POINTERS, get_sdt, find_sdt, get_sdt_signature, load_table};
use crate::paging::ActivePageTable;
#[repr(packed)]
#[derive(Clone, Copy, Debug)]
pub struct Fadt {
pub header: Sdt,
pub firmware_ctrl: u32,
pub dsdt: u32,
// field used in ACPI 1.0; no longer in use, for compatibility only
reserved: u8,
pub preferred_power_managament: u8,
pub sci_interrupt: u16,
pub smi_command_port: u32,
pub acpi_enable: u8,
pub acpi_disable: u8,
pub s4_bios_req: u8,
pub pstate_control: u8,
pub pm1a_event_block: u32,
pub pm1b_event_block: u32,
pub pm1a_control_block: u32,
pub pm1b_control_block: u32,
pub pm2_control_block: u32,
pub pm_timer_block: u32,
pub gpe0_block: u32,
pub gpe1_block: u32,
pub pm1_event_length: u8,
pub pm1_control_length: u8,
pub pm2_control_length: u8,
pub pm_timer_length: u8,
pub gpe0_ength: u8,
pub gpe1_length: u8,
pub gpe1_base: u8,
pub c_state_control: u8,
pub worst_c2_latency: u16,
pub worst_c3_latency: u16,
pub flush_size: u16,
pub flush_stride: u16,
pub duty_offset: u8,
pub duty_width: u8,
pub day_alarm: u8,
pub month_alarm: u8,
pub century: u8,
// reserved in ACPI 1.0; used since ACPI 2.0+
pub boot_architecture_flags: u16,
reserved2: u8,
pub flags: u32,
}
/* ACPI 2 structure
#[repr(packed)]
#[derive(Clone, Copy, Debug, Default)]
pub struct GenericAddressStructure {
address_space: u8,
bit_width: u8,
bit_offset: u8,
access_size: u8,
address: u64,
}
{
// 12 byte structure; see below for details
pub reset_reg: GenericAddressStructure,
pub reset_value: u8,
reserved3: [u8; 3],
// 64bit pointers - Available on ACPI 2.0+
pub x_firmware_control: u64,
pub x_dsdt: u64,
pub x_pm1a_event_block: GenericAddressStructure,
pub x_pm1b_event_block: GenericAddressStructure,
pub x_pm1a_control_block: GenericAddressStructure,
pub x_pm1b_control_block: GenericAddressStructure,
pub x_pm2_control_block: GenericAddressStructure,
pub x_pm_timer_block: GenericAddressStructure,
pub x_gpe0_block: GenericAddressStructure,
pub x_gpe1_block: GenericAddressStructure,
}
*/
impl Fadt {
pub fn new(sdt: &'static Sdt) -> Option<Fadt> {
if &sdt.signature == b"FACP" && sdt.length as usize >= mem::size_of::<Fadt>() {
Some(unsafe { ptr::read((sdt as *const Sdt) as *const Fadt) })
} else {
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

@@ -6,7 +6,7 @@ use crate::memory::Frame;
use crate::paging::{ActivePageTable, PhysicalAddress, Page, PageFlags, VirtualAddress};
use super::sdt::Sdt;
use super::{ACPI_TABLE, find_sdt, load_table, get_sdt_signature};
use super::{ACPI_TABLE, find_sdt};
#[repr(packed)]
#[derive(Clone, Copy, Debug, Default)]
@@ -38,7 +38,6 @@ impl 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");

View File

@@ -4,7 +4,7 @@ use crate::memory::{allocate_frames, Frame};
use crate::paging::{ActivePageTable, Page, PageFlags, PhysicalAddress, VirtualAddress};
use super::sdt::Sdt;
use super::{find_sdt, load_table, get_sdt_signature};
use super::find_sdt;
use core::intrinsics::{atomic_load, atomic_store};
use core::sync::atomic::Ordering;
@@ -31,7 +31,6 @@ 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");

View File

@@ -6,18 +6,12 @@ use alloc::string::String;
use alloc::vec::Vec;
use alloc::boxed::Box;
use syscall::io::{Io, Pio};
use spin::RwLock;
use crate::stop::kstop;
use spin::{Once, RwLock};
use crate::log::info;
use crate::memory::Frame;
use crate::paging::{ActivePageTable, Page, PageFlags, PhysicalAddress, VirtualAddress};
use self::dmar::Dmar;
use self::fadt::Fadt;
use self::madt::Madt;
use self::rsdt::Rsdt;
use self::sdt::Sdt;
@@ -26,16 +20,11 @@ use self::hpet::Hpet;
use self::rxsdt::Rxsdt;
use self::rsdp::RSDP;
use self::aml::{parse_aml_table, AmlError, AmlValue};
pub mod hpet;
mod dmar;
mod fadt;
pub mod madt;
mod rsdt;
pub mod sdt;
mod xsdt;
pub mod aml;
mod rxsdt;
mod rsdp;
@@ -67,48 +56,20 @@ pub fn get_sdt(sdt_address: usize, active_table: &mut ActivePageTable) -> &'stat
sdt
}
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(); }
pub enum RxsdtEnum {
Rsdt(Rsdt),
Xsdt(Xsdt),
}
impl Rxsdt for RxsdtEnum {
fn iter(&self) -> Box<dyn Iterator<Item = usize>> {
match self {
Self::Rsdt(rsdt) => <Rsdt as Rxsdt>::iter(rsdt),
Self::Xsdt(xsdt) => <Xsdt as Rxsdt>::iter(xsdt),
}
}
}
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!("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);
}
}
pub static RXSDT_ENUM: Once<RxsdtEnum> = Once::new();
/// Parse the ACPI tables to gather CPU, interrupt, and timer information
pub unsafe fn init(active_table: &mut ActivePageTable, already_supplied_rsdps: Option<(u64, u64)>) {
@@ -117,11 +78,6 @@ pub unsafe fn init(active_table: &mut ActivePageTable, already_supplied_rsdps: O
*sdt_ptrs = Some(BTreeMap::new());
}
{
let mut order = SDT_ORDER.write();
*order = Some(vec!());
}
// Search for RSDP
if let Some(rsdp) = RSDP::get_rsdp(active_table, already_supplied_rsdps) {
info!("RSDP: {:?}", rsdp);
@@ -132,15 +88,40 @@ pub unsafe fn init(active_table: &mut ActivePageTable, already_supplied_rsdps: O
}
println!(":");
let rxsdt: Box<dyn Rxsdt + Send + Sync> = if let Some(rsdt) = Rsdt::new(rxsdt) {
Box::new(rsdt)
let rxsdt = if let Some(rsdt) = Rsdt::new(rxsdt) {
let mut initialized = false;
let rsdt = RXSDT_ENUM.call_once(|| {
initialized = true;
RxsdtEnum::Rsdt(rsdt)
});
if !initialized {
log::error!("RXSDT_ENUM already initialized");
}
rsdt
} else if let Some(xsdt) = Xsdt::new(rxsdt) {
Box::new(xsdt)
let mut initialized = false;
let xsdt = RXSDT_ENUM.call_once(|| {
initialized = true;
RxsdtEnum::Xsdt(xsdt)
});
if !initialized {
log::error!("RXSDT_ENUM already initialized");
}
xsdt
} else {
println!("UNKNOWN RSDT OR XSDT SIGNATURE");
return;
};
// TODO: Don't touch ACPI tables in kernel?
rxsdt.map_all(active_table);
for sdt_address in rxsdt.iter() {
@@ -152,47 +133,19 @@ pub unsafe fn init(active_table: &mut ActivePageTable, already_supplied_rsdps: O
}
}
Fadt::init(active_table);
// TODO: Enumerate processors in userspace, and then provide an ACPI-independent interface
// to initialize enumerated processors to userspace?
Madt::init(active_table);
Dmar::init(active_table);
// TODO: Let userspace setup HPET, and then provide an interface to specify which timer to
// use?
Hpet::init(active_table);
init_namespace();
} else {
println!("NO RSDP FOUND");
}
}
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);
}
}
}
}
}
}
pub 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!();
@@ -213,51 +166,12 @@ pub fn get_sdt_signature(sdt: &'static Sdt) -> SdtSignature {
(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: RwLock<Option<Fadt>>,
pub namespace: RwLock<Option<BTreeMap<String, AmlValue>>>,
pub hpet: RwLock<Option<Hpet>>,
pub next_ctx: RwLock<u64>,
}
pub static ACPI_TABLE: Acpi = Acpi {
fadt: RwLock::new(None),
namespace: RwLock::new(None),
hpet: RwLock::new(None),
next_ctx: RwLock::new(0),
};

View File

@@ -1,3 +1,4 @@
use core::convert::TryFrom;
use core::mem;
use alloc::boxed::Box;
@@ -15,6 +16,14 @@ impl Rsdt {
None
}
}
pub fn as_slice(&self) -> &[u8] {
let length = usize::try_from(self.0.length)
.expect("expected 32-bit length to fit within usize");
unsafe {
core::slice::from_raw_parts(self.0 as *const _ as *const u8, length)
}
}
}
impl Rxsdt for Rsdt {

View File

@@ -1,3 +1,4 @@
use core::convert::TryFrom;
use core::mem;
use alloc::boxed::Box;
@@ -15,6 +16,14 @@ impl Xsdt {
None
}
}
pub fn as_slice(&self) -> &[u8] {
let length = usize::try_from(self.0.length)
.expect("expected 32-bit length to fit within usize");
unsafe {
core::slice::from_raw_parts(self.0 as *const _ as *const u8, length)
}
}
}
impl Rxsdt for Xsdt {

View File

@@ -24,9 +24,6 @@ impl IoApicRegs {
// offset 0x10
unsafe { self.pointer.offset(4) }
}
fn read_ioregsel(&self) -> u32 {
unsafe { ptr::read_volatile::<u32>(self.ioregsel()) }
}
fn write_ioregsel(&mut self, value: u32) {
unsafe { ptr::write_volatile::<u32>(self.ioregsel() as *mut u32, value) }
}
@@ -356,7 +353,12 @@ pub unsafe fn init(active_table: &mut ActivePageTable) {
irq::set_irq_method(irq::IrqMethod::Apic);
// tell the firmware that we're using APIC rather than the default 8259 PIC.
#[cfg(feature = "acpi")]
// FIXME: With ACPI moved to userspace, we should instead allow userspace to check whether the
// IOAPIC has been initialized, and then subsequently let some ACPI driver call the AML from
// userspace.
/*#[cfg(feature = "acpi")]
{
let method = {
let namespace_guard = crate::acpi::ACPI_TABLE.namespace.read();
@@ -369,7 +371,7 @@ pub unsafe fn init(active_table: &mut ActivePageTable) {
if let Some(m) = method {
m.execute("\\_PIC".into(), vec!(crate::acpi::aml::AmlValue::Integer(1)));
}
}
}*/
}
fn get_override(irq: u8) -> Option<&'static Override> {
src_overrides().iter().find(|over| over.bus_irq == irq)

View File

@@ -1,5 +1,10 @@
#[cfg(feature = "acpi")]
use crate::acpi;
use crate::{
context,
scheme::acpi,
time,
};
use crate::syscall::io::{Io, Pio};
#[no_mangle]
@@ -22,12 +27,47 @@ pub unsafe extern fn kreset() -> ! {
unreachable!();
}
#[cfg(feature = "acpi")]
fn userspace_acpi_shutdown() {
log::info!("Notifying any potential ACPI driver");
// Tell whatever driver that handles ACPI, that it should enter the S5 state (i.e.
// shutdown).
if ! acpi::register_kstop() {
// There was no context to switch to.
log::info!("No ACPI driver was alive to handle shutdown.");
return;
}
log::info!("Waiting one second for ACPI driver to run the shutdown sequence.");
let (initial_s, initial_ns) = time::monotonic();
// Since this driver is a userspace process, and we do not use any magic like directly
// context switching, we have to wait for the userspace driver to complete, with a timeout.
//
// We switch context, and wait for one second.
loop {
// TODO: Switch directly to whichever process is handling the kstop pipe. We would add an
// event flag like EVENT_DIRECT, which has already been suggested for IRQs.
// TODO: Waitpid with timeout? Because, what if the ACPI driver would crash?
let _ = unsafe { context::switch() };
let (current_s, current_ns) = time::monotonic();
let diff_s = current_s - initial_s;
let diff_part_ns = current_ns - initial_ns;
let diff_ns = diff_s * 1_000_000_000 + diff_part_ns;
if diff_ns > 1_000_000_000 {
log::info!("Timeout reached, thus falling back to other shutdown methods.");
return;
}
}
}
#[no_mangle]
pub unsafe extern fn kstop() -> ! {
println!("kstop");
log::info!("Running kstop()");
#[cfg(feature = "acpi")]
acpi::set_global_s_state(5);
userspace_acpi_shutdown();
// Magic shutdown code for bochs and qemu (older versions).
for c in "Shutdown".bytes() {

View File

@@ -34,7 +34,7 @@ pub enum Status {
Runnable,
Blocked,
Stopped(usize),
Exited(usize)
Exited(usize),
}
#[derive(Copy, Clone, Debug)]

View File

@@ -46,6 +46,7 @@
#![feature(asm)] // TODO: Relax requirements of most asm invocations
#![cfg_attr(target_arch = "aarch64", feature(llvm_asm))] // TODO: Rewrite using asm!
#![feature(concat_idents)]
#![feature(const_btree_new)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(global_asm)]

View File

@@ -1,448 +1,290 @@
use core::convert::TryInto;
use core::fmt::Write;
use core::str;
use core::sync::atomic::{self, AtomicUsize};
use alloc::boxed::Box;
use alloc::collections::BTreeMap;
use alloc::vec::Vec;
use syscall::data::Stat;
use syscall::error::{EACCES, EBADF, EBADFD, EINVAL, EIO, EISDIR, ENOENT, ENOTDIR};
use syscall::flag::{O_ACCMODE, O_DIRECTORY, O_RDWR, O_STAT, O_WRONLY};
use syscall::scheme::{calc_seek_offset_usize, Scheme};
use syscall::{Error, Result};
use syscall::{MODE_DIR, MODE_FILE};
use spin::{Mutex, Once, RwLock};
use spin::{Mutex, RwLock};
use crate::acpi::{RXSDT_ENUM, RxsdtEnum};
use crate::event;
use crate::scheme::SchemeId;
use crate::sync::WaitCondition;
use crate::acpi::sdt::Sdt;
use crate::acpi::SdtSignature;
use crate::paging::{ActivePageTable, TableKind};
use crate::syscall::data::Stat;
use crate::syscall::error::{EACCES, EBADF, EBADFD, EINTR, EINVAL, EISDIR, ENOENT, ENOTDIR, EROFS};
use crate::syscall::flag::{
EventFlags, EVENT_READ,
MODE_CHR, MODE_DIR, MODE_FILE,
O_ACCMODE, O_CREAT, O_DIRECTORY, O_EXCL, O_RDONLY, O_STAT, O_SYMLINK,
SEEK_SET, SEEK_CUR, SEEK_END,
};
use crate::syscall::scheme::Scheme;
use crate::syscall::error::{Error, Result};
#[derive(Clone, Copy)]
struct PhysSlice {
phys_ptr: usize,
len: usize,
/// These appear to be identity mapped, so this is technically not needed.
virt: usize,
}
/// A scheme used to access the RSDT or XSDT, which is needed for e.g. `acpid` to function.
pub struct AcpiScheme;
/// A scheme used to access ACPI tables needed for some drivers to function (e.g. pcid with the
/// PCIe "MCFG" table).
///
/// # Layout
/// * `/tables`
/// * _can be listed to retrieve the available tables_
/// * e.g. MCFG-<OEM ID in hex>-<OEM TABLE ID in hex>
/// * _maybe_ the MADT, in case some userspace driver takes care of the I/O APIC.
/// * _perhaps_ some interface for e.g. power management.
pub struct AcpiScheme {
handles: RwLock<BTreeMap<usize, Mutex<Handle>>>,
tables: Vec<(SdtSignature, PhysSlice)>,
next_fd: AtomicUsize,
}
const TOPLEVEL_DIR_CONTENTS: &[u8] = b"tables\n";
const ALLOWED_TABLES: &[[u8; 4]] = &[*b"MCFG", *b"APIC"];
// XXX: Why can't core also have something like std::io::Take? It's not even real I/O!
/// An internal wrapper struct that limits the number of bytes that can be fmt-written, in order to
/// properly return the length when reading directories etc. The bytes that cannot be written will
/// be discarded.
struct Take<'a> {
buf: &'a mut [u8],
struct Handle {
offset: usize,
kind: HandleKind,
stat: bool,
}
#[derive(Eq, PartialEq)]
enum HandleKind {
TopLevel,
Rxsdt,
ShutdownPipe,
}
impl Take<'_> {
pub fn write_to_buf<'a>(buf: &'a mut [u8]) -> Take<'a> {
Take { offset: 0, buf }
}
pub fn bytes_currently_written(&self) -> usize {
self.offset
}
}
static HANDLES: RwLock<BTreeMap<usize, Handle>> = RwLock::new(BTreeMap::new());
static NEXT_FD: AtomicUsize = AtomicUsize::new(0);
impl<'a> core::fmt::Write for Take<'a> {
fn write_str(&mut self, string: &str) -> core::fmt::Result {
if self.offset > self.buf.len() {
return Ok(());
static DATA: Once<Box<[u8]>> = Once::new();
const TOPLEVEL_CONTENTS: &[u8] = b"rxsdt\nkstop\n";
static KSTOP_WAITCOND: WaitCondition = WaitCondition::new();
static KSTOP_FLAG: Mutex<bool> = Mutex::new(false);
static SCHEME_ID: Once<SchemeId> = Once::new();
pub fn register_kstop() -> bool {
*KSTOP_FLAG.lock() = true;
let mut waiters_awoken = KSTOP_WAITCOND.notify();
if let Some(&acpi_scheme) = SCHEME_ID.r#try() {
let handles = HANDLES.read();
for (&fd, _) in handles.iter().filter(|(_, handle)| handle.kind == HandleKind::ShutdownPipe) {
event::trigger(acpi_scheme, fd, EVENT_READ);
waiters_awoken += 1;
}
let string_bytes = string.as_bytes();
let max = core::cmp::min(string_bytes.len() + self.offset, self.buf.len()) - self.offset;
self.buf[self.offset..self.offset + max].copy_from_slice(&string_bytes[..max]);
self.offset += max;
Ok(())
} else {
log::error!("Calling register_kstop before kernel ACPI scheme was initialized");
}
}
enum Handle {
TopLevel(usize), // seek offset
Tables(usize), // seek offset
if waiters_awoken == 0 {
log::error!("No userspace ACPI handler was notified when trying to shutdown. This is bad.");
// Let the kernel shutdown without ACPI.
return false;
}
Table {
name: [u8; 4],
oem_id: [u8; 6],
oem_table_id: [u8; 8],
offset: usize, // seek offset
},
// TODO: Context switch directly to the waiting context, to avoid annoying timeouts.
true
}
impl AcpiScheme {
fn get_tables() -> Vec<(SdtSignature, PhysSlice)> {
let mut active_table = unsafe { ActivePageTable::new(TableKind::Kernel) };
pub fn new(id: SchemeId) -> Self {
// NOTE: This __must__ be called from the main kernel context, while initializing all
// schemes. If it is called by any other context, then all ACPI data will probably not even
// be mapped.
let mut tables = Vec::new();
let mut data_init = false;
let mut id_init = false;
for allowed_tbl_name in ALLOWED_TABLES.iter() {
use crate::acpi::{find_sdt, get_sdt, get_sdt_signature};
DATA.call_once(|| {
data_init = true;
// it appears that the SDTs are identity mapped, in which case we can just call get_sdt
// whenever we need to and use the slice as if it was physical.
let rsdt_or_xsdt = RXSDT_ENUM
.r#try()
.expect("expected RXSDT_ENUM to be initialized before AcpiScheme");
let table_name_str =
str::from_utf8(allowed_tbl_name).expect("ACPI table name wasn't correct UTF-8");
let table = match rsdt_or_xsdt {
RxsdtEnum::Rsdt(rsdt) => rsdt.as_slice(),
RxsdtEnum::Xsdt(xsdt) => xsdt.as_slice(),
};
for sdt in find_sdt(table_name_str) {
let virt =
get_sdt(sdt as *const Sdt as usize, &mut active_table) as *const Sdt as usize;
let signature = get_sdt_signature(sdt);
let sdt_pointer = sdt as *const Sdt as usize;
let len = sdt.length as usize;
assert_eq!(virt, sdt_pointer);
tables.push((
signature,
PhysSlice {
phys_ptr: sdt_pointer,
len,
virt,
},
));
}
Box::from(table)
});
SCHEME_ID.call_once(|| {
id_init = true;
id
});
if !data_init || !id_init {
log::error!("AcpiScheme::init called multiple times");
}
tables
}
pub fn new() -> Self {
Self {
handles: RwLock::new(BTreeMap::new()),
tables: Self::get_tables(),
next_fd: AtomicUsize::new(0),
}
}
fn lookup_signature_index(
&self,
name: [u8; 4],
oem_id: [u8; 6],
oem_table_id: [u8; 8],
) -> Option<usize> {
self.tables
.iter()
.position(|((sig_name, sig_oem_id, sig_oem_table_id), _)| {
sig_name.as_bytes() == &name
&& sig_oem_id == &oem_id
&& sig_oem_table_id == &oem_table_id
})
}
fn lookup_signature(
&self,
name: [u8; 4],
oem_id: [u8; 6],
oem_table_id: [u8; 8],
) -> Option<PhysSlice> {
Some(self.tables[self.lookup_signature_index(name, oem_id, oem_table_id)?].1)
}
}
fn parse_table_filename(filename: &[u8]) -> Option<([u8; 4], [u8; 6], [u8; 8])> {
// the table identifier takes the form:
// 1. a four byte table name, like 'APIC' (MADT) or 'MCFG'.
// 2. a dash followed by 12 hexadecimal digits (6 bytes when decoded) composing the OEM ID.
// 3. another dash followed by 16 hex digits (8 bytes), composing the OEM Table ID.
// hence, the table is 4 + 1 + 12 + 1 + 16 = 34 bytes long.
if filename.len() != 34 {
return None;
Self
}
let mut table_identifier = [0u8; 34];
table_identifier.copy_from_slice(filename);
let table_name = &table_identifier[..4];
if table_identifier[4] != b'-' {
return None;
}
let oem_id_hex = &table_identifier[5..17];
if table_identifier[17] != b'-' {
return None;
}
let oem_table_id_hex = &table_identifier[18..34];
let oem_id_hex_str = str::from_utf8(oem_id_hex).ok()?;
let oem_table_id_hex_str = str::from_utf8(oem_table_id_hex).ok()?;
let mut oem_id = [0u8; 6];
for index in 0..oem_id.len() {
oem_id[index] = u8::from_str_radix(&oem_id_hex_str[index * 2..(index + 1) * 2], 16).ok()?;
}
let mut oem_table_id = [0u8; 8];
for index in 0..oem_table_id.len() {
oem_table_id[index] =
u8::from_str_radix(&oem_table_id_hex_str[index * 2..(index + 1) * 2], 16).ok()?;
}
Some((table_name.try_into().unwrap(), oem_id, oem_table_id))
}
fn serialize_table_filename(
buffer: &mut [u8],
(table_name, oem_id, oem_table_id): ([u8; 4], [u8; 6], [u8; 8]),
) -> usize {
let mut wrapper = Take::write_to_buf(buffer);
write!(
wrapper,
"{}-",
str::from_utf8(&table_name).expect("Acpi table id wasn't valid UTF-8")
)
.unwrap();
for b in &oem_id {
write!(wrapper, "{:2x}", b).unwrap();
}
write!(wrapper, "-").unwrap();
for b in &oem_table_id {
write!(wrapper, "{:2x}", b).unwrap();
}
wrapper.bytes_currently_written()
}
impl Scheme for AcpiScheme {
fn open(&self, path: &str, flags: usize, opener_uid: u32, _opener_gid: u32) -> Result<usize> {
let path = path.trim_start_matches('/');
if opener_uid != 0 {
return Err(Error::new(EACCES));
}
let path_str = path.trim_start_matches('/');
// TODO: Use some kind of component iterator.
let new_handle = if path_str.starts_with("tables") {
let subpath = (&path_str[6..]).trim_start_matches('/');
if subpath.is_empty() {
// List of ACPI tables
if (flags & O_DIRECTORY == 0 && flags & O_STAT == 0)
|| (flags & O_ACCMODE == O_WRONLY || flags & O_ACCMODE == O_RDWR)
{
if flags & O_CREAT == O_CREAT {
return Err(Error::new(EROFS));
}
if flags & O_EXCL == O_EXCL || flags & O_SYMLINK == O_SYMLINK {
return Err(Error::new(EINVAL));
}
if flags & O_ACCMODE != O_RDONLY && flags & O_STAT != O_STAT {
return Err(Error::new(EROFS));
}
let handle_kind = match path {
"" => {
if flags & O_DIRECTORY != O_DIRECTORY && flags & O_STAT != O_STAT {
return Err(Error::new(EISDIR));
}
Handle::Tables(0)
} else {
if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 {
HandleKind::TopLevel
}
"rxsdt" => {
if flags & O_DIRECTORY == O_DIRECTORY && flags & O_STAT != O_STAT {
return Err(Error::new(ENOTDIR));
}
if flags & O_ACCMODE == O_WRONLY || flags & O_ACCMODE == O_RDWR {
return Err(Error::new(EINVAL));
}
let (name, oem_id, oem_table_id) =
parse_table_filename(subpath.as_bytes()).ok_or(Error::new(ENOENT))?;
if self
.lookup_signature_index(name, oem_id, oem_table_id)
.is_none()
{
return Err(Error::new(ENOENT));
}
Handle::Table {
name,
oem_id,
oem_table_id,
offset: 0,
}
HandleKind::Rxsdt
}
} else if path.is_empty() {
// Top-level
if (flags & O_DIRECTORY == 0 && flags & O_STAT == 0)
|| (flags & O_ACCMODE == O_WRONLY || flags & O_ACCMODE == O_RDWR)
{
return Err(Error::new(EISDIR));
"kstop" => {
if flags & O_DIRECTORY == O_DIRECTORY && flags & O_STAT != O_STAT {
return Err(Error::new(ENOTDIR));
}
HandleKind::ShutdownPipe
}
Handle::TopLevel(0)
} else {
return Err(Error::new(ENOENT));
_ => return Err(Error::new(ENOENT)),
};
let new_fd = self.next_fd.fetch_add(1, atomic::Ordering::SeqCst);
self.handles.write().insert(new_fd, Mutex::new(new_handle));
Ok(new_fd)
}
fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
let handles_guard = self.handles.read();
let handle = handles_guard.get(&id).ok_or(Error::new(EBADF))?.lock();
Ok(match &*handle {
&Handle::TopLevel(_) => {
let path = b"acpi:";
let max = core::cmp::min(buf.len(), path.len());
buf[..max].copy_from_slice(&path[..]);
max
}
&Handle::Tables(_) => {
let path = b"acpi:tables";
let max = core::cmp::min(buf.len(), path.len());
buf[..max].copy_from_slice(&path[..]);
max
}
&Handle::Table {
name,
oem_id,
oem_table_id,
..
} => {
let base_path = b"acpi:tables/";
let base_max = core::cmp::min(buf.len(), base_path.len());
buf[..base_max].copy_from_slice(&base_path[..]);
serialize_table_filename(&mut buf[base_max..], (name, oem_id, oem_table_id))
}
})
let fd = NEXT_FD.fetch_add(1, atomic::Ordering::Relaxed);
let mut handles_guard = HANDLES.write();
let _ = handles_guard.insert(fd, Handle {
offset: 0,
kind: handle_kind,
stat: flags & O_STAT == O_STAT,
});
Ok(fd)
}
fn fstat(&self, id: usize, stat: &mut Stat) -> Result<usize> {
let handles_guard = self.handles.read();
let handle = handles_guard.get(&id).ok_or(Error::new(EBADF))?.lock();
let handles = HANDLES.read();
let handle = handles.get(&id).ok_or(Error::new(EBADF))?;
match &*handle {
&Handle::TopLevel(_) => {
stat.st_mode = MODE_DIR;
stat.st_size = TOPLEVEL_DIR_CONTENTS.len() as u64;
}
&Handle::Tables(_) => {
stat.st_mode = MODE_DIR;
stat.st_size = (self.tables.len() * 35) as u64; // fixed size of 34 bytes for the file names, plus a newline
}
&Handle::Table {
name,
oem_id,
oem_table_id,
..
} => {
let len = self
.lookup_signature(name, oem_id, oem_table_id)
.ok_or(Error::new(EBADFD))?
.len;
match handle.kind {
HandleKind::Rxsdt => {
let data = DATA.r#try().ok_or(Error::new(EBADFD))?;
stat.st_mode = MODE_FILE;
stat.st_size = len as u64;
stat.st_size = data.len().try_into().unwrap_or(u64::max_value());
}
HandleKind::TopLevel => {
stat.st_mode = MODE_DIR;
stat.st_size = TOPLEVEL_CONTENTS.len().try_into().unwrap_or(u64::max_value());
}
HandleKind::ShutdownPipe => {
stat.st_mode = MODE_CHR;
stat.st_size = 1;
}
}
Ok(0)
}
fn seek(&self, id: usize, pos: isize, whence: usize) -> Result<isize> {
let handles_guard = self.handles.read();
let mut handle = handles_guard.get(&id).ok_or(Error::new(EBADF))?.lock();
let mut handles = HANDLES.write();
let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
let (cur_offset, length) = match &*handle {
&Handle::TopLevel(offset) => (offset, TOPLEVEL_DIR_CONTENTS.len()),
&Handle::Tables(offset) => (offset, (self.tables.len() * 35)),
&Handle::Table {
name,
oem_id,
oem_table_id,
offset,
} => (
offset,
self.lookup_signature(name, oem_id, oem_table_id)
.ok_or(Error::new(EBADFD))?
.len,
),
if handle.stat {
return Err(Error::new(EBADF));
}
let file_len = match handle.kind {
HandleKind::Rxsdt => DATA.r#try().ok_or(Error::new(EBADFD))?.len(),
HandleKind::ShutdownPipe => 1,
HandleKind::TopLevel => TOPLEVEL_CONTENTS.len(),
};
let new_offset = calc_seek_offset_usize(cur_offset, pos, whence, length)?;
match &mut *handle {
&mut Handle::Table { ref mut offset, .. }
| &mut Handle::Tables(ref mut offset)
| &mut Handle::TopLevel(ref mut offset) => *offset = new_offset as usize,
}
Ok(new_offset)
let new_offset = match whence {
SEEK_SET => pos as usize,
SEEK_CUR => if pos < 0 {
handle.offset.checked_sub((-pos) as usize).ok_or(Error::new(EINVAL))?
} else {
handle.offset.saturating_add(pos as usize)
}
SEEK_END => if pos < 0 {
file_len.checked_sub((-pos) as usize).ok_or(Error::new(EINVAL))?
} else {
file_len
}
_ => return Err(Error::new(EINVAL)),
};
handle.offset = new_offset;
Ok(new_offset as isize)
}
fn read(&self, id: usize, mut buf: &mut [u8]) -> Result<usize> {
let handles_guard = self.handles.read();
let mut handle = handles_guard.get(&id).ok_or(Error::new(EBADF))?.lock();
fn read(&self, id: usize, dst_buf: &mut [u8]) -> Result<usize> {
let mut handles = HANDLES.write();
let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
match &mut *handle {
&mut Handle::TopLevel(ref mut offset) => {
let max_bytes_to_read = core::cmp::min(buf.len(), TOPLEVEL_DIR_CONTENTS.len());
let bytes_to_read = core::cmp::max(max_bytes_to_read, *offset) - *offset;
buf[..bytes_to_read]
.copy_from_slice(&TOPLEVEL_DIR_CONTENTS[*offset..*offset + bytes_to_read]);
*offset += bytes_to_read;
Ok(bytes_to_read)
}
&mut Handle::Tables(ref mut offset) => {
if *offset >= self.tables.len() * 35 {
return Ok(0);
}
// one really good thing with fixed size filenames, is that no index has to be
// stored anywhere!
let base_table_index = *offset / 35;
let mut bytes_to_skip = *offset % 35;
let mut bytes_read = 0;
for index in base_table_index..self.tables.len() {
let &(ref name_string, oem_id, oem_table_id) = &self.tables[index].0;
let signature = (
name_string.as_bytes().try_into().or(Err(Error::new(EIO)))?,
oem_id,
oem_table_id,
);
let mut src_buf = [0u8; 35];
serialize_table_filename(&mut src_buf[..34], signature);
src_buf[34] = b'\n';
let max_bytes_to_read = core::cmp::min(buf.len(), src_buf.len());
let bytes_to_read =
core::cmp::max(max_bytes_to_read, bytes_to_skip) - bytes_to_skip;
buf[..bytes_to_read].copy_from_slice(&src_buf[..bytes_to_read]);
bytes_read += bytes_to_read;
bytes_to_skip = 0;
buf = &mut buf[bytes_to_read..];
}
*offset += bytes_read;
Ok(bytes_read)
}
&mut Handle::Table {
name,
oem_id,
oem_table_id,
ref mut offset,
} => {
let index = self
.lookup_signature_index(name, oem_id, oem_table_id)
.ok_or(Error::new(EBADFD))?;
let (
_,
PhysSlice {
phys_ptr,
len,
virt: old_virt,
},
) = self.tables[index];
assert_eq!(phys_ptr, old_virt);
let new_virt =
crate::acpi::get_sdt(phys_ptr, unsafe { &mut ActivePageTable::new(TableKind::Kernel) })
as *const Sdt as usize;
let table_contents =
unsafe { core::slice::from_raw_parts(new_virt as *const u8, len) };
let max_bytes_to_read = core::cmp::min(buf.len(), table_contents.len());
let bytes_to_read = core::cmp::max(max_bytes_to_read, *offset) - *offset;
buf[..bytes_to_read]
.copy_from_slice(&table_contents[*offset..*offset + bytes_to_read]);
*offset += bytes_to_read;
Ok(bytes_to_read)
}
if handle.stat {
return Err(Error::new(EBADF));
}
let data = match handle.kind {
HandleKind::ShutdownPipe => {
let dst_byte = match dst_buf.first_mut() {
None => return Ok(0),
Some(dst) => if handle.offset >= 1 {
return Ok(0)
} else {
dst
},
};
loop {
let flag_guard = KSTOP_FLAG.lock();
if *flag_guard {
break;
} else if ! KSTOP_WAITCOND.wait(flag_guard, "waiting for kstop") {
return Err(Error::new(EINTR));
}
}
*dst_byte = 0x42;
handle.offset = 1;
return Ok(1);
}
HandleKind::Rxsdt => DATA.r#try().ok_or(Error::new(EBADFD))?,
HandleKind::TopLevel => TOPLEVEL_CONTENTS,
};
let src_offset = core::cmp::min(handle.offset, data.len());
let src_buf = data
.get(src_offset..)
.expect("expected data to be at least data.len() bytes long");
let bytes_to_copy = core::cmp::min(dst_buf.len(), src_buf.len());
dst_buf[..bytes_to_copy].copy_from_slice(&src_buf[..bytes_to_copy]);
handle.offset += bytes_to_copy;
Ok(bytes_to_copy)
}
// TODO
fn fevent(&self, id: usize, _flags: EventFlags) -> Result<EventFlags> {
let handles = HANDLES.read();
let handle = handles.get(&id).ok_or(Error::new(EBADF))?;
if handle.stat {
return Err(Error::new(EBADF));
}
Ok(EventFlags::empty())
}
fn write(&self, _id: usize, _buf: &[u8]) -> Result<usize> {
Err(Error::new(EBADF))
}
fn close(&self, id: usize) -> Result<usize> {
if HANDLES.write().remove(&id).is_none() {
return Err(Error::new(EBADF));
}
Ok(0)
}
}

View File

@@ -162,7 +162,7 @@ impl SchemeList {
// These schemes should only be available on the root
#[cfg(all(feature = "acpi", target_arch = "x86_64"))] {
self.insert(ns, "acpi", |_| Arc::new(AcpiScheme::new())).unwrap();
self.insert(ns, "kernel/acpi", |scheme_id| Arc::new(AcpiScheme::new(scheme_id))).unwrap();
}
self.insert(ns, "debug", |scheme_id| Arc::new(DebugScheme::new(scheme_id))).unwrap();
self.insert(ns, "initfs", |_| Arc::new(InitFsScheme::new())).unwrap();

View File

@@ -10,7 +10,7 @@ pub struct WaitCondition {
}
impl WaitCondition {
pub fn new() -> WaitCondition {
pub const fn new() -> WaitCondition {
WaitCondition {
contexts: Mutex::new(Vec::new())
}

View File

@@ -1148,6 +1148,22 @@ pub fn exit(status: usize) -> ! {
context.id
};
// TODO: Find a better way to implement this, perhaps when the init process calls exit.
if pid == ContextId::from(1) {
println!("Main kernel thread exited with status {:X}", status);
extern {
fn kreset() -> !;
fn kstop() -> !;
}
if status == SIGTERM {
unsafe { kreset(); }
} else {
unsafe { kstop(); }
}
}
// Files must be closed while context is valid so that messages can be passed
for (_fd, file_opt) in close_files.drain(..).enumerate() {
if let Some(file) = file_opt {
@@ -1214,21 +1230,6 @@ pub fn exit(status: usize) -> ! {
// Alert any tracers waiting of this process
ptrace::close_tracee(pid);
if pid == ContextId::from(1) {
println!("Main kernel thread exited with status {:X}", status);
extern {
fn kreset() -> !;
fn kstop() -> !;
}
if status == SIGTERM {
unsafe { kreset(); }
} else {
unsafe { kstop(); }
}
}
}
let _ = unsafe { context::switch() };