Add serde with separate library for definitions

This commit is contained in:
Ron Williams
2023-03-27 20:58:59 -07:00
parent ef48f4aa9a
commit 23be7ed63c
6 changed files with 649 additions and 253 deletions
Generated
+114 -22
View File
@@ -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",
]
+3
View File
@@ -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" }
+220 -229
View File
@@ -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::<SdtHeader>(&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::<SdtHeader>()).is_none();
let needs_extra_page = (PAGE_SIZE - physaddr_page_offset)
.checked_sub(mem::size_of::<SdtHeader>())
.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<AmlName>) -> 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<AmlValue>) -> 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<String, String>,
}
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<Sdt>,
dsdt: Option<Dsdt>,
@@ -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<Vec<Option<SdtSignature>>>,
pub next_ctx: RwLock<u64>,
@@ -391,16 +268,17 @@ pub struct AcpiContext {
impl AcpiContext {
pub fn init(rxsdt_physaddrs: impl Iterator<Item = u64>) -> 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::<Vec<Sdt>>();
Sdt::load_from_physical(physaddr).expect("failed to load physical SDT")
})
.collect::<Vec<Sdt>>();
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<Item = Ssdt> + '_ {
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<usize> {
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<Item = &'a Sdt> {
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<Sdt> {
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<SdtSignature> {
self.sdt_order.read().get(index).copied().flatten()
}
pub fn get_index_from_signature(&self, signature: &SdtSignature) -> Option<usize> {
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<RwLockReadGuard<'_, AmlSymbols>, SymbolListError> {
pub fn aml_symbols(&self) -> Result<RwLockReadGuard<'_, AmlSymbols>, 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<String, String> = 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<String, String> = 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::<FadtStruct>()..];
let bytes = &self.0 .0[mem::size_of::<FadtStruct>()..];
match plain::from_bytes::<FadtAcpi2Struct>(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::<FadtStruct>(&self.0.0)
plain::from_bytes::<FadtStruct>(&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);
}
}
+2 -2
View File
@@ -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..];
+15
View File
@@ -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"
+295
View File
@@ -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<String>,
},
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<AmlSerdeValue>,
},
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<Self> {
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<Self> {
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<String, (String, AmlHandle)>,
}
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
}