acpid: initialize aml on demand

This commit is contained in:
Jeremy Soller
2025-11-22 17:29:46 -07:00
parent 2e96800384
commit cd5adcd848
+46 -19
View File
@@ -1,6 +1,7 @@
use acpi::aml::object::{Object, WrappedObject};
use rustc_hash::FxHashMap;
use std::convert::{TryFrom, TryInto};
use std::error::Error;
use std::ops::Deref;
use std::str::FromStr;
use std::sync::{Arc, Mutex};
@@ -238,7 +239,7 @@ pub struct Ssdt(Sdt);
// must empty the cache so it is rebuilt.
// If you modify an SDT, you must discard the aml_context and rebuild it.
pub struct AmlSymbols {
aml_context: Interpreter<AmlPhysMemHandler>,
aml_context: Option<Interpreter<AmlPhysMemHandler>>,
// k = name, v = description
symbol_cache: FxHashMap<String, String>,
page_cache: Arc<Mutex<AmlPageCache>>,
@@ -246,21 +247,39 @@ pub struct AmlSymbols {
impl AmlSymbols {
pub fn new() -> Self {
let page_cache = Arc::new(Mutex::new(AmlPageCache::default()));
let handler = AmlPhysMemHandler::new(Arc::clone(&page_cache));
//TODO: use these parsed tables for the rest of acpid and return errors instead of unwrap
let rsdp_address = usize::from_str_radix(&std::env::var("RSDP_ADDR").unwrap(), 16).unwrap();
let tables = unsafe { AcpiTables::from_rsdp(handler.clone(), rsdp_address).unwrap() };
let platform = AcpiPlatform::new(tables, handler).unwrap();
Self {
aml_context: Interpreter::new_from_platform(&platform).unwrap(),
aml_context: None,
symbol_cache: FxHashMap::default(),
page_cache,
page_cache: Arc::new(Mutex::new(AmlPageCache::default())),
}
}
pub fn mut_aml_context(&mut self) -> &mut Interpreter<AmlPhysMemHandler> {
&mut self.aml_context
pub fn init(&mut self) -> Result<(), Box<dyn Error>> {
if self.aml_context.is_some() {
return Err("AML interpreter already initialized".into());
}
let format_err = |err| format!("{:?}", err);
let handler = AmlPhysMemHandler::new(Arc::clone(&self.page_cache));
//TODO: use these parsed tables for the rest of acpid
let rsdp_address = usize::from_str_radix(&std::env::var("RSDP_ADDR")?, 16)?;
let tables = unsafe { AcpiTables::from_rsdp(handler.clone(), rsdp_address).map_err(format_err)? };
let platform = AcpiPlatform::new(tables, handler).map_err(format_err)?;
let interpreter = Interpreter::new_from_platform(&platform).map_err(format_err)?;
self.aml_context = Some(interpreter);
Ok(())
}
pub fn aml_context_mut(&mut self) -> &mut Interpreter<AmlPhysMemHandler> {
// PCID must be running by this time!
if self.aml_context.is_none() {
match self.init() {
Ok(()) => (),
Err(err) => {
log::error!("failed to initialize AML context: {}", err);
}
}
}
self.aml_context.as_mut().expect("AML context not initialized")
}
pub fn symbols_cache(&self) -> &FxHashMap<String, String> {
@@ -276,10 +295,11 @@ impl AmlSymbols {
}
pub fn build_cache(&mut self) {
let aml_context = self.aml_context_mut();
let mut symbol_list: Vec<(AmlName, String)> = Vec::with_capacity(5000);
if self
.aml_context
if aml_context
.namespace
.lock()
.traverse(|level_aml_name, level| {
@@ -310,7 +330,7 @@ impl AmlSymbols {
for (aml_name, name) in &symbol_list {
// create an empty entry, in case something goes wrong with serialization
symbol_cache.insert(name.to_owned(), "".to_owned());
if let Some(ser_value) = AmlSerde::from_aml(&mut self.aml_context, aml_name) {
if let Some(ser_value) = AmlSerde::from_aml(aml_context, aml_name) {
if let Ok(ser_string) = ron::ser::to_string_pretty(&ser_value, Default::default()) {
// replace the empty entry
symbol_cache.insert(name.to_owned(), ser_string);
@@ -361,7 +381,8 @@ impl AcpiContext {
symbol: AmlName,
args: Vec<AmlSerdeValue>,
) -> Result<AmlSerdeValue, AmlEvalError> {
let interpreter = &mut self.aml_symbols.write().aml_context;
let mut symbols = self.aml_symbols.write();
let interpreter = symbols.aml_context_mut();
interpreter.acquire_global_lock(16)?;
let args = args
@@ -549,10 +570,16 @@ impl AcpiContext {
}
};
let s5 = match aml_symbols.aml_context.namespace.lock().get(s5_aml_name) {
Ok(s5) => s5,
Err(error) => {
log::error!("Cannot set S-state, missing \\_S5, {:?}", error);
let s5 = match &aml_symbols.aml_context {
Some(aml_context) => match aml_context.namespace.lock().get(s5_aml_name) {
Ok(s5) => s5,
Err(error) => {
log::error!("Cannot set S-state, missing \\_S5, {:?}", error);
return;
}
},
None => {
log::error!("Cannot set S-state, AML context not initialized");
return;
}
};