Files
RedBear-OS/acpid/src/aml/namespace.rs
T
2021-03-11 12:48:34 +01:00

488 lines
15 KiB
Rust

use std::collections::BTreeMap;
use core::fmt::Debug;
use core::str::FromStr;
use super::termlist::parse_term_list;
use super::namedobj::{ RegionSpace, FieldFlags };
use super::parser::{AmlExecutionContext, ExecutionState};
use super::AmlError;
use crate::acpi::{AcpiContext, SdtSignature};
#[derive(Clone, Debug)]
pub enum FieldSelector {
Region(String),
Bank {
region: String,
bank_register: String,
bank_selector: Box<AmlValue>
},
Index {
index_selector: String,
data_selector: String
}
}
#[derive(Clone, Debug)]
pub enum ObjectReference {
ArgObj(u8),
LocalObj(u8),
Object(String),
Index(Box<AmlValue>, Box<AmlValue>)
}
#[derive(Clone, Debug)]
pub struct Method {
pub arg_count: u8,
pub serialized: bool,
pub sync_level: u8,
pub term_list: Vec<u8>
}
#[derive(Clone, Debug)]
pub struct BufferField {
pub source_buf: Box<AmlValue>,
pub index: Box<AmlValue>,
pub length: Box<AmlValue>
}
#[derive(Clone, Debug)]
pub struct FieldUnit {
pub selector: FieldSelector,
pub connection: Box<AmlValue>,
pub flags: FieldFlags,
pub offset: usize,
pub length: usize
}
#[derive(Clone, Debug)]
pub struct Device {
pub obj_list: Vec<String>,
pub notify_methods: BTreeMap<u8, Vec<fn()>>
}
#[derive(Clone, Debug)]
pub struct ThermalZone {
pub obj_list: Vec<String>,
pub notify_methods: BTreeMap<u8, Vec<fn()>>
}
#[derive(Clone, Debug)]
pub struct Processor {
pub proc_id: u8,
pub p_blk: Option<u32>,
pub obj_list: Vec<String>,
pub notify_methods: BTreeMap<u8, Vec<fn()>>
}
#[derive(Clone, Debug)]
pub struct OperationRegion {
pub region: RegionSpace,
pub offset: Box<AmlValue>,
pub len: Box<AmlValue>,
pub accessor: Accessor,
pub accessed_by: Option<u64>
}
#[derive(Clone, Debug)]
pub struct PowerResource {
pub system_level: u8,
pub resource_order: u16,
pub obj_list: Vec<String>
}
#[derive(Debug)]
pub struct Accessor {
pub read: fn(usize) -> u64,
pub write: fn(usize, u64)
}
impl Clone for Accessor {
fn clone(&self) -> Accessor {
Accessor {
read: (*self).read,
write: (*self).write
}
}
}
#[derive(Clone, Debug)]
pub enum AmlValue {
None,
Uninitialized,
Alias(String),
Buffer(Vec<u8>),
BufferField(BufferField),
DDBHandle((Vec<String>, SdtSignature)),
DebugObject,
Device(Device),
Event(u64),
FieldUnit(FieldUnit),
Integer(u64),
IntegerConstant(u64),
Method(Method),
Mutex((u8, Option<u64>)),
ObjectReference(ObjectReference),
OperationRegion(OperationRegion),
Package(Vec<AmlValue>),
String(String),
PowerResource(PowerResource),
Processor(Processor),
RawDataBuffer(Vec<u8>),
ThermalZone(ThermalZone)
}
impl AmlValue {
pub fn get_type_string(&self) -> String {
match *self {
AmlValue::Uninitialized => String::from_str("[Uninitialized Object]").unwrap(),
AmlValue::Integer(_) => String::from_str("[Integer]").unwrap(),
AmlValue::String(_) => String::from_str("[String]").unwrap(),
AmlValue::Buffer(_) => String::from_str("[Buffer]").unwrap(),
AmlValue::Package(_) => String::from_str("[Package]").unwrap(),
AmlValue::FieldUnit(_) => String::from_str("[Field]").unwrap(),
AmlValue::Device(_) => String::from_str("[Device]").unwrap(),
AmlValue::Event(_) => String::from_str("[Event]").unwrap(),
AmlValue::Method(_) => String::from_str("[Control Method]").unwrap(),
AmlValue::Mutex(_) => String::from_str("[Mutex]").unwrap(),
AmlValue::OperationRegion(_) => String::from_str("[Operation Region]").unwrap(),
AmlValue::PowerResource(_) => String::from_str("[Power Resource]").unwrap(),
AmlValue::Processor(_) => String::from_str("[Processor]").unwrap(),
AmlValue::ThermalZone(_) => String::from_str("[Thermal Zone]").unwrap(),
AmlValue::BufferField(_) => String::from_str("[Buffer Field]").unwrap(),
AmlValue::DDBHandle(_) => String::from_str("[DDB Handle]").unwrap(),
AmlValue::DebugObject => String::from_str("[Debug Object]").unwrap(),
_ => String::new()
}
}
pub fn get_as_type(&self, ctx: &AcpiContext, t: AmlValue) -> Result<AmlValue, AmlError> {
match t {
AmlValue::None => Ok(AmlValue::None),
AmlValue::Uninitialized => Ok(self.clone()),
AmlValue::Alias(_) => match *self {
AmlValue::Alias(_) => Ok(self.clone()),
_ => Err(AmlError::AmlValueError)
},
AmlValue::Buffer(_) => Ok(AmlValue::Buffer(self.get_as_buffer(ctx)?)),
AmlValue::BufferField(_) => Ok(AmlValue::BufferField(self.get_as_buffer_field(ctx)?)),
AmlValue::DDBHandle(_) => Ok(AmlValue::DDBHandle(self.get_as_ddb_handle(ctx)?)),
AmlValue::DebugObject => match *self {
AmlValue::DebugObject => Ok(self.clone()),
_ => Err(AmlError::AmlValueError)
},
AmlValue::Device(_) => Ok(AmlValue::Device(self.get_as_device()?)),
AmlValue::Event(_) => Ok(AmlValue::Event(self.get_as_event()?)),
AmlValue::FieldUnit(_) => Ok(AmlValue::FieldUnit(self.get_as_field_unit()?)),
AmlValue::Integer(_) => Ok(AmlValue::Integer(self.get_as_integer(ctx)?)),
AmlValue::IntegerConstant(_) => Ok(AmlValue::IntegerConstant(self.get_as_integer_constant()?)),
AmlValue::Method(_) => Ok(AmlValue::Method(self.get_as_method()?)),
AmlValue::Mutex(_) => Ok(AmlValue::Mutex(self.get_as_mutex()?)),
AmlValue::ObjectReference(_) => Ok(AmlValue::ObjectReference(self.get_as_object_reference()?)),
AmlValue::OperationRegion(_) => match *self {
AmlValue::OperationRegion(_) => Ok(self.clone()),
_ => Err(AmlError::AmlValueError)
},
AmlValue::Package(_) => Ok(AmlValue::Package(self.get_as_package()?)),
AmlValue::String(_) => Ok(AmlValue::String(self.get_as_string(ctx)?)),
AmlValue::PowerResource(_) => Ok(AmlValue::PowerResource(self.get_as_power_resource()?)),
AmlValue::Processor(_) => Ok(AmlValue::Processor(self.get_as_processor()?)),
AmlValue::RawDataBuffer(_) => Ok(AmlValue::RawDataBuffer(self.get_as_raw_data_buffer()?)),
AmlValue::ThermalZone(_) => Ok(AmlValue::ThermalZone(self.get_as_thermal_zone()?))
}
}
pub fn get_as_buffer(&self, ctx: &AcpiContext) -> Result<Vec<u8>, AmlError> {
match *self {
AmlValue::Buffer(ref b) => Ok(b.clone()),
AmlValue::Integer(ref i) => {
let mut v: Vec<u8> = vec!();
let mut i = i.clone();
while i != 0 {
v.push((i & 0xFF) as u8);
i >>= 8;
}
while v.len() < 8 {
v.push(0);
}
Ok(v)
},
AmlValue::String(ref s) => {
Ok(s.clone().into_bytes())
},
AmlValue::BufferField(ref b) => {
let buf = b.source_buf.get_as_buffer(ctx)?;
let idx = b.index.get_as_integer(ctx)? as usize;
let len = b.length.get_as_integer(ctx)? as usize;
if idx + len > buf.len() {
return Err(AmlError::AmlValueError);
}
Ok(buf[idx .. idx + len].to_vec())
},
_ => Err(AmlError::AmlValueError)
}
}
pub fn get_as_buffer_field(&self, acpi_ctx: &AcpiContext) -> Result<BufferField, AmlError> {
match *self {
AmlValue::BufferField(ref b) => Ok(b.clone()),
_ => {
let raw_buf = self.get_as_buffer(acpi_ctx)?;
let buf = Box::new(AmlValue::Buffer(raw_buf.clone()));
let idx = Box::new(AmlValue::IntegerConstant(0));
let len = Box::new(AmlValue::Integer(raw_buf.len() as u64));
Ok(BufferField {
source_buf: buf,
index: idx,
length: len
})
}
}
}
pub fn get_as_ddb_handle(&self, acpi_ctx: &AcpiContext) -> Result<(Vec<String>, SdtSignature), AmlError> {
match *self {
AmlValue::DDBHandle(ref v) => Ok(v.clone()),
AmlValue::Integer(i) => if let Some(sig) = acpi_ctx.get_signature_from_index(i as usize) {
Ok((vec!(), sig))
} else {
log::error!("AmlValueError in get_as_ddb_handle integer");
Err(AmlError::AmlValueError)
},
_ => { log::error!("AmlValueError in get_as_ddb_handle other"); Err(AmlError::AmlValueError) }
}
}
pub fn get_as_device(&self) -> Result<Device, AmlError> {
match *self {
AmlValue::Device(ref s) => Ok(s.clone()),
_ => Err(AmlError::AmlValueError)
}
}
pub fn get_as_event(&self) -> Result<u64, AmlError> {
match *self {
AmlValue::Event(ref e) => Ok(e.clone()),
_ => Err(AmlError::AmlValueError)
}
}
pub fn get_as_field_unit(&self) -> Result<FieldUnit, AmlError> {
match *self {
AmlValue::FieldUnit(ref e) => Ok(e.clone()),
_ => Err(AmlError::AmlValueError)
}
}
pub fn get_as_integer(&self, acpi_ctx: &AcpiContext) -> Result<u64, AmlError> {
match *self {
AmlValue::IntegerConstant(ref i) => Ok(i.clone()),
AmlValue::Integer(ref i) => Ok(i.clone()),
AmlValue::Buffer(ref b) => {
let mut b = b.clone();
if b.len() > 8 {
return Err(AmlError::AmlValueError);
}
let mut i: u64 = 0;
while b.len() > 0 {
i <<= 8;
i += b.pop().expect("Won't happen") as u64;
}
Ok(i)
},
AmlValue::BufferField(_) => {
let mut b = self.get_as_buffer(acpi_ctx)?;
if b.len() > 8 {
return Err(AmlError::AmlValueError);
}
let mut i: u64 = 0;
while b.len() > 0 {
i <<= 8;
i += b.pop().expect("Won't happen") as u64;
}
Ok(i)
},
AmlValue::DDBHandle(ref v) => if let Some(idx) = acpi_ctx.get_index_from_signature(&v.1) {
Ok(idx as u64)
} else {
Err(AmlError::AmlValueError)
},
AmlValue::String(ref s) => {
let s = s.clone()[0..8].to_string().to_uppercase();
let mut i: u64 = 0;
for c in s.chars() {
if !c.is_digit(16) {
break;
}
i <<= 8;
i += c.to_digit(16).unwrap() as u64;
}
Ok(i)
},
_ => Err(AmlError::AmlValueError)
}
}
pub fn get_as_integer_constant(&self) -> Result<u64, AmlError> {
match *self {
AmlValue::IntegerConstant(ref i) => Ok(i.clone()),
_ => Err(AmlError::AmlValueError)
}
}
pub fn get_as_method(&self) -> Result<Method, AmlError> {
match *self {
AmlValue::Method(ref m) => Ok(m.clone()),
_ => Err(AmlError::AmlValueError)
}
}
pub fn get_as_mutex(&self) -> Result<(u8, Option<u64>), AmlError> {
match *self {
AmlValue::Mutex(ref m) => Ok(m.clone()),
_ => Err(AmlError::AmlValueError)
}
}
pub fn get_as_object_reference(&self) -> Result<ObjectReference, AmlError> {
match *self {
AmlValue::ObjectReference(ref m) => Ok(m.clone()),
_ => Err(AmlError::AmlValueError)
}
}
/*
pub fn get_as_operation_region(&self) -> Result<OperationRegion, AmlError> {
match *self {
AmlValue::OperationRegion(ref p) => Ok(p.clone()),
_ => Err(AmlError::AmlValueError)
}
}
*/
pub fn get_as_package(&self) -> Result<Vec<AmlValue>, AmlError> {
match *self {
AmlValue::Package(ref p) => Ok(p.clone()),
_ => Err(AmlError::AmlValueError)
}
}
pub fn get_as_string(&self, ctx: &AcpiContext) -> Result<String, AmlError> {
match *self {
AmlValue::String(ref s) => Ok(s.clone()),
AmlValue::Integer(ref i) => Ok(format!("{:X}", i)),
AmlValue::IntegerConstant(ref i) => Ok(format!("{:X}", i)),
AmlValue::Buffer(ref b) => Ok(String::from_utf8(b.clone()).expect("Invalid UTF-8")),
AmlValue::BufferField(_) => {
let b = self.get_as_buffer(ctx)?;
Ok(String::from_utf8(b).expect("Invalid UTF-8"))
},
_ => Err(AmlError::AmlValueError)
}
}
pub fn get_as_power_resource(&self) -> Result<PowerResource, AmlError> {
match *self {
AmlValue::PowerResource(ref p) => Ok(p.clone()),
_ => Err(AmlError::AmlValueError)
}
}
pub fn get_as_processor(&self) -> Result<Processor, AmlError> {
match *self {
AmlValue::Processor(ref p) => Ok(p.clone()),
_ => Err(AmlError::AmlValueError)
}
}
pub fn get_as_raw_data_buffer(&self) -> Result<Vec<u8>, AmlError> {
match *self {
AmlValue::RawDataBuffer(ref p) => Ok(p.clone()),
_ => Err(AmlError::AmlValueError)
}
}
pub fn get_as_thermal_zone(&self) -> Result<ThermalZone, AmlError> {
match *self {
AmlValue::ThermalZone(ref p) => Ok(p.clone()),
_ => Err(AmlError::AmlValueError)
}
}
}
impl Method {
pub fn execute(&self, acpi_ctx: &AcpiContext, scope: String, parameters: Vec<AmlValue>) -> AmlValue {
let mut ctx = AmlExecutionContext::new(acpi_ctx, scope);
ctx.init_arg_vars(parameters);
let _ = parse_term_list(&self.term_list[..], &mut ctx);
ctx.clean_namespace(acpi_ctx);
match ctx.state {
ExecutionState::RETURN(v) => v,
_ => AmlValue::IntegerConstant(0)
}
}
}
pub fn get_namespace_string(ctx: &AcpiContext, current: String, modifier_v: AmlValue) -> Result<String, AmlError> {
let mut modifier = modifier_v.get_as_string(ctx)?;
if current.len() == 0 {
return Ok(modifier);
}
if modifier.len() == 0 {
return Ok(current);
}
if modifier.starts_with("\\") {
return Ok(modifier);
}
let mut namespace = current.clone();
if modifier.starts_with("^") {
while modifier.starts_with("^") {
modifier = modifier[1..].to_string();
if namespace.ends_with("\\") {
return Err(AmlError::AmlValueError);
}
loop {
if namespace.ends_with(".") {
namespace.pop();
break;
}
if namespace.pop() == None {
return Err(AmlError::AmlValueError);
}
}
}
}
if !namespace.ends_with("\\") {
namespace.push('.');
}
Ok(namespace + &modifier)
}