Successfully parse the namespace.

This commit is contained in:
4lDO2
2021-03-11 12:48:34 +01:00
parent 0feb8685a6
commit 5fc0f0fa4e
7 changed files with 98 additions and 64 deletions
+53 -17
View File
@@ -1,7 +1,7 @@
use std::collections::HashMap;
use std::collections::{BTreeMap, HashMap};
use std::convert::{TryFrom, TryInto};
use std::ops::Deref;
use std::sync::Arc;
use std::sync::{Arc, atomic::{self, AtomicUsize}};
use std::{fmt, mem};
use syscall::flag::PhysmapFlags;
@@ -46,13 +46,19 @@ impl SdtHeader {
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct SdtSignature {
pub signature: [u8; 4],
pub oem_id: [u8; 6],
pub oem_table_id: [u8; 8],
}
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))
}
}
#[derive(Debug, Error)]
pub enum TablePhysLoadError {
// TODO: Make syscall::Error implement std::error::Error, when enabling a Cargo feature.
@@ -208,7 +214,17 @@ pub struct AcpiContext {
tables: Vec<Sdt>,
dsdt: Option<Dsdt>,
fadt: Option<Fadt>,
// TODO: Remove Option. This is not kernel code, and not static, but we still need to replace
// every match where namespace{,_mut}() are used.
namespace: RwLock<Option<HashMap<String, AmlValue>>>,
// 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>,
}
impl AcpiContext {
@@ -228,12 +244,20 @@ impl AcpiContext {
tables,
dsdt: None,
fadt: None,
namespace: RwLock::new(None),
namespace: RwLock::new(Some(HashMap::new())),
next_ctx: RwLock::new(0),
sdt_order: RwLock::new(Vec::new()),
};
for table in &this.tables {
this.new_index(&table.signature());
}
Fadt::init(&mut this);
crate::aml::init_namespace(&this);
this
}
@@ -252,9 +276,6 @@ impl AcpiContext {
self.tables.iter().position(|sdt| sdt.signature == signature)
}
pub fn find_single_sdt(&self, signature: [u8; 4]) -> Option<&Sdt> {
self.find_single_sdt_pos(signature).map(|pos| &self.tables[pos])
}
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)
}
@@ -274,14 +295,17 @@ impl AcpiContext {
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> {
todo!()
self.sdt_order.read().get(index).copied().flatten()
}
pub fn get_index_from_signature(&self, signature: &SdtSignature) -> Option<usize> {
todo!()
self.sdt_order.read().iter().rposition(|sig| sig.map_or(false, |sig| &sig == signature))
}
pub fn tables(&self) -> &[Sdt] {
&self.tables
}
pub fn new_index(&self, signature: &SdtSignature) {
self.sdt_order.write().push(Some(*signature));
}
}
#[repr(packed)]
@@ -393,7 +417,7 @@ impl Deref for Fadt {
}
impl Fadt {
pub fn new(context: &AcpiContext, sdt: Sdt) -> Option<Fadt> {
pub fn new(sdt: Sdt) -> Option<Fadt> {
if sdt.signature != *b"FACP" || sdt.length() < mem::size_of::<Fadt>() {
return None;
}
@@ -405,7 +429,7 @@ impl Fadt {
.take_single_sdt(*b"FACP")
.expect("expected ACPI to always have a FADT");
let fadt = match Fadt::new(context, fadt_sdt) {
let fadt = match Fadt::new(fadt_sdt) {
Some(fadt) => fadt,
None => {
log::error!("Failed to find FADT");
@@ -432,13 +456,9 @@ impl Fadt {
}
};
context.dsdt = Some(Dsdt(dsdt_sdt));
context.dsdt = Some(Dsdt(dsdt_sdt.clone()));
/*
let signature = get_sdt_signature(dsdt_sdt);
if let Some(ref mut ptrs) = *(SDT_POINTERS.write()) {
ptrs.insert(signature, dsdt_sdt);
}*/
context.tables.push(dsdt_sdt);
}
}
@@ -462,10 +482,17 @@ impl AmlContainingTable for PossibleAmlTables {
Self::Ssdt(ssdt) => ssdt.aml(),
}
}
fn header(&self) -> &SdtHeader {
match self {
Self::Dsdt(dsdt) => dsdt.header(),
Self::Ssdt(ssdt) => ssdt.header(),
}
}
}
pub trait AmlContainingTable {
fn aml(&self) -> &[u8];
fn header(&self) -> &SdtHeader;
}
impl<T> AmlContainingTable for &T
@@ -475,15 +502,24 @@ where
fn aml(&self) -> &[u8] {
T::aml(*self)
}
fn header(&self) -> &SdtHeader {
T::header(*self)
}
}
impl AmlContainingTable for Dsdt {
fn aml(&self) -> &[u8] {
self.0.data()
}
fn header(&self) -> &SdtHeader {
&*self.0
}
}
impl AmlContainingTable for Ssdt {
fn aml(&self) -> &[u8] {
self.0.data()
}
fn header(&self) -> &SdtHeader {
&*self.0
}
}
+10 -22
View File
@@ -49,34 +49,24 @@ pub fn parse_aml_with_scope(acpi_ctx: &AcpiContext, sdt: impl AmlContainingTable
Ok(ctx.namespace_delta)
}
pub fn is_aml_table(sdt: &SdtHeader) -> bool {
if &sdt.signature == b"DSDT" || &sdt.signature == b"SSDT" {
true
} else {
false
}
}
fn init_aml_table(acpi_ctx: &AcpiContext, sdt: impl AmlContainingTable) {
match parse_aml_table(acpi_ctx, sdt) {
Ok(_) => println!(": Parsed"),
Err(AmlError::AmlParseError(e)) => println!(": {}", e),
Err(AmlError::AmlInvalidOpCode) => println!(": Invalid opcode"),
Err(AmlError::AmlValueError) => println!(": Type constraints or value bounds not met"),
Err(AmlError::AmlDeferredLoad) => println!(": Deferred load reached top level"),
Err(AmlError::AmlFatalError(_, _, _)) => {
println!(": Fatal error occurred");
// TODO
match parse_aml_table(acpi_ctx, &sdt) {
Ok(_) => log::info!("Table {} parsed successfully", sdt.header().signature()),
Err(AmlError::AmlParseError(e)) => log::error!("Table {} got parse error: {}", sdt.header().signature(), e),
Err(AmlError::AmlInvalidOpCode) => log::error!("Table {} got invalid opcode", sdt.header().signature()),
Err(AmlError::AmlValueError) => log::error!("For table {}: type constraints or value bounds not met", sdt.header().signature()),
Err(AmlError::AmlDeferredLoad) => log::error!("For table {}: deferred load reached top level", sdt.header().signature()),
Err(AmlError::AmlFatalError(ty, code, val)) => {
log::error!("Fatal error occurred for table {}: type={}, code={}, val={:?}", sdt.header().signature(), ty, code, val);
return;
},
Err(AmlError::AmlHardFatal) => {
println!(": Fatal error occurred");
// TODO
log::error!("Hard fatal error occurred for table {}", sdt.header().signature());
return;
}
}
}
fn init_namespace(context: &AcpiContext) -> HashMap<String, AmlValue> {
pub fn init_namespace(context: &AcpiContext) {
let dsdt = context.dsdt().expect("could not find any DSDT");
log::info!("Found DSDT.");
@@ -88,8 +78,6 @@ fn init_namespace(context: &AcpiContext) -> HashMap<String, AmlValue> {
print!("Found SSDT.");
init_aml_table(context, ssdt);
}
todo!()
}
pub fn set_global_s_state(context: &AcpiContext, state: u8) {
+2 -1
View File
@@ -253,9 +253,10 @@ impl AmlValue {
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)
},
_ => Err(AmlError::AmlValueError)
_ => { log::error!("AmlValueError in get_as_ddb_handle other"); Err(AmlError::AmlValueError) }
}
}
+1
View File
@@ -10,6 +10,7 @@ use crate::acpi::AcpiContext;
pub type ParseResult = Result<AmlParseType, AmlError>;
pub type AmlParseType = AmlParseTypeGeneric<AmlValue>;
#[derive(Debug)]
pub struct AmlParseTypeGeneric<T> {
pub val: T,
pub len: usize
+9 -11
View File
@@ -1,5 +1,3 @@
use std::mem;
use super::AmlError;
use super::parser::{AmlParseType, ParseResult, AmlExecutionContext, ExecutionState};
use super::namespace::AmlValue;
@@ -9,8 +7,8 @@ use super::namestring::{parse_name_string, parse_super_name};
use crate::monotonic;
use crate::acpi::{PossibleAmlTables, SdtHeader};
use super::{parse_aml_table, is_aml_table};
use crate::acpi::PossibleAmlTables;
use super::parse_aml_table;
pub fn parse_type1_opcode(data: &[u8],
ctx: &mut AmlExecutionContext) -> ParseResult {
@@ -154,23 +152,23 @@ fn parse_def_load(data: &[u8],
let ddb_handle_object = parse_super_name(&data[2 + name.len..], ctx)?;
let tbl = ctx.get(ctx.acpi_context(), name.val)?.get_as_buffer(ctx.acpi_context())?;
// TODO
let sdt = plain::from_bytes::<SdtHeader>(&tbl[..mem::size_of::<SdtHeader>()]).unwrap();
let table = match ctx.acpi_context().sdt_from_signature(&sdt.signature()) {
Some(table) => table,
None => return Err(AmlError::AmlValueError),
};
let table = crate::acpi::Sdt::new(tbl.into()).map_err(|error| {
log::error!("Failed to parse def_load ACPI table: {}", error);
AmlError::AmlValueError
})?;
if let Some(aml_sdt) = PossibleAmlTables::try_new(table.clone()) {
ctx.acpi_context().new_index(&table.signature());
let delta = parse_aml_table(ctx.acpi_context(), aml_sdt)?;
let _ = ctx.modify(ctx.acpi_context(), ddb_handle_object.val, AmlValue::DDBHandle((delta, sdt.signature())));
let _ = ctx.modify(ctx.acpi_context(), ddb_handle_object.val, AmlValue::DDBHandle((delta, table.signature())));
Ok(AmlParseType {
val: AmlValue::None,
len: 2 + name.len + ddb_handle_object.len
})
} else {
log::error!("Loaded table is not for AML");
Err(AmlError::AmlValueError)
}
}
+4 -4
View File
@@ -1346,15 +1346,15 @@ fn parse_def_load_table(data: &[u8],
let parameter_data = parse_term_arg(&data[2 + signature.len + oem_id.len + oem_table_id.len + root_path.len + parameter_path.len..], ctx)?;
let signature = {
<[u8; 4]>::try_from(&*signature.val.get_as_buffer(ctx.acpi_context())?)
<[u8; 4]>::try_from(&*signature.val.get_as_string(ctx.acpi_context())?.as_bytes())
.expect("expected 'load table' def to have a signature that is 4 bytes long")
};
let oem_id = {
<[u8; 6]>::try_from(&*oem_id.val.get_as_buffer(ctx.acpi_context())?)
<[u8; 6]>::try_from(&*oem_id.val.get_as_string(ctx.acpi_context())?.as_bytes())
.expect("expected 'load table' def to have an OEM ID that is 6 bytes long")
};
let oem_table_id = {
<[u8; 8]>::try_from(&*oem_table_id.val.get_as_buffer(ctx.acpi_context())?)
<[u8; 8]>::try_from(&*oem_table_id.val.get_as_string(ctx.acpi_context())?.as_bytes())
.expect("expected 'load table' def to have an OEM table ID that is 8 bytes long")
};
@@ -1594,7 +1594,7 @@ fn parse_def_mid(data: &[u8],
let mut res = s.clone().split_off(idx);
if len < res.len() {
res.split_off(len);
res.truncate(len);
}
AmlValue::String(res)
+19 -9
View File
@@ -62,7 +62,7 @@ fn parse_hex_digit(hex: u8) -> Option<u8> {
let hex = hex.to_ascii_lowercase();
if hex >= b'a' && hex <= b'f' {
Some(hex - b'a')
Some(hex - b'a' + 10)
} else if hex >= b'0' && hex <= b'9' {
Some(hex - b'0')
} else {
@@ -71,7 +71,7 @@ fn parse_hex_digit(hex: u8) -> Option<u8> {
}
fn parse_hex_2digit(hex: &[u8]) -> Option<u8> {
parse_hex_digit(hex[0]).and_then(|least_significant| Some(least_significant | (parse_hex_digit(hex[1])? << 4)))
parse_hex_digit(hex[0]).and_then(|most_significant| Some((most_significant << 4) | parse_hex_digit(hex[1])?))
}
fn parse_oem_id(hex: [u8; 12]) -> Option<[u8; 6]> {
@@ -99,7 +99,7 @@ fn parse_oem_table_id(hex: [u8; 16]) -> Option<[u8; 8]> {
fn parse_table(table: &[u8]) -> Option<SdtSignature> {
let signature_part = table.get(..4)?;
let first_hyphen = table.get(5)?;
let first_hyphen = table.get(4)?;
let oem_id_part = table.get(5..17)?;
let second_hyphen = table.get(17)?;
let oem_table_part = table.get(18..34)?;
@@ -111,7 +111,7 @@ fn parse_table(table: &[u8]) -> Option<SdtSignature> {
return None;
}
if table.len() > 20 {
if table.len() > 34 {
return None;
}
@@ -139,7 +139,7 @@ impl SchemeMut for AcpiScheme<'_> {
let components = path.split('/').collect::<Vec<_>>();
let kind = match &*components {
[] => HandleKind::TopLevel,
[""] => HandleKind::TopLevel,
["tables"] => HandleKind::Tables,
["tables", table] => {
@@ -152,7 +152,7 @@ impl SchemeMut for AcpiScheme<'_> {
if kind.is_dir() && !flag_dir && !flag_stat {
return Err(Error::new(EISDIR));
} else if flag_dir && !flag_stat {
} else if !kind.is_dir() && flag_dir && !flag_stat {
return Err(Error::new(ENOTDIR));
}
@@ -191,6 +191,10 @@ impl SchemeMut for AcpiScheme<'_> {
fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result<isize> {
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
if handle.stat {
return Err(Error::new(EBADF));
}
let file_len = handle.kind.len(self.ctx)?;
let new_offset = match whence {
@@ -215,6 +219,10 @@ impl SchemeMut for AcpiScheme<'_> {
fn read(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
if handle.stat {
return Err(Error::new(EBADF));
}
let src_buf = match handle.kind {
HandleKind::TopLevel => TOPLEVEL_CONTENTS,
HandleKind::Table(ref signature) => self.ctx.sdt_from_signature(signature).ok_or(Error::new(EBADFD))?.as_slice(),
@@ -223,14 +231,14 @@ impl SchemeMut for AcpiScheme<'_> {
use std::io::prelude::*;
let tables_to_skip = handle.offset / TABLE_DENTRY_LENGTH;
let tables_to_fill = (buf.len() + TABLE_DENTRY_LENGTH - 1) / TABLE_DENTRY_LENGTH;
let max_tables_to_fill = (buf.len() + TABLE_DENTRY_LENGTH - 1) / TABLE_DENTRY_LENGTH;
let bytes_to_skip = handle.offset % TABLE_DENTRY_LENGTH;
let mut bytes_to_skip = handle.offset % TABLE_DENTRY_LENGTH;
let mut src_buf = [0_u8; TABLE_DENTRY_LENGTH];
let mut bytes_written = 0;
for table in self.ctx.tables().iter().skip(tables_to_skip).take(tables_to_fill) {
for table in self.ctx.tables().iter().skip(tables_to_skip).take(max_tables_to_fill) {
let mut cursor = std::io::Cursor::new(&mut src_buf[..]);
cursor.write_all(&table.signature).unwrap();
cursor.write_all(&[b'-']).unwrap();
@@ -242,12 +250,14 @@ impl SchemeMut for AcpiScheme<'_> {
for byte in table.oem_table_id.iter() {
write!(cursor, "{:>02X}", byte).unwrap();
}
cursor.write_all(&[b'\n']).unwrap();
let src_buf = &src_buf[bytes_to_skip..];
let dst_buf = &mut buf[bytes_written..];
let to_copy = std::cmp::min(src_buf.len(), dst_buf.len());
dst_buf[..to_copy].copy_from_slice(&src_buf[..to_copy]);
bytes_written += to_copy;
bytes_to_skip = 0;
}
handle.offset = handle.offset.checked_add(bytes_written).ok_or(Error::new(EOVERFLOW))?;