Skip to content

Commit 916d921

Browse files
committed
aml: (WIP) basic DefIndexField implementation
1 parent 301302e commit 916d921

File tree

5 files changed

+218
-7
lines changed

5 files changed

+218
-7
lines changed

aml/src/expression.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::{
44
opcode::{self, opcode},
55
parser::{choice, comment_scope, n_of, take, take_to_end_of_pkglength, try_with_context, Parser, Propagate},
66
pkg_length::pkg_length,
7-
term_object::{data_ref_object, term_arg, def_cond_ref_of},
7+
term_object::{data_ref_object, def_cond_ref_of, term_arg},
88
value::{AmlType, AmlValue, Args},
99
AmlError,
1010
DebugVerbosity,

aml/src/lib.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -334,8 +334,17 @@ impl AmlContext {
334334
match self.namespace.get(handle).unwrap().type_of() {
335335
AmlType::FieldUnit => {
336336
let mut field = self.namespace.get(handle).unwrap().clone();
337-
field.write_field(value, self)?;
338-
field.read_field(self)
337+
match field {
338+
AmlValue::Field { .. } => {
339+
field.write_field(value, self)?;
340+
field.read_field(self)
341+
}
342+
AmlValue::IndexField { .. } => {
343+
field.write_index_field(value, self)?;
344+
field.read_index_field(self)
345+
}
346+
_ => unreachable!(),
347+
}
339348
}
340349
AmlType::BufferField => {
341350
let mut buffer_field = self.namespace.get(handle).unwrap().clone();

aml/src/opcode.rs

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ pub const EXT_DEF_DEVICE_OP: u8 = 0x82;
4343
pub const EXT_DEF_PROCESSOR_OP: u8 = 0x83;
4444
pub const EXT_DEF_POWER_RES_OP: u8 = 0x84;
4545
pub const EXT_DEF_THERMAL_ZONE_OP: u8 = 0x85;
46+
pub const EXT_DEF_INDEX_FIELD_OP: u8 = 0x86;
4647

4748
/*
4849
* Type 1 opcodes

aml/src/term_object.rs

+96-3
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use crate::{
1717
Parser,
1818
Propagate,
1919
},
20-
pkg_length::{pkg_length, PkgLength},
20+
pkg_length::{pkg_length, raw_pkg_length, PkgLength},
2121
statement::statement_opcode,
2222
value::{AmlValue, FieldFlags, MethodCode, MethodFlags, RegionSpace},
2323
AmlContext,
@@ -110,7 +110,8 @@ where
110110
def_processor(),
111111
def_power_res(),
112112
def_thermal_zone(),
113-
def_mutex()
113+
def_mutex(),
114+
def_index_field()
114115
),
115116
)
116117
}
@@ -868,7 +869,7 @@ where
868869
if let Ok((_name, _handle)) = handle {
869870
match target {
870871
Target::Null => { /* just return the result of the check */ }
871-
_ => {return (Err(Propagate::Err(AmlError::Unimplemented)), context) },
872+
_ => return (Err(Propagate::Err(AmlError::Unimplemented)), context),
872873
}
873874
}
874875
(Ok(result), context)
@@ -877,6 +878,98 @@ where
877878
.map(|((), result)| Ok(result))
878879
}
879880

