From 23be7ed63ca1b858d98bafbc9462fc5bbe0c9325 Mon Sep 17 00:00:00 2001 From: Ron Williams Date: Mon, 27 Mar 2023 20:58:59 -0700 Subject: [PATCH] Add serde with separate library for definitions --- Cargo.lock | 136 +++++++++++--- acpid/Cargo.toml | 3 + acpid/src/acpi.rs | 449 ++++++++++++++++++++++---------------------- acpid/src/scheme.rs | 4 +- amlserde/Cargo.toml | 15 ++ amlserde/src/lib.rs | 295 +++++++++++++++++++++++++++++ 6 files changed, 649 insertions(+), 253 deletions(-) create mode 100644 amlserde/Cargo.toml create mode 100644 amlserde/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index fa39129d36..58740eac28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,6 +20,7 @@ name = "acpid" version = "0.1.0" dependencies = [ "aml", + "amlserde", "log", "num-derive", "num-traits", @@ -29,7 +30,9 @@ dependencies = [ "redox-log", "redox_syscall 0.3.4", "rustc-hash", + "serde_json", "thiserror", + "toml 0.7.3", ] [[package]] @@ -69,6 +72,16 @@ dependencies = [ "spinning_top", ] +[[package]] +name = "amlserde" +version = "0.0.1" +dependencies = [ + "aml", + "rustc-hash", + "serde", + "toml 0.7.3", +] + [[package]] name = "ansi_term" version = "0.12.1" @@ -430,7 +443,7 @@ checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.98", ] [[package]] @@ -474,6 +487,12 @@ dependencies = [ "uuid", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "heck" version = "0.3.3" @@ -530,6 +549,16 @@ dependencies = [ "spin", ] +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg 1.1.0", + "hashbrown", +] + [[package]] name = "instant" version = "0.1.12" @@ -728,7 +757,7 @@ checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.98", ] [[package]] @@ -878,7 +907,7 @@ checksum = "0f35583365be5d148e959284f42526841917b7bfa09e2d1a7ad5dde2cf0eaa39" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.98", ] [[package]] @@ -917,7 +946,7 @@ dependencies = [ "smallvec 1.9.0", "structopt", "thiserror", - "toml", + "toml 0.5.9", ] [[package]] @@ -961,7 +990,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", + "syn 1.0.98", "version_check", ] @@ -978,9 +1007,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.42" +version = "1.0.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c278e965f1d8cf32d6e0e96de3d3e79712178ae67986d9cf9151f51e95aac89b" +checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534" dependencies = [ "unicode-ident", ] @@ -997,9 +1026,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.20" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" dependencies = [ "proc-macro2", ] @@ -1297,7 +1326,7 @@ checksum = "aaaae8f38bb311444cfb7f1979af0bc9240d95795f75f9ceddf6a59b79ceffa0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.98", ] [[package]] @@ -1327,35 +1356,44 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.140" +version = "1.0.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc855a42c7967b7c369eb5860f7164ef1f6f81c20c7cc1141f2a604e18723b03" +checksum = "771d4d9c4163ee138805e12c710dd365e4f44be8be0503cb1bb9eb989425d9c9" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.140" +version = "1.0.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f2122636b9fe3b81f1cb25099fcf2d3f542cdb1d45940d56c713158884a05da" +checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.10", ] [[package]] name = "serde_json" -version = "1.0.82" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" +checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" dependencies = [ "itoa", "ryu", "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4" +dependencies = [ + "serde", +] + [[package]] name = "slab" version = "0.4.7" @@ -1453,7 +1491,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.98", ] [[package]] @@ -1467,6 +1505,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aad1363ed6d37b84299588d62d3a7d95b5a5c2d9aad5c85609fda12afaa1f40" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "tap" version = "1.0.1" @@ -1511,7 +1560,7 @@ checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.98", ] [[package]] @@ -1549,6 +1598,40 @@ dependencies = [ "serde", ] +[[package]] +name = "toml" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b403acf6f2bb0859c93c7f0d967cb4a75a7ac552100f9322faf64dc047669b21" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "unicode-bidi" version = "0.3.8" @@ -1722,7 +1805,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 1.0.98", "wasm-bindgen-shared", ] @@ -1744,7 +1827,7 @@ checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.98", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1799,6 +1882,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "winnow" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28" +dependencies = [ + "memchr", +] + [[package]] name = "ws2_32-sys" version = "0.2.1" @@ -1838,5 +1930,5 @@ dependencies = [ "serde_json", "smallvec 1.9.0", "thiserror", - "toml", + "toml 0.5.9", ] diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml index c9829bbf69..3e052af591 100644 --- a/acpid/Cargo.toml +++ b/acpid/Cargo.toml @@ -18,3 +18,6 @@ redox-log = "0.1.1" redox_syscall = "0.3" rustc-hash = "1.1.0" thiserror = "1" +toml = "0.7" +serde_json = "1.0.94" +amlserde = { path = "../amlserde" } \ No newline at end of file diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index 2d8ecf87ec..c33dc33fb0 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -1,3 +1,4 @@ +use amlserde::{AmlHandleLookup, AmlSerde}; use rustc_hash::FxHashMap; use std::convert::{TryFrom, TryInto}; use std::ops::Deref; @@ -13,7 +14,8 @@ use syscall::io::{Io, Pio}; use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; use thiserror::Error; -use aml::{AmlContext, AmlName, AmlHandle, AmlValue}; +use aml::{AmlContext, AmlError, AmlHandle, AmlName, AmlValue}; +use amlserde::pretty_name; pub mod dmar; use self::dmar::Dmar; @@ -68,7 +70,13 @@ pub struct SdtSignature { impl fmt::Display for SdtSignature { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}-{}-{}", String::from_utf8_lossy(&self.signature), String::from_utf8_lossy(&self.oem_id), String::from_utf8_lossy(&self.oem_table_id)) + write!( + f, + "{}-{}-{}", + String::from_utf8_lossy(&self.signature), + String::from_utf8_lossy(&self.oem_id), + String::from_utf8_lossy(&self.oem_table_id) + ) } } @@ -133,14 +141,19 @@ impl Sdt { let header = match plain::from_bytes::(&slice) { Ok(header) => header, Err(plain::Error::TooShort) => return Err(InvalidSdtError::InvalidSize), - Err(plain::Error::BadAlignment) => panic!("plain::from_bytes failed due to alignment, but SdtHeader is #[repr(packed)]!"), + Err(plain::Error::BadAlignment) => panic!( + "plain::from_bytes failed due to alignment, but SdtHeader is #[repr(packed)]!" + ), }; if header.length() != slice.len() { return Err(InvalidSdtError::InvalidSize); } - let checksum = slice.iter().copied().fold(0_u8, |current_sum, item| current_sum.wrapping_add(item)); + let checksum = slice + .iter() + .copied() + .fold(0_u8, |current_sum, item| current_sum.wrapping_add(item)); if checksum != 0 { return Err(InvalidSdtError::BadChecksum); @@ -154,7 +167,9 @@ impl Sdt { // Begin by reading and validating the header first. The SDT header is always 36 bytes // long, and can thus span either one or two page table frames. - let needs_extra_page = (PAGE_SIZE - physaddr_page_offset).checked_sub(mem::size_of::()).is_none(); + let needs_extra_page = (PAGE_SIZE - physaddr_page_offset) + .checked_sub(mem::size_of::()) + .is_none(); let page_table_count = 1 + if needs_extra_page { 1 } else { 0 }; let pages = PhysmapGuard::map(physaddr_start_page, page_table_count)?; @@ -223,13 +238,6 @@ impl fmt::Debug for Sdt { pub struct Dsdt(Sdt); pub struct Ssdt(Sdt); - -#[derive(Debug, Error)] -pub enum SymbolListError { - #[error("Aml Internal Error")] - AmlInternalError, -} - // Current AML implementation builds the aml_context.namespace at startup, // but the cache for symbols is lazy-loaded when someone // reads from the acpi:/symbols scheme. @@ -243,136 +251,6 @@ pub struct AmlSymbols { pub symbols_str: String, } -impl AmlSymbols { - pub fn to_str(&self) -> &str { - &self.symbols_str - } - - /// Format a value as toml, to use as file contents - pub fn format_value(name: &str, value: &AmlValue, handle_lookup: &AmlHandleLookup) -> String { - let mut value_str = String::with_capacity(256); - let _ = write!(value_str, "[symbol]\nname = \"{}\"\n\n[value]\n", name); - let _ = match value { - AmlValue::Integer(n) => - write!(value_str, "type = \"Integer\"\nvalue = \"{:#x}\"\n", n), - AmlValue::String(s) => - write!(value_str, "type = \"String\"\nvalue = \"{}\"\n", s), - AmlValue::Processor { id, pblk_address, pblk_len } => - write!(value_str, "type = \"Processor\"\nid = \"{}\"\npblk_address = \"{}\"\npblk_len = \"{}\"\n", - id, pblk_address, pblk_len), - AmlValue::Method { flags, code } => - write!(value_str, "type = \"Method\"\nflags = \"{:?}\"\ncode = {}\n", flags, AmlSymbols::code_as_string(code)), - AmlValue::OpRegion { region, offset, length, parent_device } => - write!(value_str, "type = \"OpRegion\"\nregion = \"{:?}\"\noffset = \"{:#x}\"\nlength = \"{:#x}\"\ndevice = \"{}\"\n", - region, offset, length, AmlSymbols::device_option_as_string(parent_device)), - AmlValue::Field { region, flags, offset, length } => - write!(value_str, "type = \"Field\"\nregion = \"{}\"\nflags = \"{:?}\"\noffset = \"{:#x}\"\nlength = \"{:#x}\"\n", - handle_lookup.get_as_str(region), flags, offset, length), - AmlValue::Package(contents) => - write!(value_str, "type = \"Package\"\ncontents = {}\n", - AmlSymbols::contents_as_string(contents)), - AmlValue::Device => write!(value_str, "type = \"Device\"\n"), - AmlValue::Buffer(_) => write!(value_str, "type = \"Buffer\"\n"), - other => - write!(value_str, "type = \"Other\"\ndebug = \"{:.64?}\"\n", other), - }; - - value_str.shrink_to_fit(); - value_str - } - - fn device_option_as_string(device: &Option) -> String { - if let Some(name) = device { - format!("\"{}\"", AmlSymbols::pretty_name(name)) - } else { - "\"None\"".to_string() - } - } - - fn code_as_string(code: &aml::value::MethodCode) -> String { - match code { - aml::value::MethodCode::Aml(bytes) => - if bytes.len() > 15 { - format!("\"AML({:x?}...)\"", &bytes[..15]) - } else { - format!("\"AML({:x?})\"", bytes) - }, - aml::value::MethodCode::Native(_) => format!("(native method)"), - } - } - - fn contents_as_string(contents: &Vec) -> String { - let mut buf = String::with_capacity(128); - let _ = write!(buf, "[ "); - for value in contents { - match value { - AmlValue::Integer(n) => { let _ = write!(buf, "{:x}, ", n); }, - AmlValue::String(s) => { let _ = write!(buf, "\"{}\",", s); } - _ => { let _ = write!(buf, "{:?}", value); }, - } - if buf.len() > 58 { - let _ = write!(buf, "..."); - break; - } - } - let _ = write!(buf, "]"); - buf - } - - /// Remove trailing underscores from each name segment - pub fn pretty_name(level_aml_name: &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 - } - - pub fn child_symbol(level_name: &str, value_name: &str) -> String { - format!("{}.{}", level_name, value_name.trim_end_matches('_')) - } - - pub fn root_symbol(value_name: &str) -> String { - format!("\\{}", value_name.trim_end_matches('_')) - } - -} - -pub struct AmlHandleLookup { - map: FxHashMap, -} - -impl AmlHandleLookup { - pub fn new() -> Self { - Self { map: FxHashMap::default() } - } - - fn handle_to_key(&self, handle: &AmlHandle) -> String { - format!("{:?}", handle) - } - - pub fn insert(&mut self, handle: &AmlHandle, name: &String) { - self.map.insert(self.handle_to_key(handle), name.to_owned()); - } - - pub fn get(&self, handle: &AmlHandle) -> Option<&String> { - self.map.get(&self.handle_to_key(handle)) - } - - pub fn get_as_str(&self, handle: &AmlHandle) -> &str { - if let Some(name) = self.get(handle) { - &name[..] - } else { - "Unrecognized" - } - } -} - pub struct AcpiContext { tables: Vec, dsdt: Option, @@ -383,7 +261,6 @@ pub struct AcpiContext { // 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 // generate an index only for those. - sdt_order: RwLock>>, pub next_ctx: RwLock, @@ -391,16 +268,17 @@ pub struct AcpiContext { impl AcpiContext { pub fn init(rxsdt_physaddrs: impl Iterator) -> Self { - let tables = rxsdt_physaddrs.map(|physaddr| { - let physaddr: usize = physaddr - .try_into() - .expect("expected ACPI addresses to be compatible with the current word size"); + let tables = rxsdt_physaddrs + .map(|physaddr| { + let physaddr: usize = physaddr + .try_into() + .expect("expected ACPI addresses to be compatible with the current word size"); - log::trace!("TABLE AT {:#>08X}", physaddr); + log::trace!("TABLE AT {:#>08X}", physaddr); - Sdt::load_from_physical(physaddr) - .expect("failed to load physical SDT") - }).collect::>(); + Sdt::load_from_physical(physaddr).expect("failed to load physical SDT") + }) + .collect::>(); let mut this = Self { tables, @@ -409,7 +287,10 @@ impl AcpiContext { // Temporary values aml_symbols: RwLock::new(AmlSymbols { - aml_context: AmlContext::new(Box::new(AmlPhysMemHandler), aml::DebugVerbosity::None), + aml_context: AmlContext::new( + Box::new(AmlPhysMemHandler), + aml::DebugVerbosity::None, + ), symbols_cache: FxHashMap::default(), symbols_str: "".to_string(), }), @@ -426,14 +307,14 @@ impl AcpiContext { Fadt::init(&mut this); //TODO (hangs on real hardware): Dmar::init(&this); - this.aml_symbols.write().aml_context = AcpiContext::build_aml_context(&this); this } fn build_aml_context(acpi: &AcpiContext) -> AmlContext { - let mut aml_context = AmlContext::new(Box::new(AmlPhysMemHandler), aml::DebugVerbosity::None); + let mut aml_context = + AmlContext::new(Box::new(AmlPhysMemHandler), aml::DebugVerbosity::None); if let Some(dsdt) = acpi.dsdt() { match aml_context.parse_table(dsdt.aml()) { @@ -461,34 +342,56 @@ impl AcpiContext { self.dsdt.as_ref() } pub fn ssdts(&self) -> impl Iterator + '_ { - self.find_multiple_sdts(*b"SSDT").map(|sdt| Ssdt(sdt.clone())) + self.find_multiple_sdts(*b"SSDT") + .map(|sdt| Ssdt(sdt.clone())) } fn find_single_sdt_pos(&self, signature: [u8; 4]) -> Option { - let count = self.tables.iter().filter(|sdt| sdt.signature == signature).count(); + let count = self + .tables + .iter() + .filter(|sdt| sdt.signature == signature) + .count(); if count > 1 { - log::warn!("Expected only a single SDT of signature `{}` ({:?}), but there were {}", String::from_utf8_lossy(&signature), signature, count); + log::warn!( + "Expected only a single SDT of signature `{}` ({:?}), but there were {}", + String::from_utf8_lossy(&signature), + signature, + count + ); } - self.tables.iter().position(|sdt| sdt.signature == signature) + self.tables + .iter() + .position(|sdt| sdt.signature == signature) } pub fn find_multiple_sdts<'a>(&'a self, signature: [u8; 4]) -> impl Iterator { - self.tables.iter().filter(move |sdt| sdt.signature == signature) + self.tables + .iter() + .filter(move |sdt| sdt.signature == signature) } pub fn take_single_sdt(&self, signature: [u8; 4]) -> Option { - self.find_single_sdt_pos(signature).map(|pos| self.tables[pos].clone()) + self.find_single_sdt_pos(signature) + .map(|pos| self.tables[pos].clone()) } pub fn fadt(&self) -> Option<&Fadt> { self.fadt.as_ref() } pub fn sdt_from_signature(&self, signature: &SdtSignature) -> Option<&Sdt> { - self.tables.iter().find(|sdt| sdt.signature == signature.signature && sdt.oem_id == signature.oem_id && sdt.oem_table_id == signature.oem_table_id) + self.tables.iter().find(|sdt| { + sdt.signature == signature.signature + && sdt.oem_id == signature.oem_id + && sdt.oem_table_id == signature.oem_table_id + }) } pub fn get_signature_from_index(&self, index: usize) -> Option { self.sdt_order.read().get(index).copied().flatten() } pub fn get_index_from_signature(&self, signature: &SdtSignature) -> Option { - self.sdt_order.read().iter().rposition(|sig| sig.map_or(false, |sig| &sig == signature)) + self.sdt_order + .read() + .iter() + .rposition(|sig| sig.map_or(false, |sig| &sig == signature)) } pub fn tables(&self) -> &[Sdt] { &self.tables @@ -507,8 +410,7 @@ impl AcpiContext { None } - pub fn aml_symbols(&self) -> Result, SymbolListError> { - + pub fn aml_symbols(&self) -> Result, AmlError> { // return the cached value if it exists let symbols = self.aml_symbols.read(); if !symbols.symbols_cache.is_empty() { @@ -520,62 +422,57 @@ impl AcpiContext { // 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_list: Vec<(String, AmlHandle)> = Vec::with_capacity(3000); + let mut symbol_list: Vec<(AmlName, String, AmlHandle)> = Vec::with_capacity(5000); let mut aml_symbols = self.aml_symbols.write(); - let root = aml::AmlName::root(); - let traverse = aml_symbols.aml_context.namespace - .traverse(| level_aml_name, level | { - let level_is_root = level_aml_name.eq(&root); - let level_name = AmlSymbols::pretty_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 { - AmlSymbols::root_symbol(name.as_str()) + aml_symbols + .aml_context + .namespace + .traverse(|level_aml_name, level| { + for (child_seg, handle) in level.values.iter() { + if let Ok(aml_name) = + AmlName::from_name_seg(child_seg.to_owned()).resolve(level_aml_name) + { + let name = pretty_name(&aml_name); + symbol_list.push((aml_name, name, handle.to_owned())); } else { - AmlSymbols::child_symbol(&level_name, name.as_str()) - }; - symbols_str.push_str(&symbol); - symbols_str.push('\n'); - symbols_list.push((symbol, handle.to_owned())); + log::error!( + "AmlName resolve failed, {:?}:{:?}", + level_aml_name, + child_seg + ); + } } Ok(true) - }); - - match traverse { - Err(error) => { - log::error!("Traverse failed, {:?}", error); - return Err(SymbolListError::AmlInternalError); - } - _ => {} - } + })?; + let mut symbols_str = String::with_capacity(symbol_list.len() * 10); let mut handle_lookup = AmlHandleLookup::new(); - for (name, handle) in &symbols_list { - handle_lookup.insert(handle, name); - } - - let namespace = &aml_symbols.aml_context.namespace; - - let mut symbols_cache: FxHashMap = FxHashMap::default(); - - for (name, handle) in symbols_list { - if let Ok(value) = namespace.get(handle.to_owned()) { - symbols_cache.insert(name.to_owned(), AmlSymbols::format_value(&name, value, &handle_lookup)); - } + for (_aml_name, name, handle) in &symbol_list { + let _ = writeln!(symbols_str, "{}", &name); + handle_lookup.insert(handle.to_owned(), name.to_owned()); } symbols_str.shrink_to_fit(); + let mut symbol_cache: FxHashMap = FxHashMap::default(); + + for (_aml_name, name, handle) in &symbol_list { + if let Some(ser_value) = AmlSerde::from_aml(&aml_symbols.aml_context, &handle_lookup, handle) { + if let Ok(ser_string) = serde_json::to_string_pretty(&ser_value) { + symbol_cache.insert(name.to_owned(), ser_string); + } + } + } + + // Cache the new list log::trace!("Updating symbols list"); aml_symbols.symbols_str = symbols_str; - aml_symbols.symbols_cache = symbols_cache; + aml_symbols.symbols_cache = symbol_cache; // return the cached value Ok(RwLockWriteGuard::downgrade(aml_symbols)) @@ -598,7 +495,7 @@ impl AcpiContext { } let fadt = match self.fadt() { Some(fadt) => fadt, - None => { + None => { log::error!("Cannot set global S-state due to missing FADT."); return; } @@ -611,26 +508,41 @@ impl AcpiContext { 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; } + Err(error) => { + log::error!("Could not build AmlName for \\_S5, {:?}", error); + return; + } }; let s5 = match aml_symbols.aml_context.namespace.get_by_path(&s5_aml_name) { Ok(s5) => s5, - Err(error) => { log::error!("Cannot set S-state, missing \\_S5, {:?}", error); return; } + 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; } + _ => { + 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; } + _ => { + 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::error!("typb is not an Integer"); + return; + } }; log::trace!("Shutdown SLP_TYPa {:X}, SLP_TYPb {:X}", slp_typa, slp_typb); @@ -646,14 +558,17 @@ impl AcpiContext { #[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); + log::error!( + "Cannot shutdown with ACPI outw(0x{:X}, 0x{:X}) on this architecture", + port, + val + ); } loop { core::hint::spin_loop(); } } - } #[repr(packed)] @@ -746,12 +661,14 @@ pub struct Fadt(Sdt); impl Fadt { pub fn acpi_2_struct(&self) -> Option<&FadtAcpi2Struct> { - let bytes = &self.0.0[mem::size_of::()..]; + let bytes = &self.0 .0[mem::size_of::()..]; match plain::from_bytes::(bytes) { Ok(fadt2) => Some(fadt2), Err(plain::Error::TooShort) => None, - Err(plain::Error::BadAlignment) => unreachable!("plain::from_bytes reported bad alignment, but FadtAcpi2Struct is #[repr(packed)]"), + Err(plain::Error::BadAlignment) => unreachable!( + "plain::from_bytes reported bad alignment, but FadtAcpi2Struct is #[repr(packed)]" + ), } } } @@ -760,7 +677,7 @@ impl Deref for Fadt { type Target = FadtStruct; fn deref(&self) -> &Self::Target { - plain::from_bytes::(&self.0.0) + plain::from_bytes::(&self.0 .0) .expect("expected FADT struct to already be validated in Deref impl") } } @@ -788,14 +705,12 @@ impl Fadt { let dsdt_ptr = match fadt.acpi_2_struct() { Some(fadt2) => usize::try_from(fadt2.x_dsdt).unwrap_or_else(|_| { - usize::try_from(fadt.dsdt) - .expect("expected any given u32 to fit within usize") + usize::try_from(fadt.dsdt).expect("expected any given u32 to fit within usize") }), - None => usize::try_from(fadt.dsdt) - .expect("expected any given u32 to fit within usize") + None => usize::try_from(fadt.dsdt).expect("expected any given u32 to fit within usize"), }; - log::debug!("FACP at {:X}", {dsdt_ptr}); + log::debug!("FACP at {:X}", { dsdt_ptr }); let dsdt_sdt = match Sdt::load_from_physical(fadt.dsdt as usize) { Ok(dsdt) => dsdt, @@ -933,23 +848,61 @@ impl aml::Handler for AmlPhysMemHandler { 0 } - fn read_pci_u16(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16) -> u16 { + 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 { + 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) { + 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) { + 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) { + fn write_pci_u32( + &self, + _segment: u16, + _bus: u8, + _device: u8, + _function: u8, + _offset: u16, + _value: u32, + ) { log::error!("write pci u8 {:X}", _device); } } @@ -1014,23 +967,61 @@ impl aml::Handler for AmlPhysMemHandler { 0 } - fn read_pci_u16(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16) -> u16 { + 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 { + 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) { + 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) { + 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) { + fn write_pci_u32( + &self, + _segment: u16, + _bus: u8, + _device: u8, + _function: u8, + _offset: u16, + _value: u32, + ) { log::error!("write pci u8 {:X}", _device); } } diff --git a/acpid/src/scheme.rs b/acpid/src/scheme.rs index d09b4aee33..99151814f1 100644 --- a/acpid/src/scheme.rs +++ b/acpid/src/scheme.rs @@ -45,7 +45,7 @@ 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(aml_symbols) => aml_symbols.to_str().len(), + Self::Symbols(aml_symbols) => aml_symbols.symbols_str.len(), Self::Symbol(description) => description.len(), }) } @@ -287,7 +287,7 @@ impl SchemeMut for AcpiScheme<'_> { } HandleKind::Symbols(aml_symbols) => { - let symbols = aml_symbols.to_str(); + let symbols = &aml_symbols.symbols_str; let offset = std::cmp::min(symbols.len(), handle.offset); let src_buf = &symbols.as_bytes()[offset..]; diff --git a/amlserde/Cargo.toml b/amlserde/Cargo.toml new file mode 100644 index 0000000000..49adbe294e --- /dev/null +++ b/amlserde/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "amlserde" +version = "0.0.1" +authors = ["Ron Williams"] +repository = "https://gitlab.redox-os.org/redox-os/drivers" +description = "Library for serializing AML symbols" +categories = ["hardware-support"] +license = "MIT/Apache-2.0" +edition = "2021" + +[dependencies] +aml = { git = "https://github.com/rw-vanc/acpi.git", branch = "cumulative" } +rustc-hash = "1.1.0" +serde = { version = "1.0", features = ["derive"] } +toml = "0.7.3" diff --git a/amlserde/src/lib.rs b/amlserde/src/lib.rs new file mode 100644 index 0000000000..51417c776f --- /dev/null +++ b/amlserde/src/lib.rs @@ -0,0 +1,295 @@ +use aml::{ + value::{FieldAccessType, FieldUpdateRule, RegionSpace}, + AmlContext, AmlHandle, AmlName, AmlValue, +}; +use rustc_hash::FxHashMap; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct AmlSerde { + pub name: String, + pub value: AmlSerdeValue, +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum AmlSerdeValue { + Boolean(bool), + Integer(u64), + String(String), + OpRegion { + region: AmlSerdeRegionSpace, + offset: u64, + length: u64, + parent_device: Option, + }, + Field { + region: String, + flags: AmlSerdeFieldFlags, + offset: u64, + length: u64, + }, + Device, + Method { + arg_count: u8, + serialize: bool, + sync_level: u8, + }, + Buffer, + BufferField { + offset: u64, + length: u64, + }, + Processor { + id: u8, + pblk_address: u32, + pblk_len: u8, + }, + Mutex { + sync_level: u8, + }, + Package { + contents: Vec, + }, + PowerResource { + system_level: u8, + resource_order: u16, + }, + ThermalZone, + External, +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum AmlSerdeRegionSpace { + SystemMemory, + SystemIo, + PciConfig, + EmbeddedControl, + SMBus, + SystemCmos, + PciBarTarget, + IPMI, + GeneralPurposeIo, + GenericSerialBus, + OemDefined(u8), +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct AmlSerdeFieldFlags { + access_type: AmlSerdeFieldAccessType, + lock_rule: bool, + update_rule: AmlSerdeFieldUpdateRule, +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum AmlSerdeFieldAccessType { + Any, + Byte, + Word, + DWord, + QWord, + Buffer, +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum AmlSerdeFieldUpdateRule { + Preserve, + WriteAsOnes, + WriteAsZeros, +} + +impl AmlSerde { + pub fn default() -> Self { + Self { + name: "name".to_owned(), + value: AmlSerdeValue::String(String::default()), + } + } + + pub fn from_aml( + aml_context: &AmlContext, + aml_lookup: &AmlHandleLookup, + handle: &AmlHandle, + ) -> Option { + let name = if let Some((name, _handle)) = aml_lookup.get(handle) { + name.to_owned() + } else { + return None; + }; + + let aml_value = if let Ok(aml_value) = aml_context.namespace.get(handle.clone()) { + aml_value + } else { + return None; + }; + + let value = if let Some(value) = AmlSerdeValue::from_aml_value(aml_value, aml_lookup) { + value + } else { + return None; + }; + + Some(AmlSerde { name, value }) + } +} + +impl AmlSerdeValue { + pub fn default() -> Self { + AmlSerdeValue::String("".to_owned()) + } + + fn from_aml_value(aml_value: &AmlValue, aml_lookup: &AmlHandleLookup) -> Option { + Some(match aml_value { + AmlValue::Boolean(b) => AmlSerdeValue::Boolean(b.to_owned()), + + AmlValue::Integer(n) => AmlSerdeValue::Integer(n.to_owned()), + + AmlValue::String(s) => AmlSerdeValue::String(s.to_owned()), + + AmlValue::OpRegion { + region, + offset, + length, + parent_device, + } => AmlSerdeValue::OpRegion { + region: match region { + RegionSpace::SystemMemory => AmlSerdeRegionSpace::SystemMemory, + RegionSpace::SystemIo => AmlSerdeRegionSpace::SystemIo, + RegionSpace::PciConfig => AmlSerdeRegionSpace::PciConfig, + RegionSpace::EmbeddedControl => AmlSerdeRegionSpace::EmbeddedControl, + RegionSpace::SMBus => AmlSerdeRegionSpace::SMBus, + RegionSpace::SystemCmos => AmlSerdeRegionSpace::SystemCmos, + RegionSpace::PciBarTarget => AmlSerdeRegionSpace::PciBarTarget, + RegionSpace::IPMI => AmlSerdeRegionSpace::IPMI, + RegionSpace::GeneralPurposeIo => AmlSerdeRegionSpace::GeneralPurposeIo, + RegionSpace::GenericSerialBus => AmlSerdeRegionSpace::GenericSerialBus, + RegionSpace::OemDefined(n) => AmlSerdeRegionSpace::OemDefined(n.to_owned()), + }, + offset: offset.to_owned(), + length: length.to_owned(), + parent_device: if let Some(parent) = parent_device { + Some(pretty_name(parent)) + } else { + None + }, + }, + + AmlValue::Field { + region, + flags, + offset, + length, + } => AmlSerdeValue::Field { + region: if let Some((region, _handle)) = aml_lookup.get(region) { + region.to_owned() + } else { + return None; + }, + flags: AmlSerdeFieldFlags { + access_type: match flags.access_type() { + Ok(FieldAccessType::Any) => AmlSerdeFieldAccessType::Any, + Ok(FieldAccessType::Byte) => AmlSerdeFieldAccessType::Byte, + Ok(FieldAccessType::Word) => AmlSerdeFieldAccessType::Word, + Ok(FieldAccessType::DWord) => AmlSerdeFieldAccessType::DWord, + Ok(FieldAccessType::QWord) => AmlSerdeFieldAccessType::QWord, + Ok(FieldAccessType::Buffer) => AmlSerdeFieldAccessType::Buffer, + _ => return None, + }, + lock_rule: flags.lock_rule(), + update_rule: match flags.field_update_rule() { + Ok(FieldUpdateRule::Preserve) => AmlSerdeFieldUpdateRule::Preserve, + Ok(FieldUpdateRule::WriteAsOnes) => AmlSerdeFieldUpdateRule::WriteAsOnes, + Ok(FieldUpdateRule::WriteAsZeros) => AmlSerdeFieldUpdateRule::WriteAsZeros, + _ => return None, + }, + }, + offset: offset.to_owned(), + length: length.to_owned(), + }, + + AmlValue::Device => AmlSerdeValue::Device, + + AmlValue::Method { flags, code: _ } => AmlSerdeValue::Method { + arg_count: flags.arg_count(), + serialize: flags.serialize(), + sync_level: flags.sync_level(), + }, + AmlValue::Buffer(_) => AmlSerdeValue::Buffer, + AmlValue::BufferField { + buffer_data: _, + offset, + length, + } => AmlSerdeValue::BufferField { + offset: offset.to_owned(), + length: length.to_owned(), + }, + AmlValue::Processor { + id, + pblk_address, + pblk_len, + } => AmlSerdeValue::Processor { + id: id.to_owned(), + pblk_address: pblk_address.to_owned(), + pblk_len: pblk_len.to_owned(), + }, + AmlValue::Mutex { sync_level } => AmlSerdeValue::Mutex { + sync_level: sync_level.to_owned(), + }, + AmlValue::Package(aml_contents) => AmlSerdeValue::Package { + contents: aml_contents + .iter() + .filter_map(|item| AmlSerdeValue::from_aml_value(item, aml_lookup)) + .collect(), + }, + + AmlValue::PowerResource { + system_level, + resource_order, + } => AmlSerdeValue::PowerResource { + system_level: system_level.to_owned(), + resource_order: resource_order.to_owned(), + }, + AmlValue::ThermalZone => AmlSerdeValue::ThermalZone, + AmlValue::External => AmlSerdeValue::External, + }) + } +} + +pub struct AmlHandleLookup { + map: FxHashMap, +} + +impl AmlHandleLookup { + pub fn new() -> Self { + Self { + map: FxHashMap::default(), + } + } + + fn handle_to_key(&self, handle: &AmlHandle) -> String { + format!("{:?}", handle) + } + + pub fn insert(&mut self, handle: AmlHandle, name: String) { + self.map.insert(self.handle_to_key(&handle), (name, handle)); + } + + pub fn get(&self, handle: &AmlHandle) -> Option<&(String, AmlHandle)> { + self.map.get(&self.handle_to_key(handle)) + } +} + +/// Remove trailing underscores from each name segment +pub fn pretty_name(aml_name: &AmlName) -> String { + let mut name = aml_name.as_string(); + // remove leading slash + name = name.trim_start_matches("\\").to_owned(); + // 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 +}