switch to aml crate, implement acpi:/symbols

This commit is contained in:
Ron Williams
2023-01-22 19:42:41 -08:00
parent c9722c4024
commit f4564d6caf
16 changed files with 401 additions and 5294 deletions
+333 -16
View File
@@ -1,4 +1,4 @@
use std::collections::BTreeMap;
use rustc_hash::FxHashSet;
use std::convert::{TryFrom, TryInto};
use std::ops::Deref;
use std::sync::Arc;
@@ -6,10 +6,13 @@ use std::{fmt, mem};
use syscall::flag::PhysmapFlags;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
use syscall::io::{Io, Pio};
use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use thiserror::Error;
use super::aml::AmlValue;
use aml::{AmlContext, AmlName};
pub mod dmar;
use self::dmar::Dmar;
@@ -219,14 +222,29 @@ impl fmt::Debug for Sdt {
pub struct Dsdt(Sdt);
pub struct Ssdt(Sdt);
#[derive(Debug, Error)]
pub enum SymbolListError {
#[error("Aml Internal Error")]
AmlInternalError,
}
pub struct AmlSymbols {
pub symbols_str: String,
symbols_hash: FxHashSet<String>,
}
pub struct AcpiContext {
tables: Vec<Sdt>,
dsdt: Option<Dsdt>,
fadt: Option<Fadt>,
// TODO: Remove Option. This is not kernel code, and not static, but we still need to replace
// every match where namespace{,_mut}() are used.
namespace: RwLock<Option<BTreeMap<String, AmlValue>>>,
// the aml parser
aml_context: RwLock<AmlContext>,
// Use to cache the symbols list, which doesn't change very often
// Set it to None if the ACPI tables change e.g. due to PnP
aml_symbols: RwLock<Option<AmlSymbols>>,
// TODO: The kernel ACPI code seemed to use load_table quite ubiquitously, however ACPI 5.1
// states that DDBHandles can only be obtained when loading XSDT-pointed tables. So, we'll
@@ -236,6 +254,7 @@ pub struct AcpiContext {
pub next_ctx: RwLock<u64>,
}
impl AcpiContext {
pub fn init(rxsdt_physaddrs: impl Iterator<Item = u64>) -> Self {
let tables = rxsdt_physaddrs.map(|physaddr| {
@@ -243,7 +262,7 @@ impl AcpiContext {
.try_into()
.expect("expected ACPI addresses to be compatible with the current word size");
log::debug!("TABLE AT {:#>08X}", physaddr);
log::trace!("TABLE AT {:#>08X}", physaddr);
Sdt::load_from_physical(physaddr)
.expect("failed to load physical SDT")
@@ -253,7 +272,10 @@ impl AcpiContext {
tables,
dsdt: None,
fadt: None,
namespace: RwLock::new(Some(BTreeMap::new())),
aml_context: RwLock::new(AmlContext::new(Box::new(AmlPhysMemHandler), aml::DebugVerbosity::None)),
aml_symbols: RwLock::new(None),
next_ctx: RwLock::new(0),
sdt_order: RwLock::new(Vec::new()),
@@ -266,10 +288,28 @@ impl AcpiContext {
Fadt::init(&mut this);
//TODO (hangs on real hardware): Dmar::init(&this);
crate::aml::init_namespace(&this);
if let Some(mut parser) = this.aml_context.try_write() {
if let Some(dsdt) = this.dsdt() {
match parser.parse_table(dsdt.aml()) {
Ok(_) => log::trace!("Parsed DSDT"),
Err(e) => {
log::error!("DSDT: {:?}", e);
}
}
} else {
log::error!("No DSDT for aml parsing");
}
for (path, _) in this.namespace.get_mut().as_mut().unwrap().iter() {
log::trace!("ACPI NS: {}", path);
for ssdt in this.ssdts() {
match parser.parse_table(ssdt.aml()) {
Ok(_) => log::trace!("Parsed SSDT"),
Err(e) => {
log::error!("SSDT: {:?}", e);
}
}
}
} else {
log::error!("Failed to obtain aml_context");
}
this
@@ -296,12 +336,6 @@ impl AcpiContext {
pub fn take_single_sdt(&self, signature: [u8; 4]) -> Option<Sdt> {
self.find_single_sdt_pos(signature).map(|pos| self.tables[pos].clone())
}
pub fn namespace(&self) -> RwLockReadGuard<'_, Option<BTreeMap<String, AmlValue>>> {
self.namespace.read()
}
pub fn namespace_mut(&self) -> RwLockWriteGuard<'_, Option<BTreeMap<String, AmlValue>>> {
self.namespace.write()
}
pub fn fadt(&self) -> Option<&Fadt> {
self.fadt.as_ref()
}
@@ -320,6 +354,204 @@ impl AcpiContext {
pub fn new_index(&self, signature: &SdtSignature) {
self.sdt_order.write().push(Some(*signature));
}
fn aml_context(&self) -> RwLockReadGuard<'_, AmlContext>{
self.aml_context.read()
}
fn aml_context_mut(&self) -> RwLockWriteGuard<'_, AmlContext> {
self.aml_context.write()
}
pub fn aml_lookup(&self, symbol: &str) -> Option<AmlName> {
let aml_name = match AmlName::from_str(symbol) {
Ok(aml_name) => aml_name,
Err(error) => {
log::error!("Lookup failed to convert name to AmlName {}, {:?}", symbol, error);
return None;
}
};
// Check the cache first
if let Ok(symbols_option) = self.aml_symbols() {
if let Some(symbols) = symbols_option.as_ref() {
if symbols.symbols_hash.contains(symbol) {
log::trace!("Found symbol in cache, {}", symbol);
return Some(aml_name);
}
}
}
// Symbol does not exactly match cache, allow lookup using namespace rules
let aml_ctx = self.aml_context();
let root = aml::AmlName::root();
if aml_ctx.namespace.get_by_path(&aml_name).is_ok()
|| aml_ctx.namespace.search_for_level(&aml_name, &root).is_ok()
{
Some(aml_name)
} else {
log::trace!("Lookup did not find {}", aml_name);
None
}
}
pub fn aml_symbols(&self) -> Result<RwLockReadGuard<'_, Option<AmlSymbols>>, SymbolListError> {
// Some private functions for building the symbol name correctly and efficiently
fn level_name(level_aml_name: &aml::AmlName) -> String {
let mut name = level_aml_name.as_string();
// remove unnecessary underscores
while let Some(index) = name.find("_.") {
name.remove(index);
}
while name.len() > 0 && &name[name.len() - 1..] == "_" {
name.pop();
}
name.shrink_to_fit();
name
}
fn child_symbol(level_name: &str, value_name: &str) -> String {
let mut name = String::with_capacity(level_name.len() + 1 + value_name.len());
name.push_str(level_name);
name.push('.');
name.push_str(value_name.trim_end_matches('_'));
name.shrink_to_fit();
name
}
fn root_symbol(value_name: &str) -> String {
let mut name = String::with_capacity(1 + value_name.len());
name.push('\\');
name.push_str(value_name.trim_end_matches('_'));
name.shrink_to_fit();
name
}
// return the cached value if it exists
let symbols = self.aml_symbols.read();
if symbols.is_some() {
return Ok(symbols);
}
// free the read lock
drop(symbols);
// List has not been initialized, we have to build it
log::trace!("Creating symbols list");
let mut symbols_str: String = String::with_capacity(30000);
let mut symbols_hash: FxHashSet<String> = FxHashSet::default();
// Get write lock because traverse requires mut
let mut aml_ctx = self.aml_context_mut();
let root = aml::AmlName::root();
let traverse = aml_ctx.namespace.traverse(| level_aml_name, level | {
let level_is_root = level_aml_name.eq(&root);
let level_name = level_name(level_aml_name);
for (name, _handle) in level.values.iter() {
// Create the name of the symbol as "\levelname.symbolname"
let symbol = if level_is_root {
root_symbol(name.as_str())
} else {
child_symbol(&level_name, name.as_str())
};
symbols_str.push_str(&symbol);
symbols_str.push('\n');
symbols_hash.insert(symbol);
}
Ok(true)
});
match traverse {
Err(error) => {
log::error!("Traverse failed, {:?}", error);
return Err(SymbolListError::AmlInternalError);
}
_ => {}
}
symbols_str.shrink_to_fit();
// Cache the new list
log::trace!("Updating symbols list");
let mut write_guarded_symbols = self.aml_symbols.write();
*write_guarded_symbols = Some(AmlSymbols { symbols_str, symbols_hash });
// return the cached value
Ok(RwLockWriteGuard::downgrade(write_guarded_symbols))
}
/// Discard any cached symbols list. To be called if the AML namespace changes.
/// The caller must have at least a Read Lock on the aml context to ensure
/// the cached list is not out of sync with the namespace.
pub fn aml_symbols_reset(&self) {
let mut symbols = self.aml_symbols.write();
*symbols = None;
}
/// Set Power State
/// See https://uefi.org/sites/default/files/resources/ACPI_6_1.pdf
/// - search for PM1a
/// See https://forum.osdev.org/viewtopic.php?t=16990 for practical details
pub fn set_global_s_state(&self, state: u8) {
if state != 5 {
return;
}
let fadt = match self.fadt() {
Some(fadt) => fadt,
None => {
log::error!("Cannot set global S-state due to missing FADT.");
return;
}
};
let port = fadt.pm1a_control_block as u16;
let mut val = 1 << 13;
let aml_ctx = self.aml_context();
let s5_aml_name = match aml::AmlName::from_str("\\_S5") {
Ok(aml_name) => aml_name,
Err(error) => { log::error!("Could not build AmlName for \\_S5, {:?}", error); return; }
};
let s5 = match aml_ctx.namespace.get_by_path(&s5_aml_name) {
Ok(s5) => s5,
Err(error) => { log::error!("Cannot set S-state, missing \\_S5, {:?}", error); return; }
};
let package = match s5 {
aml::AmlValue::Package(package) => package,
_ => { log::error!("Cannot set S-state, \\_S5 is not a package"); return; }
};
let slp_typa = match package[0] {
aml::AmlValue::Integer(i) => i,
_ => { log::error!("typa is not an Integer"); return; }
};
let slp_typb = match package[1] {
aml::AmlValue::Integer(i) => i,
_ => { log::error!("typb is not an Integer"); return; }
};
log::trace!("Shutdown SLP_TYPa {:X}, SLP_TYPb {:X}", slp_typa, slp_typb);
val |= slp_typa as u16;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
{
log::warn!("Shutdown with ACPI outw(0x{:X}, 0x{:X})", port, val);
Pio::<u16>::new(port).write(val);
}
// TODO: Handle SLP_TYPb
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
{
log::error!("Cannot shutdown with ACPI outw(0x{:X}, 0x{:X}) on this architecture", port, val);
}
loop {
core::hint::spin_loop();
}
}
}
#[repr(packed)]
@@ -539,3 +771,88 @@ impl AmlContainingTable for Ssdt {
&*self.0
}
}
struct AmlPhysMemHandler;
impl aml::Handler for AmlPhysMemHandler {
fn read_u8(&self, _address: usize) -> u8 {
log::error!("read u8 {:X}", _address);
0
}
fn read_u16(&self, _address: usize) -> u16 {
log::error!("read u16 {:X}", _address);
0
}
fn read_u32(&self, _address: usize) -> u32 {
log::error!("read u32 {:X}", _address);
0
}
fn read_u64(&self, _address: usize) -> u64 {
log::error!("read u64 {:X}", _address);
0
}
fn write_u8(&mut self, _address: usize, _value: u8) {
log::error!("write u8 {:X}", _address);
}
fn write_u16(&mut self, _address: usize, _value: u16) {
log::error!("write u16 {:X}", _address);
}
fn write_u32(&mut self, _address: usize, _value: u32) {
log::error!("write u32 {:X}", _address);
}
fn write_u64(&mut self, _address: usize, _value: u64) {
log::error!("write u64 {:X}", _address);
}
fn read_io_u8(&self, _port: u16) -> u8 {
log::error!("read io u8 {:X}", _port);
0
}
fn read_io_u16(&self, _port: u16) -> u16 {
log::error!("read io u16 {:X}", _port);
0
}
fn read_io_u32(&self, _port: u16) -> u32 {
log::error!("read io u32 {:X}", _port);
0
}
fn write_io_u8(&self, _port: u16, _value: u8) {
log::error!("write io u8 {:X}", _port);
}
fn write_io_u16(&self, _port: u16, _value: u16) {
log::error!("write io u16 {:X}", _port);
}
fn write_io_u32(&self, _port: u16, _value: u32) {
log::error!("write io u32 {:X}", _port);
}
fn read_pci_u8(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16) -> u8 {
log::error!("read pci u8 {:X}", _device);
0
}
fn read_pci_u16(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16) -> u16 {
log::error!("read pci u8 {:X}", _device);
0
}
fn read_pci_u32(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16) -> u32 {
log::error!("read pci u8 {:X}", _device);
0
}
fn write_pci_u8(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16, _value: u8) {
log::error!("write pci u8 {:X}", _device);
}
fn write_pci_u16(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16, _value: u16) {
log::error!("write pci u8 {:X}", _device);
}
fn write_pci_u32(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16, _value: u32) {
log::error!("write pci u8 {:X}", _device);
}
}
-184
View File
@@ -1,184 +0,0 @@
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)
}
}
-144
View File
@@ -1,144 +0,0 @@
//! # AML
//!
//! Code to parse and execute ACPI Machine Language tables.
use std::collections::HashMap;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
use syscall::io::{Io, Pio};
use crate::acpi::{AcpiContext, AmlContainingTable, Sdt, SdtHeader};
#[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(acpi_ctx: &AcpiContext, sdt: impl AmlContainingTable) -> Result<Vec<String>, AmlError> {
parse_aml_with_scope(acpi_ctx, sdt, "\\".to_owned())
}
pub fn parse_aml_with_scope(acpi_ctx: &AcpiContext, sdt: impl AmlContainingTable, scope: String) -> Result<Vec<String>, AmlError> {
let data = sdt.aml();
let mut ctx = AmlExecutionContext::new(acpi_ctx, scope);
parse_term_list(data, &mut ctx)?;
Ok(ctx.namespace_delta)
}
fn init_aml_table(acpi_ctx: &AcpiContext, sdt: impl AmlContainingTable) {
match parse_aml_table(acpi_ctx, &sdt) {
Ok(_) => log::debug!("Table {} parsed successfully", sdt.header().signature()),
Err(AmlError::AmlParseError(e)) => log::error!("Table {} got parse error: {}", sdt.header().signature(), e),
Err(AmlError::AmlInvalidOpCode) => log::error!("Table {} got invalid opcode", sdt.header().signature()),
Err(AmlError::AmlValueError) => log::error!("For table {}: type constraints or value bounds not met", sdt.header().signature()),
Err(AmlError::AmlDeferredLoad) => log::error!("For table {}: deferred load reached top level", sdt.header().signature()),
Err(AmlError::AmlFatalError(ty, code, val)) => {
log::error!("Fatal error occurred for table {}: type={}, code={}, val={:?}", sdt.header().signature(), ty, code, val);
return;
},
Err(AmlError::AmlHardFatal) => {
log::error!("Hard fatal error occurred for table {}", sdt.header().signature());
return;
}
}
}
pub fn init_namespace(context: &AcpiContext) {
let dsdt = context.dsdt().expect("could not find any DSDT");
log::debug!("Found DSDT.");
init_aml_table(context, dsdt);
let ssdts = context.ssdts();
for ssdt in ssdts {
print!("Found SSDT.");
init_aml_table(context, ssdt);
}
}
pub fn set_global_s_state(context: &AcpiContext, state: u8) {
if state != 5 {
return;
}
let fadt = match context.fadt() {
Some(fadt) => fadt,
None => {
log::error!("Cannot set global S-state due to missing FADT.");
return;
}
};
let port = fadt.pm1a_control_block as u16;
let mut val = 1 << 13;
let namespace_guard = context.namespace();
let namespace = match &*namespace_guard {
Some(namespace) => namespace,
None => {
log::error!("Cannot set global S-state due to missing ACPI namespace");
return;
}
};
let s5 = match namespace.get("\\_S5") {
Some(s5) => s5,
None => {
log::error!("Cannot set global S-state due to missing \\_S5");
return;
}
};
let p = match s5.get_as_package() {
Ok(package) => package,
Err(error) => {
log::error!("Cannot set global S-state due to \\_S5 not being a package: {:?}", error);
return;
}
};
let slp_typa = p[0].get_as_integer(context).expect("SLP_TYPa is not an integer");
let slp_typb = p[1].get_as_integer(context).expect("SLP_TYPb is not an integer");
log::info!("Shutdown SLP_TYPa {:X}, SLP_TYPb {:X}", slp_typa, slp_typb);
val |= slp_typa as u16;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
{
log::info!("Shutdown with ACPI outw(0x{:X}, 0x{:X})", port, val);
Pio::<u16>::new(port).write(val);
}
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
{
log::error!("Cannot shutdown with ACPI outw(0x{:X}, 0x{:X}) on this architecture", port, val);
}
loop {
core::hint::spin_loop();
}
}
File diff suppressed because it is too large Load Diff
-490
View File
@@ -1,490 +0,0 @@
use std::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::{AcpiContext, SdtSignature};
#[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),
#[allow(dead_code)]
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, ctx: &AcpiContext, 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(ctx)?)),
AmlValue::BufferField(_) => Ok(AmlValue::BufferField(self.get_as_buffer_field(ctx)?)),
AmlValue::DDBHandle(_) => Ok(AmlValue::DDBHandle(self.get_as_ddb_handle(ctx)?)),
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(ctx)?)),
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(ctx)?)),
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, ctx: &AcpiContext) -> 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(ctx)?;
let idx = b.index.get_as_integer(ctx)? as usize;
let len = b.length.get_as_integer(ctx)? 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, acpi_ctx: &AcpiContext) -> Result<BufferField, AmlError> {
match *self {
AmlValue::BufferField(ref b) => Ok(b.clone()),
_ => {
let raw_buf = self.get_as_buffer(acpi_ctx)?;
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, acpi_ctx: &AcpiContext) -> Result<(Vec<String>, SdtSignature), AmlError> {
match *self {
AmlValue::DDBHandle(ref v) => Ok(v.clone()),
AmlValue::Integer(i) => if let Some(sig) = acpi_ctx.get_signature_from_index(i as usize) {
Ok((vec!(), sig))
} else {
log::error!("AmlValueError in get_as_ddb_handle integer");
Err(AmlError::AmlValueError)
},
_ => { log::error!("AmlValueError in get_as_ddb_handle other"); 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, acpi_ctx: &AcpiContext) -> 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(acpi_ctx)?;
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) = acpi_ctx.get_index_from_signature(&v.1) {
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, ctx: &AcpiContext) -> 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(ctx)?;
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, acpi_ctx: &AcpiContext, scope: String, parameters: Vec<AmlValue>) -> AmlValue {
let mut ctx = AmlExecutionContext::new(acpi_ctx, scope);
ctx.init_arg_vars(parameters);
let _ = parse_term_list(&self.term_list[..], &mut ctx);
ctx.clean_namespace(acpi_ctx);
match ctx.state {
ExecutionState::RETURN(v) => v,
_ => AmlValue::IntegerConstant(0)
}
}
}
pub fn get_namespace_string(ctx: &AcpiContext, current: String, modifier_v: AmlValue) -> Result<String, AmlError> {
let mut modifier = modifier_v.get_as_string(ctx)?;
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)
}
-106
View File
@@ -1,106 +0,0 @@
use super::AmlError;
use super::parser::{AmlParseType, ParseResult, AmlExecutionContext, ExecutionState};
use super::namespace::{AmlValue, get_namespace_string};
use super::pkglength::parse_pkg_length;
use super::namestring::parse_name_string;
use super::termlist::parse_term_list;
use super::dataobj::parse_data_ref_obj;
pub fn parse_namespace_modifier(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_selector! {
data, ctx,
parse_alias_op,
parse_scope_op,
parse_name_op
};
Err(AmlError::AmlInvalidOpCode)
}
fn parse_alias_op(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
match ctx.state {
ExecutionState::EXECUTING => (),
_ => return Ok(AmlParseType {
val: AmlValue::None,
len: 0
})
}
parser_opcode!(data, 0x06);
let source_name = parse_name_string(&data[1..], ctx)?;
let alias_name = parse_name_string(&data[1 + source_name.len..], ctx)?;
let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), source_name.val)?;
let local_alias_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), alias_name.val)?;
ctx.add_to_namespace(ctx.acpi_context(), 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.acpi_context(), ctx.scope.clone(), name.val)?;
ctx.add_to_namespace(ctx.acpi_context(), 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.acpi_context(), 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
})
}
-223
View File
@@ -1,223 +0,0 @@
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)
}
}
-557
View File
@@ -1,557 +0,0 @@
use std::collections::BTreeMap;
use parking_lot::RwLockWriteGuard;
use super::namespace::{AmlValue, ObjectReference};
use super::AmlError;
use crate::acpi::AcpiContext;
pub type ParseResult = Result<AmlParseType, AmlError>;
pub type AmlParseType = AmlParseTypeGeneric<AmlValue>;
#[derive(Debug)]
pub struct AmlParseTypeGeneric<T> {
pub val: T,
pub len: usize
}
pub enum ExecutionState {
EXECUTING,
CONTINUE,
BREAK,
RETURN(AmlValue)
}
pub struct AmlExecutionContext<'a> {
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,
pub acpi_context: &'a AcpiContext,
}
impl<'a> AmlExecutionContext<'a> {
pub fn new(acpi_context: &'a AcpiContext, scope: String) -> AmlExecutionContext<'_> {
let mut idptr = acpi_context.next_ctx.write();
let id: u64 = *idptr;
*idptr += 1;
AmlExecutionContext {
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,
acpi_context,
}
}
pub fn acpi_context(&self) -> &'a AcpiContext {
self.acpi_context
}
pub fn wait_for_event(&mut self, ctx: &AcpiContext, event_ptr: AmlValue) -> Result<bool, AmlError> {
let mut namespace_ptr = self.prelock(ctx);
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, ctx: &AcpiContext, event_ptr: AmlValue) -> Result<(), AmlError> {
let mut namespace_ptr = self.prelock(ctx);
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, ctx: &AcpiContext, mutex_ptr: AmlValue) -> Result<(), AmlError> {
let id = self.ctx_id;
let mut namespace_ptr = self.prelock(ctx);
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, ctx: &AcpiContext, mutex_ptr: AmlValue) -> Result<bool, AmlError> {
let id = self.ctx_id;
let mut namespace_ptr = self.prelock(ctx);
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, ctx: &AcpiContext, name: String, value: AmlValue) -> Result<(), AmlError> {
let mut namespace = ctx.namespace_mut();
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, ctx: &AcpiContext) {
let mut namespace = ctx.namespace_mut();
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<'ctx>(&mut self, ctx: &'ctx AcpiContext) -> RwLockWriteGuard<'ctx, Option<BTreeMap<String, AmlValue>>> {
ctx.namespace_mut()
}
fn modify_local_obj(&mut self, ctx: &AcpiContext, local: usize, value: AmlValue) -> Result<(), AmlError> {
self.local_vars[local] = value.get_as_type(ctx, self.local_vars[local].clone())?;
Ok(())
}
fn modify_object(&mut self, ctx: &AcpiContext, name: String, value: AmlValue) -> Result<(), AmlError> {
if let Some(ref mut namespace) = *ctx.namespace_mut() {
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(ctx, coercion_obj)?);
Ok(())
} else {
Err(AmlError::AmlHardFatal)
}
}
fn modify_index_final(&mut self, ctx: &AcpiContext, name: String, value: AmlValue, indices: Vec<u64>) -> Result<(), AmlError> {
if let Some(ref mut namespace) = *ctx.namespace_mut() {
let mut obj = if let Some(s) = namespace.get(&name) {
s.clone()
} else {
return Err(AmlError::AmlValueError);
};
obj = self.modify_index_core(ctx, obj, value, indices)?;
namespace.insert(name, obj);
Ok(())
} else {
Err(AmlError::AmlValueError)
}
}
fn modify_index_core(&mut self, ctx: &AcpiContext, 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(ctx)? 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(ctx)? 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(ctx)?;
let _ = self.modify(ctx, 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(ctx, p[indices[0] as usize].clone(), value, indices[1..].to_vec())?;
}
Ok(AmlValue::Package(p))
},
_ => Err(AmlError::AmlValueError)
}
}
pub fn modify_index(&mut self, ctx: &AcpiContext, name: AmlValue, value: AmlValue, indices: Vec<u64>) -> Result<(), AmlError>{
match name {
AmlValue::ObjectReference(r) => match r {
ObjectReference::Object(s) => self.modify_index_final(ctx, s, value, indices),
ObjectReference::Index(c, v) => {
let mut indices = indices.clone();
indices.push(v.get_as_integer(ctx)?);
self.modify_index(ctx, *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(ctx, v, value, indices)?;
Ok(())
}
},
_ => Err(AmlError::AmlValueError)
}
}
pub fn modify(&mut self, ctx: &AcpiContext, 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(ctx, i as usize, value),
ObjectReference::Object(s) => self.modify_object(ctx, s, value),
ObjectReference::Index(c, v) => self.modify_index(ctx, *c, value, vec!(v.get_as_integer(ctx)?))
},
AmlValue::String(s) => self.modify_object(ctx, 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, ctx: &AcpiContext, name: String, value: AmlValue) -> Result<(), AmlError> {
if let Some(ref mut namespace) = *ctx.namespace_mut() {
namespace.insert(name, value);
Ok(())
} else {
Err(AmlError::AmlHardFatal)
}
}
pub fn copy(&mut self, ctx: &AcpiContext, 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(ctx, s, value),
ObjectReference::Index(c, v) => self.modify_index(ctx, *c, value, vec!(v.get_as_integer(ctx)?))
},
AmlValue::String(s) => self.copy_object(ctx, s, value),
_ => Err(AmlError::AmlValueError)
}
}
fn get_index_final(&self, ctx: &AcpiContext, name: String, indices: Vec<u64>) -> Result<AmlValue, AmlError> {
if let Some(ref namespace) = *ctx.namespace() {
let obj = if let Some(s) = namespace.get(&name) {
s.clone()
} else {
return Err(AmlError::AmlValueError);
};
self.get_index_core(ctx, obj, indices)
} else {
Err(AmlError::AmlValueError)
}
}
fn get_index_core(&self, ctx: &AcpiContext, 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(ctx)?;
Ok(AmlValue::Integer(b.source_buf.get_as_buffer(ctx, )?[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(ctx, p[indices[0] as usize].clone(), indices[1..].to_vec())
}
},
_ => Err(AmlError::AmlValueError)
}
}
pub fn get_index(&self, ctx: &AcpiContext, name: AmlValue, indices: Vec<u64>) -> Result<AmlValue, AmlError>{
match name {
AmlValue::ObjectReference(r) => match r {
ObjectReference::Object(s) => self.get_index_final(ctx, s, indices),
ObjectReference::Index(c, v) => {
let mut indices = indices.clone();
indices.push(v.get_as_integer(ctx)?);
self.get_index(ctx, *c, indices)
},
ObjectReference::ArgObj(_) => Err(AmlError::AmlValueError),
ObjectReference::LocalObj(i) => {
let v = self.local_vars[i as usize].clone();
self.get_index_core(ctx, v, indices)
}
},
_ => Err(AmlError::AmlValueError)
}
}
pub fn get(&self, ctx: &AcpiContext, 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) = *ctx.namespace() {
if let Some(o) = namespace.get(s) {
o.clone()
} else {
AmlValue::None
}
} else { AmlValue::None },
ObjectReference::Index(c, v) => self.get_index(ctx, *c, vec!(v.get_as_integer(ctx)?))?,
},
AmlValue::String(ref s) => if let Some(ref namespace) = *ctx.namespace() {
if let Some(o) = namespace.get(s) {
o.clone()
} else {
AmlValue::None
}
} else { AmlValue::None },
_ => AmlValue::None
})
}
}
-52
View File
@@ -1,52 +0,0 @@
#[macro_export]
macro_rules! parser_selector {
{$data:expr, $ctx:expr, $func:expr} => {
match $func($data, $ctx) {
Ok(res) => return Ok(res),
Err(AmlError::AmlInvalidOpCode) => (),
Err(e) => return Err(e)
}
};
{$data:expr, $ctx:expr, $func:expr, $($funcs:expr),+} => {
parser_selector! {$data, $ctx, $func};
parser_selector! {$data, $ctx, $($funcs),*};
};
}
#[macro_export]
macro_rules! parser_selector_simple {
{$data:expr, $func:expr} => {
match $func($data) {
Ok(res) => return Ok(res),
Err(AmlError::AmlInvalidOpCode) => (),
Err(e) => return Err(e)
}
};
{$data:expr, $func:expr, $($funcs:expr),+} => {
parser_selector_simple! {$data, $func};
parser_selector_simple! {$data, $($funcs),*};
};
}
#[macro_export]
macro_rules! parser_opcode {
($data:expr, $opcode:expr) => {
if $data[0] != $opcode {
return Err(AmlError::AmlInvalidOpCode);
}
};
($data:expr, $opcode:expr, $alternate_opcode:expr) => {
if $data[0] != $opcode && $data[0] != $alternate_opcode {
return Err(AmlError::AmlInvalidOpCode);
}
};
}
#[macro_export]
macro_rules! parser_opcode_extended {
($data:expr, $opcode:expr) => {
if $data[0] != 0x5B || $data[1] != $opcode {
return Err(AmlError::AmlInvalidOpCode);
}
};
}
-25
View File
@@ -1,25 +0,0 @@
use super::AmlError;
pub fn parse_pkg_length(data: &[u8]) -> Result<(usize, usize), AmlError> {
let lead_byte = data[0];
let count_bytes: usize = (lead_byte >> 6) as usize;
if count_bytes == 0 {
return Ok(((lead_byte & 0x3F) as usize, 1 as usize));
}
let upper_two = (lead_byte >> 4) & 0x03;
if upper_two != 0 {
return Err(AmlError::AmlParseError("Invalid package length"));
}
let mut current_byte = 0;
let mut pkg_len: usize = (lead_byte & 0x0F) as usize;
while current_byte < count_bytes {
pkg_len += (data[1 + current_byte] as u32 * 16 * (256 as u32).pow(current_byte as u32)) as usize;
current_byte += 1;
}
Ok((pkg_len, count_bytes + 1))
}
-172
View File
@@ -1,172 +0,0 @@
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(ctx.acpi_context(), 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(ctx.acpi_context(), get_namespace_string(ctx.acpi_context(), 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)
}
-477
View File
@@ -1,477 +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::monotonic;
use crate::acpi::PossibleAmlTables;
use super::parse_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(ctx.acpi_context(), name.val)?.get_as_buffer(ctx.acpi_context())?;
let table = crate::acpi::Sdt::new(tbl.into()).map_err(|error| {
log::error!("Failed to parse def_load ACPI table: {}", error);
AmlError::AmlValueError
})?;
if let Some(aml_sdt) = PossibleAmlTables::try_new(table.clone()) {
ctx.acpi_context().new_index(&table.signature());
let delta = parse_aml_table(ctx.acpi_context(), aml_sdt)?;
let _ = ctx.modify(ctx.acpi_context(), ddb_handle_object.val, AmlValue::DDBHandle((delta, table.signature())));
Ok(AmlParseType {
val: AmlValue::None,
len: 2 + name.len + ddb_handle_object.len
})
} else {
log::error!("Loaded table is not for AML");
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(ctx.acpi_context())? as u8;
match ctx.get(ctx.acpi_context(), 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(ctx.acpi_context(), 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(ctx.acpi_context(), object.val.clone())?.get_as_event()?;
let _ = ctx.modify(ctx.acpi_context(), 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(ctx.acpi_context(), 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(ctx.acpi_context())?;
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(ctx.acpi_context())?;
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(ctx.acpi_context(), object.val)?.get_as_ddb_handle(ctx.acpi_context())?;
let mut namespace = ctx.prelock(ctx.acpi_context());
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(ctx.acpi_context())? > 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(ctx.acpi_context())? == 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
+9 -10
View File
@@ -1,3 +1,5 @@
#![feature(if_let_guard)]
use std::convert::TryFrom;
use std::io::{self, prelude::*};
use std::fs::{File, OpenOptions};
@@ -13,11 +15,8 @@ use syscall::data::{Event, Packet};
use syscall::flag::{EventFlags, O_NONBLOCK};
mod acpi;
mod aml;
mod scheme;
// TODO: Perhaps use the acpi and aml crates?
fn monotonic() -> (u64, u64) {
use syscall::call::clock_gettime;
use syscall::data::TimeSpec;
@@ -38,8 +37,8 @@ fn setup_logging() -> Option<&'static RedoxLogger> {
let mut logger = RedoxLogger::new()
.with_output(
OutputBuilder::stderr()
.with_filter(log::LevelFilter::Info) // limit global output to important info
.with_ansi_escape_codes()
.with_filter(log::LevelFilter::Warn) // limit global output to important info
// .with_ansi_escape_codes()
.flush_on_newline(true)
.build()
);
@@ -48,9 +47,9 @@ fn setup_logging() -> Option<&'static RedoxLogger> {
match OutputBuilder::in_redox_logging_scheme("misc", "acpi", "acpid.log") {
Ok(b) => logger = logger.with_output(
// TODO: Add a configuration file for this
b.with_filter(log::LevelFilter::Trace)
b.with_filter(log::LevelFilter::Warn)
.flush_on_newline(true)
.with_ansi_escape_codes()
// .with_ansi_escape_codes()
.build()
),
Err(error) => eprintln!("Failed to create xhci.log: {}", error),
@@ -59,8 +58,8 @@ fn setup_logging() -> Option<&'static RedoxLogger> {
#[cfg(target_os = "redox")]
match OutputBuilder::in_redox_logging_scheme("misc", "acpi", "acpid.ansi.log") {
Ok(b) => logger = logger.with_output(
b.with_filter(log::LevelFilter::Trace)
.with_ansi_escape_codes()
b.with_filter(log::LevelFilter::Warn)
// .with_ansi_escape_codes()
.flush_on_newline(true)
.build()
),
@@ -215,7 +214,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! {
drop(shutdown_pipe);
drop(event_queue);
aml::set_global_s_state(&acpi_context, 5);
acpi_context.set_global_s_state(5);
unreachable!("System should have shut down before this is entered");
}
+57 -11
View File
@@ -1,38 +1,43 @@
use std::collections::BTreeMap;
use std::convert::{TryFrom, TryInto};
use parking_lot::RwLockReadGuard;
use syscall::data::Stat;
use syscall::error::{EBADF, EBADFD, EINVAL, EISDIR, ENOENT, ENOTDIR, EOVERFLOW};
use syscall::error::{EIO, EBADF, EBADFD, EINVAL, EISDIR, ENOENT, ENOTDIR, EOVERFLOW};
use syscall::error::{Error, Result};
use syscall::flag::{O_ACCMODE, O_DIRECTORY, O_RDONLY, O_STAT, O_SYMLINK};
use syscall::flag::{MODE_FILE, MODE_DIR, SEEK_CUR, SEEK_END, SEEK_SET};
use syscall::scheme::SchemeMut;
use crate::acpi::{AcpiContext, SdtSignature};
use crate::acpi::{AcpiContext, SdtSignature, AmlSymbols};
pub struct AcpiScheme<'acpi> {
ctx: &'acpi AcpiContext,
handles: BTreeMap<usize, Handle>,
handles: BTreeMap<usize, Handle<'acpi>>,
next_fd: usize,
}
struct Handle {
struct Handle<'a> {
offset: usize,
kind: HandleKind,
kind: HandleKind<'a>,
stat: bool,
}
enum HandleKind {
enum HandleKind<'a> {
TopLevel,
Tables,
Table(SdtSignature),
Symbols(RwLockReadGuard<'a, Option<AmlSymbols>>),
Symbol(aml::AmlName),
}
impl HandleKind {
impl HandleKind<'_> {
fn is_dir(&self) -> bool {
match self {
Self::TopLevel => true,
Self::Tables => true,
Self::Table(_) => false,
Self::Symbols(_) => true,
Self::Symbol(_) => false,
}
}
fn len(&self, acpi_ctx: &AcpiContext) -> Result<usize> {
@@ -40,6 +45,13 @@ impl HandleKind {
Self::TopLevel => TOPLEVEL_CONTENTS.len(),
Self::Tables => acpi_ctx.tables().len().checked_mul(TABLE_DENTRY_LENGTH).unwrap_or(usize::max_value()),
Self::Table(signature) => acpi_ctx.sdt_from_signature(signature).ok_or(Error::new(EBADFD))?.length(),
Self::Symbols(symbols_option) => {
match symbols_option.as_ref() {
Some(symbols) => symbols.symbols_str.len(),
_ => 0,
}
},
Self::Symbol(_) => 0,
})
}
}
@@ -54,7 +66,7 @@ impl<'acpi> AcpiScheme<'acpi> {
}
}
const TOPLEVEL_CONTENTS: &[u8] = b"tables\n";
const TOPLEVEL_CONTENTS: &[u8] = b"tables\nsymbols\n";
const TABLE_DENTRY_LENGTH: usize = 35;
@@ -147,6 +159,20 @@ impl SchemeMut for AcpiScheme<'_> {
HandleKind::Table(signature)
}
["symbols"] => if let Ok(symbols_option) = self.ctx.aml_symbols() {
HandleKind::Symbols(symbols_option)
} else {
return Err(Error::new(EIO))
},
["symbols", symbol] => {
if let Some(symbol) = self.ctx.aml_lookup(symbol) {
HandleKind::Symbol(symbol)
} else {
return Err(Error::new(ENOENT));
}
}
_ => return Err(Error::new(ENOENT)),
};
@@ -177,7 +203,7 @@ impl SchemeMut for AcpiScheme<'_> {
}
fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result<usize> {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
stat.st_size = handle.kind.len(self.ctx)?.try_into().unwrap_or(u64::max_value());
if handle.kind.is_dir() {
@@ -223,7 +249,7 @@ impl SchemeMut for AcpiScheme<'_> {
return Err(Error::new(EBADF));
}
let src_buf = match handle.kind {
let src_buf = match &handle.kind {
HandleKind::TopLevel => TOPLEVEL_CONTENTS,
HandleKind::Table(ref signature) => self.ctx.sdt_from_signature(signature).ok_or(Error::new(EBADFD))?.as_slice(),
@@ -264,6 +290,26 @@ impl SchemeMut for AcpiScheme<'_> {
return Ok(bytes_written);
}
HandleKind::Symbols(symbols_option) => {
match symbols_option.as_ref() {
Some(symbols) => {
let offset = std::cmp::min(symbols.symbols_str.len(), handle.offset);
let src_buf = &symbols.symbols_str.as_bytes()[offset..];
let to_copy = std::cmp::min(src_buf.len(), buf.len());
buf[..to_copy].copy_from_slice(&src_buf[..to_copy]);
handle.offset = handle.offset.checked_add(to_copy).ok_or(Error::new(EOVERFLOW))?;
return Ok(to_copy);
}
_ => return Err(Error::new(EIO)),
}
}
HandleKind::Symbol(_) => b"",
};
let offset = std::cmp::min(src_buf.len(), handle.offset);
@@ -272,7 +318,7 @@ impl SchemeMut for AcpiScheme<'_> {
let to_copy = std::cmp::min(src_buf.len(), buf.len());
buf[..to_copy].copy_from_slice(&src_buf[..to_copy]);
handle.offset += to_copy;
handle.offset = handle.offset.checked_add(to_copy).ok_or(Error::new(EOVERFLOW))?;
Ok(to_copy)
}