Skip to content

Commit 044480a

Browse files
committed
Handle DerefOf buffer fields
Allow DerefOf to read directly from BufferField objects. This matches AML patterns emitted by firmware that creates named fields over buffers and then uses DerefOf(field).
1 parent daf6df9 commit 044480a

8 files changed

Lines changed: 117 additions & 23 deletions

File tree

src/aml/mod.rs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -839,19 +839,17 @@ where
839839
}
840840
Opcode::DerefOf => {
841841
extract_args!(op => [Argument::Object(object)]);
842-
let result = match **object {
843-
Object::Reference { kind: _, inner: _ } => object.clone().unwrap_reference(),
844-
Object::String(_) => {
845-
let path = AmlName::from_str(&object.as_string().unwrap())?;
842+
let object = object.clone().unwrap_reference();
843+
let result = match &*object {
844+
Object::BufferField { .. } => object.read_buffer_field(self.integer_size)?.wrap(),
845+
Object::FieldUnit(field) => self.do_field_read(field)?,
846+
Object::String(path) => {
847+
let path = AmlName::from_str(path)?;
846848
let (_, object) = self.namespace.lock().search(&path, &context.current_scope)?;
847849
object.clone()
848850
}
849-
_ => {
850-
return Err(AmlError::ObjectNotOfExpectedType {
851-
expected: ObjectType::Reference,
852-
got: object.typ(),
853-
});
854-
}
851+
Object::Reference { .. } => unreachable!(),
852+
_ => object,
855853
};
856854
context.contribute_arg(Argument::Object(result));
857855
context.retire_op(op);
@@ -1675,7 +1673,7 @@ where
16751673
Opcode::FindSetLeftBit | Opcode::FindSetRightBit => {
16761674
context.start(OpInFlight::new(opcode, &[ResolveBehaviour::TermArg, ResolveBehaviour::Target]))
16771675
}
1678-
Opcode::DerefOf => context.start(OpInFlight::new(opcode, &[ResolveBehaviour::TermArg])),
1676+
Opcode::DerefOf => context.start(OpInFlight::new(opcode, &[ResolveBehaviour::SuperName])),
16791677
Opcode::ConcatRes => context.start(OpInFlight::new(
16801678
opcode,
16811679
&[ResolveBehaviour::TermArg, ResolveBehaviour::TermArg, ResolveBehaviour::Target],

src/aml/object.rs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -261,10 +261,16 @@ impl Object {
261261

262262
pub fn read_buffer_field(&self, integer_size: IntegerSize) -> Result<Object, AmlError> {
263263
if let Self::BufferField { buffer, offset, length } = self {
264-
let buffer = match **buffer {
265-
Object::Buffer(ref buffer) => buffer.as_slice(),
266-
Object::String(ref string) => string.as_bytes(),
267-
_ => panic!(),
264+
let buffer = buffer.clone().unwrap_transparent_reference();
265+
let buffer = match &*buffer {
266+
Object::Buffer(buffer) => buffer.as_slice(),
267+
Object::String(string) => string.as_bytes(),
268+
typ => {
269+
return Err(AmlError::InvalidOperationOnObject {
270+
op: Operation::ReadBufferField,
271+
typ: typ.typ(),
272+
});
273+
}
268274
};
269275
if *length <= integer_size as usize {
270276
let mut dst = [0u8; 8];
@@ -283,12 +289,18 @@ impl Object {
283289
pub fn write_buffer_field(&mut self, value: &[u8], token: &ObjectToken) -> Result<(), AmlError> {
284290
// TODO: bounds check the buffer first to avoid panicking
285291
if let Self::BufferField { buffer, offset, length } = self {
292+
let buffer = buffer.clone().unwrap_transparent_reference();
286293
let buffer = match unsafe { buffer.gain_mut(token) } {
287294
Object::Buffer(buffer) => buffer.as_mut_slice(),
288295
// XXX: this unfortunately requires us to trust AML to keep the string as valid
289296
// UTF8... maybe there is a better way?
290297
Object::String(string) => unsafe { string.as_bytes_mut() },
291-
_ => panic!(),
298+
typ => {
299+
return Err(AmlError::InvalidOperationOnObject {
300+
op: Operation::WriteBufferField,
301+
typ: typ.typ(),
302+
});
303+
}
292304
};
293305
copy_bits(value, 0, buffer, *offset, *length);
294306
Ok(())

tests/de_ref_of.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,72 @@ DefinitionBlock ("", "SSDT", 2, "RSACPI", "DerefOf", 0x00000002) {
2626
let handler = NullHandler {};
2727
test_infra::run_aml_test(AML, handler);
2828
}
29+
30+
#[test]
31+
fn test_deref_of_direct_buffer_field() {
32+
const AML: &str = r#"
33+
DefinitionBlock ("", "SSDT", 2, "RSACPI", "DerefOf", 0x00000002) {
34+
Name (ADAT, Buffer (0x01) { 0xaa })
35+
CreateByteField (ADAT, 0x00, BF00)
36+
37+
Method(MAIN, 0, NotSerialized) {
38+
Return (DerefOf(BF00) - 0xaa)
39+
}
40+
}
41+
"#;
42+
43+
let handler = NullHandler {};
44+
test_infra::run_aml_test(AML, handler);
45+
}
46+
47+
#[test]
48+
fn test_deref_of_local_buffer_field_after_store() {
49+
const AML: &str = r#"
50+
DefinitionBlock ("", "SSDT", 2, "RSACPI", "DerefOf", 0x00000002) {
51+
Method(MAIN, 0, NotSerialized) {
52+
Local0 = Buffer (0x01) { 0x00 }
53+
CreateByteField (Local0, 0x00, BF00)
54+
BF00 = 0xaa
55+
Return (DerefOf(BF00) - 0xaa)
56+
}
57+
}
58+
"#;
59+
60+
let handler = NullHandler {};
61+
test_infra::run_aml_test(AML, handler);
62+
}
63+
64+
#[test]
65+
fn test_deref_of_named_buffer_field_stores_value() {
66+
const AML: &str = r#"
67+
DefinitionBlock ("", "SSDT", 2, "RSACPI", "DerefOf", 0x00000002) {
68+
Name (ADAT, Buffer (0x01) { 0xaa })
69+
CreateByteField (ADAT, 0x00, BF00)
70+
71+
Method(MAIN, 0, NotSerialized) {
72+
Local0 = DerefOf(BF00)
73+
Return (Local0 - 0xaa)
74+
}
75+
}
76+
"#;
77+
78+
let handler = NullHandler {};
79+
test_infra::run_aml_test(AML, handler);
80+
}
81+
82+
#[test]
83+
fn test_deref_of_named_string_path() {
84+
const AML: &str = r#"
85+
DefinitionBlock ("", "SSDT", 2, "RSACPI", "DerefOf", 0x00000002) {
86+
Name (TGT, 0xaa)
87+
Name (STR, "\\TGT")
88+
89+
Method(MAIN, 0, NotSerialized) {
90+
Return (DerefOf(STR) - 0xaa)
91+
}
92+
}
93+
"#;
94+
95+
let handler = NullHandler {};
96+
test_infra::run_aml_test(AML, handler);
97+
}

tests/operation_region.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
use aml_test_tools::handlers::std_test_handler::{Command, construct_std_handler, create_mutex, read_u8, write_pci_u8, write_u8, read_pci_u8};
1+
use aml_test_tools::handlers::std_test_handler::{
2+
Command,
3+
construct_std_handler,
4+
create_mutex,
5+
read_pci_u8,
6+
read_u8,
7+
write_pci_u8,
8+
write_u8,
9+
};
210
use pci_types::PciAddress;
311

412
mod test_infra;

tests/test_infra/mod.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
use acpi::Handler;
2-
use aml_test_tools::{RunTestResult, TestResult, handlers::logging_handler::LoggingHandler, new_interpreter, run_test_for_string, run_test_for_opcodes};
2+
use aml_test_tools::{
3+
RunTestResult,
4+
TestResult,
5+
handlers::logging_handler::LoggingHandler,
6+
new_interpreter,
7+
run_test_for_opcodes,
8+
run_test_for_string,
9+
};
310

411
// The following two functions are very similar in structure, but whilst there are only two of them
512
// it's not worth adding complexity to make them DRY.

tests/uacpi_examples.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
1010
mod test_infra;
1111

12-
use aml_test_tools::{handlers::null_handler::NullHandler};
12+
use aml_test_tools::handlers::null_handler::NullHandler;
1313

1414
#[test]
1515
fn expressions_with_package() {

tools/aml_test_tools/src/handlers/check_cmd_handler.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,8 @@ where
271271

272272
#[cfg(test)]
273273
mod test {
274-
use crate::handlers::null_handler::NullHandler;
275274
use super::*;
275+
use crate::handlers::null_handler::NullHandler;
276276

277277
#[test]
278278
fn handler_basic_functions() {
@@ -322,4 +322,4 @@ mod test {
322322
let handler = CheckCommandHandler::new(test_commands, NullHandler {});
323323
handler.read_io_u8(2);
324324
}
325-
}
325+
}

tools/aml_test_tools/src/handlers/std_test_handler.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
//! Rather than defining a [`Handler`], this module defines useful functions to streamline the most-
22
//! used case of a [`CheckCommandHandler`] wrapping a [`ListedResponseHandler`].
33
4-
use pci_types::PciAddress;
54
use crate::handlers::{
65
check_cmd_handler::{AcpiCommands as Check, CheckCommandHandler},
76
listed_response_handler::{AcpiCommands as Response, ListedResponseHandler},
87
};
98
use acpi::{Handle, Handler};
9+
use pci_types::PciAddress;
1010

1111
/// Simplifies the construction of a standard test [`Handler`].
1212
///
@@ -162,4 +162,4 @@ pub const fn acquire(mutex: Handle, timeout: u16) -> Command {
162162
/// A simple helper to generate a [`Command`] for [`Handler::release`].
163163
pub const fn release(mutex: Handle) -> Command {
164164
(Check::Release(mutex), Response::Skip())
165-
}
165+
}

0 commit comments

Comments
 (0)