881+
fn index_field_element<'a, 'c>(
882+
index_handle: AmlHandle,
883+
data_handle: AmlHandle,
884+
flags: FieldFlags,
885+
current_offset: u64,
886+
) -> impl Parser<'a, 'c, u64>
887+
where
888+
'c: 'a,
889+
{
890+
/*
891+
* Reserved fields shouldn't actually be added to the namespace; they seem to show gaps in
892+
* the operation region that aren't used for anything.
893+
*
894+
* NOTE: had to use raw_pkg_length() instead of pkg_length() here because pkg_length() performs
895+
* checks against aml code slice, and in this specific context the check should be
896+
* performed against the parent field's size
897+
*/
898+
let reserved_field =
899+
opcode(opcode::RESERVED_FIELD).then(raw_pkg_length()).map(|((), length)| Ok(length as u64));
900+
901+
let named_field = name_seg().then(pkg_length()).map_with_context(move |(name_seg, length), context| {
902+
try_with_context!(
903+
context,
904+
context.namespace.add_value_at_resolved_path(
905+
AmlName::from_name_seg(name_seg),
906+
&context.current_scope,
907+
AmlValue::IndexField {
908+
index: index_handle,
909+
data: data_handle,
910+
flags,
911+
offset: current_offset,
912+
length: length.raw_length as u64,
913+
}
914+
)
915+
);
916+
917+
(Ok(length.raw_length as u64), context)
918+
});
919+
920+
choice!(reserved_field, named_field)
921+
}
922+
923+
pub fn def_index_field<'a, 'c>() -> impl Parser<'a, 'c, ()>
924+
where
925+
'c: 'a,
926+
{
927+
/*
928+
* DefIndexField := IndexFieldOp PkgLength NameString NameString FieldFlags FieldList
929+
* IndexFieldOp := ExtOpPrefix 0x86
930+
*/
931+
// Declare a group of field that must be accessed by writing to an index
932+
// register and then reading/writing from a data register.
933+
ext_opcode(opcode::EXT_DEF_INDEX_FIELD_OP)
934+
.then(comment_scope(
935+
DebugVerbosity::Scopes,
936+
"DefIndexField",
937+
pkg_length()
938+
.then(name_string())
939+
.then(name_string())
940+
.then(take())
941+
.map_with_context(|(((list_length, index_name), data_name), flags), context| {
942+
let (_, index_handle) =
943+
try_with_context!(context, context.namespace.search(&index_name, &context.current_scope));
944+
let (_, data_handle) =
945+
try_with_context!(context, context.namespace.search(&data_name, &context.current_scope));
946+
947+
(Ok((list_length, index_handle, data_handle, flags)), context)
948+
})
949+
.feed(|(list_length, index_handle, data_handle, flags)| {
950+
move |mut input: &'a [u8], mut context: &'c mut AmlContext| -> ParseResult<'a, 'c, ()> {
951+
let mut current_offset = 0;
952+
while list_length.still_parsing(input) {
953+
let (new_input, new_context, field_length) = index_field_element(
954+
index_handle,
955+
data_handle,
956+
FieldFlags::new(flags),
957+
current_offset,
958+
)
959+
.parse(input, context)?;
960+
961+
input = new_input;
962+
context = new_context;
963+
current_offset += field_length;
964+
}
965+
966+
Ok((input, context, ()))
967+
}
968+
}),
969+
))
970+
.discard_result()
971+
}
972+
880973
pub fn term_arg<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
881974
where
882975
'c: 'a,

aml/src/value.rs

