Skip to content

Commit

Permalink
Merge pull request #114 from Amjad50/aml_display
Browse files Browse the repository at this point in the history
Improve displaying AML code using `fmt::Display` and Added more AML parsing
  • Loading branch information
Amjad50 authored Jul 16, 2024
2 parents 127cec5 + 55a0c66 commit b4aa087
Show file tree
Hide file tree
Showing 9 changed files with 2,540 additions and 775 deletions.
8 changes: 6 additions & 2 deletions book/src/kernel/acpi/aml.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@

This is an `AML` parser that is able to parse the code inside the `DSDT` and `SSDT` tables.

Currently, we do not use the parsed code, as we need to build an interpreter for it, so that we can emulate executing it
and get the data we need.
We have 2 forms of the parsed `AML`.
- **Normal:** This is what we get from the table, we just parse it directly
- **Structured:** After getting the `Normal` version, we do some processing to order them and group them by `Scope`
so that we can easily search for a given label.

Any of these can be printed by the cmdline `log_aml` being `normal` or `structured` (See [Cmdline](../boot/cmdline.md))

## Why this is needed?

Expand Down
210 changes: 210 additions & 0 deletions kernel/src/acpi/aml/display.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
use core::{
cell::RefCell,
fmt::{self, Write},
};

#[derive(Default)]
struct PadAdapterState {
on_newline: bool,
}

struct PadAdapter<'buf, 'state> {
buf: &'buf mut (dyn fmt::Write + 'buf),
state: &'state mut PadAdapterState,
}

impl<'buf, 'state> PadAdapter<'buf, 'state> {
pub fn wrap(buf: &'buf mut dyn fmt::Write, state: &'state mut PadAdapterState) -> Self {
Self { buf, state }
}
}

impl fmt::Write for PadAdapter<'_, '_> {
fn write_str(&mut self, s: &str) -> fmt::Result {
for s in s.split_inclusive('\n') {
if self.state.on_newline {
self.buf.write_str(" ")?;
}

self.state.on_newline = s.ends_with('\n');
self.buf.write_str(s)?;
}

Ok(())
}

fn write_char(&mut self, c: char) -> fmt::Result {
if self.state.on_newline {
self.buf.write_str(" ")?;
}
self.state.on_newline = c == '\n';
self.buf.write_char(c)
}
}

struct FmtHolder<F>
where
F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result,
{
f: RefCell<Option<F>>,
}

impl<F> FmtHolder<F>
where
F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result,
{
fn new(value_fmt: F) -> Self {
Self {
f: RefCell::new(Some(value_fmt)),
}
}
}

impl<F> fmt::Display for FmtHolder<F>
where
F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(self.f.borrow_mut().take().unwrap())(f)
}
}

pub struct AmlDisplayer<'a, 'b: 'a> {
fmt: &'a mut fmt::Formatter<'b>,
result: fmt::Result,
in_paren_arg: bool,
already_in_paren_arg: bool,
already_in_body: bool,
in_body: bool,
is_list: bool,
}

