Files
RedBear-OS/amlserde/src/lib.rs
T
2023-03-29 01:41:13 -07:00

312 lines
9.3 KiB
Rust

use aml::value::{FieldAccessType, FieldUpdateRule, RegionSpace};
use aml::{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 {
pub access_type: AmlSerdeFieldAccessType,
pub lock_rule: bool,
pub 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: &mut AmlContext,
aml_lookup: &AmlHandleLookup,
name: &String,
aml_name: &AmlName,
handle: &AmlHandle,
) -> Option<Self> {
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: aml_name.to_string(),
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(parent.to_string())
} else {
None
},
},
AmlValue::Field {
region,
flags,
offset,
length,
} => AmlSerdeValue::Field {
region: if let Some((region, _handle)) = aml_lookup.get(region) {
region.to_string()
} 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 mod aml_serde_name {
use aml::AmlName;
/// Add a leading backslash to make the name a valid
/// namespace reference
pub fn to_aml_format(pretty_name: &String) -> String {
format!("\\{}", pretty_name)
}
/// convert a string from AML namespace style to
/// acpi symbol style
pub fn to_symbol(aml_style_name: &String) -> String {
let mut name = aml_style_name.to_owned();
// 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
}
/// Convert to string and remove
/// trailing underscores from each name segment
pub fn aml_to_symbol(aml_name: &AmlName) -> String {
to_symbol(&aml_name.as_string())
}
}
pub struct AmlHandleLookup {
map: FxHashMap<String, (AmlName, 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, aml_name: AmlName) {
self.map
.insert(self.handle_to_key(&handle), (aml_name, handle));
}
pub fn get(&self, handle: &AmlHandle) -> Option<&(AmlName, AmlHandle)> {
self.map.get(&self.handle_to_key(handle))
}
}