Skip to content

Commit 19a4c5c

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 19a4c5c

3 files changed

Lines changed: 53 additions & 6 deletions

File tree

src/aml/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,7 @@ where
841841
extract_args!(op => [Argument::Object(object)]);
842842
let result = match **object {
843843
Object::Reference { kind: _, inner: _ } => object.clone().unwrap_reference(),
844+
Object::BufferField { .. } => object.read_buffer_field(self.integer_size)?.wrap(),
844845
Object::String(_) => {
845846
let path = AmlName::from_str(&object.as_string().unwrap())?;
846847
let (_, object) = self.namespace.lock().search(&path, &context.current_scope)?;
@@ -1675,7 +1676,7 @@ where
16751676
Opcode::FindSetLeftBit | Opcode::FindSetRightBit => {
16761677
context.start(OpInFlight::new(opcode, &[ResolveBehaviour::TermArg, ResolveBehaviour::Target]))
16771678
}
1678-
Opcode::DerefOf => context.start(OpInFlight::new(opcode, &[ResolveBehaviour::TermArg])),
1679+
Opcode::DerefOf => context.start(OpInFlight::new(opcode, &[ResolveBehaviour::SuperName])),
16791680
Opcode::ConcatRes => context.start(OpInFlight::new(
16801681
opcode,
16811682
&[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: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,37 @@ 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+
}

0 commit comments

Comments
 (0)