|
1 |
| -use crate::op_region::OpRegion; |
| 1 | +use crate::{AmlError, op_region::OpRegion}; |
2 | 2 | use alloc::{sync::Arc, vec::Vec};
|
3 | 3 | use bit_field::BitField;
|
4 | 4 |
|
@@ -43,6 +43,27 @@ impl Object {
|
43 | 43 | }
|
44 | 44 | }
|
45 | 45 |
|
| 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 | + |
46 | 67 | /// Returns the `ObjectType` of this object. Returns the type of the referenced object in the
|
47 | 68 | /// case of `Object::Reference`.
|
48 | 69 | pub fn typ(&self) -> ObjectType {
|
@@ -112,3 +133,56 @@ pub enum ObjectType {
|
112 | 133 | String,
|
113 | 134 | ThermalZone,
|
114 | 135 | }
|
| 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