Successfully parse the namespace.
This commit is contained in:
+53
-17
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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))?;
|
||||
|
||||
Reference in New Issue
Block a user