Skip to content

Commit e02ab2a

Browse files
committed
Fix handling of VarPackages
1 parent f66b801 commit e02ab2a

File tree

2 files changed

+125
-60
lines changed

2 files changed

+125
-60
lines changed

src/aml/mod.rs

Lines changed: 116 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,7 @@ where
558558
context.contribute_arg(Argument::Object(Object::Buffer(buffer).wrap()));
559559
context.retire_op(op);
560560
}
561-
Opcode::Package | Opcode::VarPackage => {
561+
Opcode::Package => {
562562
let mut elements = Vec::with_capacity(op.expected_arguments);
563563
for arg in &op.arguments {
564564
let Argument::Object(object) = arg else { panic!() };
@@ -582,6 +582,27 @@ where
582582
context.contribute_arg(Argument::Object(Object::Package(elements).wrap()));
583583
context.retire_op(op);
584584
}
585+
Opcode::VarPackage => {
586+
let Argument::Object(total_elements) = &op.arguments[0] else { panic!() };
587+
let total_elements =
588+
total_elements.clone().unwrap_transparent_reference().as_integer()? as usize;
589+
590+
let mut elements = Vec::with_capacity(total_elements);
591+
for arg in &op.arguments[1..] {
592+
let Argument::Object(object) = arg else { panic!() };
593+
elements.push(object.clone());
594+
}
595+
596+
/*
597+
* As above, we always remove the block here after the in-flight op has
598+
* been retired.
599+
*/
600+
assert_eq!(context.current_block.kind, BlockKind::VarPackage);
601+
assert_eq!(context.peek(), Err(AmlError::RunOutOfStream));
602+
context.current_block = context.block_stack.pop().unwrap();
603+
context.contribute_arg(Argument::Object(Object::Package(elements).wrap()));
604+
context.retire_op(op);
605+
}
585606
Opcode::If => {
586607
let [
587608
Argument::TrackedPc(start_pc),
@@ -918,28 +939,9 @@ where
918939
assert!(!context.block_stack.is_empty());
919940

920941
if let Some(package_op) = context.in_flight.last_mut()
921-
&& (package_op.op == Opcode::Package || package_op.op == Opcode::VarPackage)
942+
&& package_op.op == Opcode::Package
922943
{
923-
let num_elements_left = match package_op.op {
924-
Opcode::Package => package_op.expected_arguments - package_op.arguments.len(),
925-
Opcode::VarPackage => {
926-
let Argument::Object(total_elements) = &package_op.arguments[0] else {
927-
panic!()
928-
};
929-
let total_elements =
930-
total_elements.clone().unwrap_transparent_reference().as_integer()?
931-
as usize;
932-
933-
// Update the expected number of arguments to terminate the in-flight op
934-
package_op.expected_arguments = total_elements;
935-
936-
total_elements - package_op.arguments.len()
937-
}
938-
_ => panic!(
939-
"Current in-flight op is not a `Package` or `VarPackage` when finished parsing package block"
940-
),
941-
};
942-
944+
let num_elements_left = package_op.expected_arguments - package_op.arguments.len();
943945
for _ in 0..num_elements_left {
944946
package_op.arguments.push(Argument::Object(Object::Uninitialized.wrap()));
945947
}
@@ -949,6 +951,33 @@ where
949951
// package ops for rationale here.
950952
continue;
951953
}
954+
BlockKind::VarPackage => {
955+
assert!(!context.block_stack.is_empty());
956+
957+
if let Some(package_op) = context.in_flight.last_mut()
958+
&& package_op.op == Opcode::VarPackage
959+
{
960+
let num_elements_left = {
961+
let Argument::Object(total_elements) = &package_op.arguments[0] else {
962+
panic!()
963+
};
964+
let total_elements =
965+
total_elements.clone().unwrap_transparent_reference().as_integer()?
966+
as usize;
967+
968+
// Update the expected number of arguments to terminate the in-flight op
969+
package_op.expected_arguments = package_op.arguments.len();
970+
total_elements - (package_op.arguments.len() - 1)
971+
};
972+
973+
for _ in 0..num_elements_left {
974+
package_op.arguments.push(Argument::Object(Object::Uninitialized.wrap()));
975+
}
976+
}
977+
978+
// As above, leave the package's block.
979+
continue;
980+
}
952981
BlockKind::IfThenBranch => {
953982
context.current_block = context.block_stack.pop().unwrap();
954983

@@ -1087,7 +1116,7 @@ where
10871116
* be in the package later.
10881117
*/
10891118
context.start_in_flight_op(OpInFlight::new(Opcode::VarPackage, usize::MAX));
1090-
context.start_new_block(BlockKind::Package, remaining_length);
1119+
context.start_new_block(BlockKind::VarPackage, remaining_length);
10911120
}
10921121
Opcode::Method => {
10931122
let start_pc = context.current_block.pc;
@@ -1307,48 +1336,75 @@ where
13071336
* to by a string. This is not well defined by the specification, but matches
13081337
* expected behaviour of other interpreters, and is most useful for downstream
13091338
* users.
1339+
* - In variable-length package definitions, the first 'element' is the
1340+
* length of the package, and should be resolved to an object. The
1341+
* remaining elements should be treated the same as in a package definition.
13101342
*/
1311-
if context.current_block.kind == BlockKind::Package {
1312-
context
1313-
.last_op()?
1314-
.arguments
1315-
.push(Argument::Object(Object::String(name.to_string()).wrap()));
1343+
enum ResolveBehaviour {
1344+
ResolveToObject,
1345+
ResolveIfExists,
1346+
PackageElement,
1347+
}
1348+
let behaviour = if context.current_block.kind == BlockKind::Package {
1349+
ResolveBehaviour::PackageElement
1350+
} else if context.current_block.kind == BlockKind::VarPackage {
1351+
if context.last_op()?.arguments.len() == 0 {
1352+
ResolveBehaviour::ResolveToObject
1353+
} else {
1354+
ResolveBehaviour::PackageElement
1355+
}
13161356
} else if context.in_flight.last().map(|op| op.op == Opcode::CondRefOf).unwrap_or(false) {
1317-
let object = self.namespace.lock().search(&name, &context.current_scope);
1318-
match object {
1319-
Ok((_, object)) => {
1320-
let reference =
1321-
Object::Reference { kind: ReferenceKind::RefOf, inner: object.clone() };
1322-
context.last_op()?.arguments.push(Argument::Object(reference.wrap()));
1323-
}
1324-
Err(AmlError::ObjectDoesNotExist(_)) => {
1325-
let reference = Object::Reference {
1326-
kind: ReferenceKind::Unresolved,
1327-
inner: Object::String(name.to_string()).wrap(),
1328-
};
1329-
context.last_op()?.arguments.push(Argument::Object(reference.wrap()));
1357+
ResolveBehaviour::ResolveIfExists
1358+
} else {
1359+
ResolveBehaviour::ResolveToObject
1360+
};
1361+
1362+
match behaviour {
1363+
ResolveBehaviour::ResolveToObject => {
1364+
let object = self.namespace.lock().search(&name, &context.current_scope);
1365+
match object {
1366+
Ok((resolved_name, object)) => {
1367+
if let Object::Method { flags, .. } | Object::NativeMethod { flags, .. } =
1368+
*object
1369+
{
1370+
context.start_in_flight_op(OpInFlight::new_with(
1371+
Opcode::InternalMethodCall,
1372+
vec![Argument::Object(object), Argument::Namestring(resolved_name)],
1373+
flags.arg_count(),
1374+
))
1375+
} else if let Object::FieldUnit(ref field) = *object {
1376+
let value = self.do_field_read(field)?;
1377+
context.last_op()?.arguments.push(Argument::Object(value));
1378+
} else {
1379+
context.last_op()?.arguments.push(Argument::Object(object));
1380+
}
1381+
}
1382+
Err(err) => Err(err)?,
13301383
}
1331-
Err(other) => Err(other)?,
13321384
}
1333-
} else {
1334-
let object = self.namespace.lock().search(&name, &context.current_scope);
1335-
match object {
1336-
Ok((resolved_name, object)) => {
1337-
if let Object::Method { flags, .. } | Object::NativeMethod { flags, .. } = *object
1338-
{
1339-
context.start_in_flight_op(OpInFlight::new_with(
1340-
Opcode::InternalMethodCall,
1341-
vec![Argument::Object(object), Argument::Namestring(resolved_name)],
1342-
flags.arg_count(),
1343-
))
1344-
} else if let Object::FieldUnit(ref field) = *object {
1345-
let value = self.do_field_read(field)?;
1346-
context.last_op()?.arguments.push(Argument::Object(value));
1347-
} else {
1348-
context.last_op()?.arguments.push(Argument::Object(object));
1385+
ResolveBehaviour::ResolveIfExists => {
1386+
let object = self.namespace.lock().search(&name, &context.current_scope);
1387+
match object {
1388+
Ok((_, object)) => {
1389+
let reference =
1390+
Object::Reference { kind: ReferenceKind::RefOf, inner: object.clone() };
1391+
context.last_op()?.arguments.push(Argument::Object(reference.wrap()));
1392+
}
1393+
Err(AmlError::ObjectDoesNotExist(_)) => {
1394+
let reference = Object::Reference {
1395+
kind: ReferenceKind::Unresolved,
1396+
inner: Object::String(name.to_string()).wrap(),
1397+
};
1398+
context.last_op()?.arguments.push(Argument::Object(reference.wrap()));
13491399
}
1400+
Err(other) => Err(other)?,
13501401
}
1351-
Err(err) => Err(err)?,
1402+
}
1403+
ResolveBehaviour::PackageElement => {
1404+
context
1405+
.last_op()?
1406+
.arguments
1407+
.push(Argument::Object(Object::String(name.to_string()).wrap()));
13521408
}
13531409
}
13541410
}
@@ -2476,6 +2532,7 @@ pub enum BlockKind {
24762532
old_scope: AmlName,
24772533
},
24782534
Package,
2535+
VarPackage,
24792536
/// Used for executing the then-branch of an `DefIfElse`. After finishing, it will check for
24802537
/// and skip over an else-branch, if present.
24812538
IfThenBranch,

tests/package.asl

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,15 @@ DefinitionBlock("package.aml", "DSDT", 1, "RSACPI", "PACKGE", 1) {
2020
Package { 0x0d, 0x0e, 0x0f },
2121
})
2222

23-
Name(LEN, 10)
23+
Name(LEN, 5)
24+
Name(BAL, Package(LEN) {
25+
1,
26+
2,
27+
3,
28+
4,
29+
})
30+
31+
LEN = 10
2432
Name(BAZ, Package (LEN) {
2533
4,
2634
11,

0 commit comments

Comments
 (0)