switch to aml crate, implement acpi:/symbols
This commit is contained in:
+333
-16
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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,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)
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user