impl<'a, 'b: 'a> AmlDisplayer<'a, 'b> {
pub fn start(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> Self {
let result = fmt.write_str(name);
Self {
fmt,
result,
in_paren_arg: false,
already_in_paren_arg: false,
in_body: false,
is_list: false,
already_in_body: false,
}
}

pub fn set_list(&mut self, value: bool) -> &mut Self {
self.is_list = value;
self
}

pub fn paren_arg<F>(&mut self, value_fmt: F) -> &mut Self
where
F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result,
{
if !self.in_paren_arg && self.already_in_paren_arg {
self.result = Err(fmt::Error);
}

self.result = self.result.and_then(|_| {
let prefix = if self.in_paren_arg { ", " } else { " (" };

self.fmt.write_str(prefix)?;
value_fmt(self.fmt)
});

self.in_paren_arg = true;
self.already_in_paren_arg = true;

self
}

pub fn finish_paren_arg(&mut self) -> &mut Self {
if self.in_paren_arg {
self.result = self.result.and_then(|_| self.fmt.write_str(")"));
self.in_paren_arg = false;
}
self
}

pub fn body_field<F>(&mut self, value_fmt: F) -> &mut Self
where
F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result,
{
self.finish_paren_arg();

self.result = self.result.and_then(|_| {
if self.fmt.alternate() {
if !self.in_body {
self.fmt.write_str(" {\n")?;
} else {
self.fmt
.write_str(if self.is_list { ",\n" } else { "\n" })?;
}

let mut state = PadAdapterState { on_newline: true };
let mut writer = PadAdapter::wrap(self.fmt, &mut state);
let fmt_holder = FmtHolder::new(value_fmt);

writer.write_fmt(format_args!("{:#}", fmt_holder))
} else {
let prefix = if self.in_body {
if self.is_list {
", "
} else {
"; "
}
} else {
" { "
};

self.fmt.write_str(prefix)?;
value_fmt(self.fmt)
}
});

self.in_body = true;
self.already_in_body = true;

self
}

pub fn at_least_empty_paren_arg(&mut self) -> &mut Self {
if !self.in_paren_arg && !self.already_in_paren_arg {
self.result = self.result.and_then(|_| self.fmt.write_str(" ()"));
}
self
}

pub fn at_least_empty_body(&mut self) -> &mut Self {
if !self.in_body && !self.already_in_body {
self.result = self.result.and_then(|_| self.fmt.write_str("{ }"));
}
self
}

pub fn finish(&mut self) -> fmt::Result {
self.finish_paren_arg();

if self.in_body {
self.result = self.result.and_then(|_| {
if !self.fmt.alternate() {
self.fmt.write_str(" }")
} else {
self.fmt.write_str("\n}")
}
});
self.in_body = false;
}

self.result
}
}

pub struct HexHolder<'a, T: fmt::UpperHex>(pub &'a T);

impl<T: fmt::UpperHex> fmt::Display for HexHolder<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:#X}", self.0)
}
}
18 changes: 12 additions & 6 deletions kernel/src/acpi/aml/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{
};

use super::{
parser::{IntegerData, TermArg, UnresolvedDataObject},
parser::{resource_template::ResourceTemplate, IntegerData, TermArg, UnresolvedDataObject},
structured::{StructuredAml, StructuredAmlError},
};

Expand Down Expand Up @@ -39,6 +39,7 @@ impl Package {
#[derive(Debug, Clone)]
pub enum DataObject {
Integer(IntegerData),
ResourceTemplate(ResourceTemplate),
Buffer(IntegerData, Vec<u8>),
Package(Package),
String(String),
Expand Down Expand Up @@ -99,7 +100,6 @@ impl ExecutionContext {
ElementType::PowerResource(_)
| ElementType::RegionFields(_, _)
| ElementType::IndexField(_)
| ElementType::Mutex(_)
| ElementType::ScopeOrDevice(_)
| ElementType::Processor(_) => {
return Err(AmlExecutionError::ElementNotExecutable(label.to_string()))
Expand Down Expand Up @@ -141,20 +141,26 @@ impl ExecutionContext {
reference_path: &str,
) -> Result<DataObject, AmlExecutionError> {
match data {
UnresolvedDataObject::Buffer(term, data) => {
let size_term = self.execute_term_arg(term.as_ref(), reference_path)?;
UnresolvedDataObject::Buffer(buffer) => {
let size_term = self.execute_term_arg(buffer.size.as_ref(), reference_path)?;

let size_term = match size_term {
DataObject::Integer(i) => i,
_ => {
return Err(AmlExecutionError::UnexpectedTermResultType(
term.as_ref().clone(),
buffer.size.as_ref().clone(),
"Integer".to_string(),
))
}
};

Ok(DataObject::Buffer(size_term, data.into_iter().collect()))
Ok(DataObject::Buffer(
size_term,
buffer.data.into_iter().collect(),
))
}
UnresolvedDataObject::ResourceTemplate(template) => {
Ok(DataObject::ResourceTemplate(template))
}
UnresolvedDataObject::Package(size, elements) => Ok(DataObject::Package(Package {
size: IntegerData::ByteConst(size),
Expand Down
1 change: 1 addition & 0 deletions kernel/src/acpi/aml/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod display;
pub mod execution;
mod parser;
mod structured;
Expand Down
Loading

0 comments on commit b4aa087

Please sign in to comment.