+109-1
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,13 @@ pub enum AmlValue {
193193
offset: u64,
194194
length: u64,
195195
},
196+
IndexField {
197+
index: AmlHandle,
198+
data: AmlHandle,
199+
flags: FieldFlags,
200+
offset: u64,
201+
length: u64,
202+
},
196203
Device,
197204
Method {
198205
flags: MethodFlags,
@@ -250,7 +257,7 @@ impl AmlValue {
250257
AmlValue::Integer(_) => AmlType::Integer,
251258
AmlValue::String(_) => AmlType::String,
252259
AmlValue::OpRegion { .. } => AmlType::OpRegion,
253-
AmlValue::Field { .. } => AmlType::FieldUnit,
260+
AmlValue::Field { .. } | AmlValue::IndexField { .. } => AmlType::FieldUnit,
254261
AmlValue::Device => AmlType::Device,
255262
AmlValue::Method { .. } => AmlType::Method,
256263
AmlValue::Buffer(_) => AmlType::Buffer,
@@ -297,6 +304,8 @@ impl AmlValue {
297304
* `as_integer` on the result.
298305
*/
299306
AmlValue::Field { .. } => self.read_field(context)?.as_integer(context),
307+
// TODO: IndexField cannot be accessed through an immutable &AmlContext
308+
AmlValue::IndexField { .. } => todo!(),
300309
AmlValue::BufferField { .. } => self.read_buffer_field(context)?.as_integer(context),
301310

302311
_ => Err(AmlError::IncompatibleValueConversion { current: self.type_of(), target: AmlType::Integer }),
@@ -308,6 +317,8 @@ impl AmlValue {
308317
AmlValue::Buffer(ref bytes) => Ok(bytes.clone()),
309318
// TODO: implement conversion of String and Integer to Buffer
310319
AmlValue::Field { .. } => self.read_field(context)?.as_buffer(context),
320+
// TODO: IndexField cannot be accessed through an immutable &AmlContext
321+
AmlValue::IndexField { .. } => todo!(),
311322
AmlValue::BufferField { .. } => self.read_buffer_field(context)?.as_buffer(context),
312323
_ => Err(AmlError::IncompatibleValueConversion { current: self.type_of(), target: AmlType::Buffer }),
313324
}
@@ -318,6 +329,8 @@ impl AmlValue {
318329
AmlValue::String(ref string) => Ok(string.clone()),
319330
// TODO: implement conversion of Buffer to String
320331
AmlValue::Field { .. } => self.read_field(context)?.as_string(context),
332+
// TODO: IndexField cannot be accessed through an immutable &AmlContext
333+
AmlValue::IndexField { .. } => todo!(),
321334
_ => Err(AmlError::IncompatibleValueConversion { current: self.type_of(), target: AmlType::String }),
322335
}
323336
}
@@ -404,6 +417,101 @@ impl AmlValue {
404417
}
405418
}
406419

420+
/// Stores an IndexField's index (as specified by its offset) and returns the bit offset within
421+
/// the Data part of the field
422+
fn write_index(
423+
&mut self,
424+
index_flags: &FieldFlags,
425+
offset: u64,
426+
length: u64,
427+
context: &mut AmlContext,
428+
) -> Result<usize, AmlError> {
429+
let index_align = match index_flags.access_type()? {
430+
FieldAccessType::Any => 8,
431+
FieldAccessType::Byte => 8,
432+
FieldAccessType::Word => 16,
433+
FieldAccessType::DWord => 32,
434+
FieldAccessType::QWord => 64,
435+
FieldAccessType::Buffer => 8,
436+
};
437+
438+
// Value to write to the Index part of the field
439+
let length = length as usize;
440+
let index_value = (offset / 8) & !((index_align >> 3) - 1);
441+
let bit_offset = (offset - index_value * 8) as usize;
442+
443+
// TODO handle cases when access_type/offset/length combinations lead to crossing of index
444+
// boundary
445+
if (bit_offset + length - 1) / index_align as usize != 0 {
446+
todo!(
447+
"IndexField access crosses the index boundary (range: {:#x?}, access type: {} bits)",
448+
bit_offset..(bit_offset + length),
449+
index_align
450+
);
451+
}
452+
453+
// Write the desired index
454+
// NOTE not sure if the spec says the index field can only be an integer one, but I can't
455+
// think of any reason for it to be anything else
456+
self.write_field(AmlValue::Integer(index_value), context)?;
457+
458+
Ok(bit_offset)
459+
}
460+
461+
/// Reads from an IndexField, returning either an `Integer` or a `Buffer` depending on the
462+
/// field size
463+
pub fn read_index_field(&self, context: &mut AmlContext) -> Result<AmlValue, AmlError> {
464+
let AmlValue::IndexField { index, data, flags, offset, length } = self else {
465+
return Err(AmlError::IncompatibleValueConversion {
466+
current: self.type_of(),
467+
target: AmlType::FieldUnit,
468+
});
469+
};
470+
471+
let mut index_field = context.namespace.get_mut(*index)?.clone();
472+
let data_field = context.namespace.get_mut(*data)?.clone();
473+
474+
// Write the Index part of the field
475+
let bit_offset = index_field.write_index(flags, *offset, *length, context)?;
476+
477+
// TODO buffer field accesses
478+
479+
// Read the value of the Data field
480+
let field_value = data_field.read_field(context)?.as_integer(context)?;
481+
let value = field_value.get_bits(bit_offset..(bit_offset + *length as usize));
482+
483+
Ok(AmlValue::Integer(value))
484+
}
485+
486+
pub fn write_index_field(&self, value: AmlValue, context: &mut AmlContext) -> Result<(), AmlError> {
487+
let AmlValue::IndexField { index, data, flags, offset, length } = self else {
488+
return Err(AmlError::IncompatibleValueConversion {
489+
current: self.type_of(),
490+
target: AmlType::FieldUnit,
491+
});
492+
};
493+
494+
let mut index_field = context.namespace.get_mut(*index)?.clone();
495+
let mut data_field = context.namespace.get_mut(*data)?.clone();
496+
497+
// Write the Index part of the field
498+
let bit_offset = index_field.write_index(flags, *offset, *length, context)?;
499+
500+
// TODO handle field update rule properly
501+
// TODO buffer field accesses
502+
503+
// Read the old value of the Data field (to preserve bits we're not interested in)
504+
let mut field_value = data_field.read_field(context)?.as_integer(context)?;
505+
506+
// Modify the bits
507+
field_value.set_bits(bit_offset..(bit_offset + *length as usize), value.as_integer(context)?);
508+
509+
// Write the Data field back
510+
data_field.write_field(AmlValue::Integer(field_value), context)?;
511+
512+
Ok(())
513+
}
514+
407515
/// Reads from a field of an opregion, returning either a `AmlValue::Integer` or an `AmlValue::Buffer`,
408516
/// depending on the size of the field.
409517
pub fn read_field(&self, context: &AmlContext) -> Result<AmlValue, AmlError> {

0 commit comments

Comments
 (0)