Skip to content

Commit db0362f

Browse files
committed
aml: support reads from and writes to buffer fields
1 parent a56959e commit db0362f

File tree

2 files changed

+106
-3
lines changed

2 files changed

+106
-3
lines changed

aml/src/lib.rs

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -744,8 +744,35 @@ impl Interpreter {
744744
// TODO: write the object to the destination, including e.g. field writes that then lead to
745745
// literally god knows what.
746746
match target {
747-
Argument::Object(_) => {}
747+
Argument::Object(target) => match target.gain_mut() {
748+
Object::Integer(target) => match object.gain_mut() {
749+
Object::Integer(value) => {
750+
*target = *value;
751+
}
752+
Object::BufferField { .. } => {
753+
let mut buffer = [0u8; 8];
754+
object.gain_mut().read_buffer_field(&mut buffer)?;
755+
let value = u64::from_le_bytes(buffer);
756+
*target = value;
757+
}
758+
_ => panic!(),
759+
},
760+
Object::BufferField { .. } => match object.gain_mut() {
761+
Object::Integer(value) => {
762+
target.gain_mut().write_buffer_field(&value.to_le_bytes())?;
763+
}
764+
Object::Buffer(value) => {
765+
target.gain_mut().write_buffer_field(&value.as_slice())?;
766+
}
767+
_ => panic!(),
768+
},
769+
_ => panic!("Stores to objects like {:?} are not yet supported", target),
770+
},
748771
Argument::Namestring(_) => {}
772+
Argument::UnresolvedObjectPath(_) => {
773+
// TODO: do we need to attempt to allow this somehow??
774+
todo!("Is this allowed here?");
775+
}
749776

750777
Argument::ByteData(_) | Argument::TrackedPc(_) | Argument::PkgLength(_) => panic!(),
751778
}
@@ -804,7 +831,7 @@ impl Block {
804831
}
805832
}
806833

807-
#[derive(Debug)]
834+
#[derive(PartialEq, Debug)]
808835
pub enum BlockKind {
809836
Table,
810837
Method,
@@ -1284,6 +1311,8 @@ pub enum AmlError {
12841311
NoCurrentOp,
12851312

12861313
MethodArgCountIncorrect,
1314+
1315+
InvalidOperationOnObject,
12871316
}
12881317

12891318
/// This trait represents the interface from the `Interpreter` to the hosting kernel, and allows

aml/src/object.rs

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::op_region::OpRegion;
1+
use crate::{AmlError, op_region::OpRegion};
22
use alloc::{sync::Arc, vec::Vec};
33
use bit_field::BitField;
44

@@ -43,6 +43,27 @@ impl Object {
4343
}
4444
}
4545

46+
pub fn read_buffer_field(&self, dst: &mut [u8]) -> Result<(), AmlError> {
47+
if let Self::BufferField { buffer, offset, length } = self {
48+
let Object::Buffer(ref buffer) = **buffer else { panic!() };
49+
// TODO: assert length of buffer is sufficient
50+
copy_bits(buffer.as_slice(), *offset, dst, 0, *length);
51+
Ok(())
52+
} else {
53+
Err(AmlError::InvalidOperationOnObject)
54+
}
55+
}
56+
57+
pub fn write_buffer_field(&mut self, value: &[u8]) -> Result<(), AmlError> {
58+
if let Self::BufferField { buffer, offset, length } = self {
59+
let Object::Buffer(buffer) = buffer.gain_mut() else { panic!() };
60+
copy_bits(value, 0, buffer.as_mut_slice(), *offset, *length);
61+
Ok(())
62+
} else {
63+
Err(AmlError::InvalidOperationOnObject)
64+
}
65+
}
66+
4667
/// Returns the `ObjectType` of this object. Returns the type of the referenced object in the
4768
/// case of `Object::Reference`.
4869
pub fn typ(&self) -> ObjectType {
@@ -112,3 +133,56 @@ pub enum ObjectType {
112133
String,
113134
ThermalZone,
114135
}
136+
137+
/// Copy an arbitrary bit range of `src` to an arbitrary bit range of `dst`. This is used for
138+
/// buffer fields. Data is zero-extended if `src` does not cover `length` bits, matching the
139+
/// expected behaviour for buffer fields.
140+
fn copy_bits(src: &[u8], mut src_index: usize, dst: &mut [u8], mut dst_index: usize, mut length: usize) {
141+
while length > 0 {
142+
let src_shift = src_index & 7;
143+
let mut src_bits = src.get(src_index / 8).unwrap_or(&0x00) >> src_shift;
144+
if src_shift > 0 && length > (8 - src_shift) {
145+
src_bits |= src.get(src_index / 8 + 1).unwrap_or(&0x00) << (8 - src_shift);
146+
}
147+
148+
if length < 8 {
149+
src_bits &= (1 << length) - 1;
150+
}
151+
152+
let dst_shift = dst_index & 7;
153+
let mut dst_mask: u16 = if length < 8 { ((1 << length) - 1) as u16 } else { 0xff as u16 } << dst_shift;
154+
dst[dst_index / 8] =
155+
(dst[dst_index / 8] & !(dst_mask as u8)) | ((src_bits << dst_shift) & (dst_mask as u8));
156+
157+
if dst_shift > 0 && length > (8 - dst_shift) {
158+
dst_mask >>= 8;
159+
dst[dst_index / 8 + 1] &= !(dst_mask as u8);
160+
dst[dst_index / 8 + 1] |= (src_bits >> (8 - dst_shift)) & (dst_mask as u8);
161+
}
162+
163+
if length < 8 {
164+
length = 0;
165+
} else {
166+
length -= 8;
167+
src_index += 8;
168+
dst_index += 8;
169+
}
170+
}
171+
}
172+
173+
#[cfg(test)]
174+
mod tests {
175+
use super::*;
176+
177+
#[test]
178+
fn test_copy_bits() {
179+
let src = [0b1011_1111, 0b1111_0111, 0b1111_1111, 0b1111_1111, 0b1111_1111];
180+
let mut dst = [0b1110_0001, 0, 0, 0, 0];
181+
182+
copy_bits(&src, 0, &mut dst, 2, 15);
183+
for i in 0..dst.len() {
184+
print!("{:08b} ", dst[i]);
185+
}
186+
assert_eq!(dst, [0b1111_1101, 0b1101_1110, 0b0000_0001, 0b0000_0000, 0b0000_0000]);
187+
}
188+
}

0 commit comments

Comments
 (0)