Skip to content

Commit b2a5f4a

Browse files
alnyanIsaacWoods
authored andcommitted
AML: Implement OpReg-relative PkgLength parser
1 parent 9d2fa98 commit b2a5f4a

File tree

3 files changed

+94
-20
lines changed

3 files changed

+94
-20
lines changed

aml/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,11 @@ pub enum AmlError {
706706
MalformedStream,
707707
InvalidNameSeg,
708708
InvalidPkgLength,
709+
/// Invalid PkgLength relative to an OperationRegion
710+
InvalidRegionPkgLength {
711+
region_bit_length: u64,
712+
raw_length: u32,
713+
},
709714
InvalidFieldFlags,
710715
UnterminatedStringConstant,
711716
InvalidStringConstant,

aml/src/pkg_length.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,23 @@ use crate::{
22
parser::{take, take_n, Parser, Propagate},
33
AmlContext,
44
AmlError,
5+
AmlHandle,
6+
AmlValue,
57
};
68
use bit_field::BitField;
79

10+
/*
11+
* There are two types of PkgLength implemented: PkgLength and RegionPkgLength. The reason for this
12+
* is that while both are parsed as PkgLength op, they might have different meanings in different
13+
* contexts:
14+
*
15+
* - PkgLength refers to an offset within the AML input slice
16+
* - RegionPkgLength refers to an offset within an operation region (and is used this way in parsers
17+
* like def_field())
18+
*
19+
* They both have identical fields, but the fields themselves have an entirely different meaning.
20+
*/
21+
822
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
923
pub struct PkgLength {
1024
pub raw_length: u32,
@@ -14,6 +28,12 @@ pub struct PkgLength {
1428
pub end_offset: u32,
1529
}
1630

31+
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
32+
pub struct RegionPkgLength {
33+
pub raw_length: u32,
34+
pub end_offset: u32,
35+
}
36+
1737
impl PkgLength {
1838
pub fn from_raw_length(stream: &[u8], raw_length: u32) -> Result<PkgLength, AmlError> {
1939
Ok(PkgLength {
@@ -29,6 +49,48 @@ impl PkgLength {
2949
}
3050
}
3151

52+
impl RegionPkgLength {
53+
pub fn from_raw_length(region_bit_length: u64, raw_length: u32) -> Result<RegionPkgLength, AmlError> {
54+
Ok(RegionPkgLength {
55+
raw_length,
56+
end_offset: (region_bit_length as u32)
57+
.checked_sub(raw_length)
58+
.ok_or(AmlError::InvalidRegionPkgLength { region_bit_length, raw_length })?,
59+
})
60+
}
61+
}
62+
63+
pub fn region_pkg_length<'a, 'c>(region_handle: AmlHandle) -> impl Parser<'a, 'c, RegionPkgLength>
64+
where
65+
'c: 'a,
66+
{
67+
move |input: &'a [u8], context: &'c mut AmlContext| -> crate::parser::ParseResult<'a, 'c, RegionPkgLength> {
68+
let region_value = match context.namespace.get(region_handle) {
69+
Ok(value) => value,
70+
Err(err) => return Err((input, context, Propagate::Err(err))),
71+
};
72+
73+
/*
74+
* OperationRegion length is in bytes, PkgLength is in bits, so conversion is needed
75+
*/
76+
let region_bit_length = match region_value {
77+
AmlValue::OpRegion { length, .. } => *length * 8,
78+
_ => return Err((input, context, Propagate::Err(AmlError::FieldRegionIsNotOpRegion))),
79+
};
80+
81+
let (new_input, context, raw_length) = raw_pkg_length().parse(input, context)?;
82+
83+
/*
84+
* NOTE: we use the original input here, because `raw_length` includes the length of the
85+
* `PkgLength`.
86+
*/
87+
match RegionPkgLength::from_raw_length(region_bit_length, raw_length) {
88+
Ok(pkg_length) => Ok((new_input, context, pkg_length)),
89+
Err(err) => Err((input, context, Propagate::Err(err))),
90+
}
91+
}
92+
}
93+
3294
pub fn pkg_length<'a, 'c>() -> impl Parser<'a, 'c, PkgLength>
3395
where
3496
'c: 'a,

aml/src/term_object.rs

Lines changed: 27 additions & 20 deletions
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, region_pkg_length, PkgLength},
2121
statement::statement_opcode,
2222
value::{AmlValue, FieldFlags, MethodCode, MethodFlags, RegionSpace},
2323
AmlContext,
@@ -561,32 +561,39 @@ where
561561
* Reserved fields shouldn't actually be added to the namespace; they seem to show gaps in
562562
* the operation region that aren't used for anything.
563563
*/
564-
let reserved_field =
565-
opcode(opcode::RESERVED_FIELD).then(pkg_length()).map(|((), length)| Ok(length.raw_length as u64));
564+
let reserved_field = opcode(opcode::RESERVED_FIELD)
565+
.then(region_pkg_length(region_handle))
566+
.map(|((), length)| Ok(length.raw_length as u64));
566567

567568
// TODO: work out what to do with an access field
568569
// let access_field = opcode(opcode::ACCESS_FIELD)
569570
// .then(take())
570571
// .then(take())
571572
// .map_with_context(|(((), access_type), access_attrib), context| (Ok( , context));
572573

573-
let named_field = name_seg().then(pkg_length()).map_with_context(move |(name_seg, length), context| {
574-
try_with_context!(
575-
context,
576-
context.namespace.add_value_at_resolved_path(
577-
AmlName::from_name_seg(name_seg),
578-
&context.current_scope,
579-
AmlValue::Field {
580-
region: region_handle,
581-
flags,
582-
offset: current_offset,
583-
length: length.raw_length as u64,
584-
},
585-
)
586-
);
587-
588-
(Ok(length.raw_length as u64), context)
589-
});
574+
// TODO: fields' start and end offsets need to be checked against their enclosing
575+
// OperationRegions to make sure they don't sit outside or cross the boundary.
576+
// This might not be a problem if a sane ASL compiler is used (which should check this
577+
// at compile-time), but it's better to be safe and validate that as well.
578+
579+
let named_field =
580+
name_seg().then(region_pkg_length(region_handle)).map_with_context(move |(name_seg, length), context| {
581+
try_with_context!(
582+
context,
583+
context.namespace.add_value_at_resolved_path(
584+
AmlName::from_name_seg(name_seg),
585+
&context.current_scope,
586+
AmlValue::Field {
587+
region: region_handle,
588+
flags,
589+
offset: current_offset,
590+
length: length.raw_length as u64,
591+
},
592+
)
593+
);
594+
595+
(Ok(length.raw_length as u64), context)
596+
});
590597

591598
choice!(reserved_field, named_field)
592599
}

0 commit comments

Comments
 (0)