Files
RedBear-OS/acpid/src/aml/mod.rs
T
2022-07-26 16:11:45 -06:00

145 lines
4.3 KiB
Rust

//! # 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();
}
}