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:
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
@@ -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,
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
124
src/acpi/fadt.rs
124
src/acpi/fadt.rs
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
|
||||
@@ -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");
|
||||
|
||||
172
src/acpi/mod.rs
172
src/acpi/mod.rs
@@ -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),
|
||||
};
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -34,7 +34,7 @@ pub enum Status {
|
||||
Runnable,
|
||||
Blocked,
|
||||
Stopped(usize),
|
||||
Exited(usize)
|
||||
Exited(usize),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -10,7 +10,7 @@ pub struct WaitCondition {
|
||||
}
|
||||
|
||||
impl WaitCondition {
|
||||
pub fn new() -> WaitCondition {
|
||||
pub const fn new() -> WaitCondition {
|
||||
WaitCondition {
|
||||
contexts: Mutex::new(Vec::new())
|
||||
}
|
||||
|
||||
@@ -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() };
|
||||
|
||||
Reference in New Issue
Block a user