123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828 |
- use crate::{
- misc::debug_obj,
- name_object::{name_string, simple_name, super_name, target},
- opcode::{self, opcode},
- parser::{choice, comment_scope, n_of, take, take_to_end_of_pkglength, try_with_context, Parser, Propagate},
- pkg_length::pkg_length,
- term_object::{data_ref_object, def_cond_ref_of, term_arg},
- value::{AmlType, AmlValue, Args},
- AmlError,
- DebugVerbosity,
- };
- use alloc::{
- string::{String, ToString},
- sync::Arc,
- vec,
- vec::Vec,
- };
- use core::{cmp::Ordering, convert::TryInto, mem, ops::Deref};
- pub fn expression_opcode<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
- where
- 'c: 'a,
- {
- /*
- * ExpressionOpcode := DefAquire | DefAdd | DefAnd | DefBuffer | DefConcat | DefConcatRes |
- * DefCondRefOf | DefCopyObject | DefDecrement | DefDerefOf | DefDivide |
- * DefFindSetLeftBit | DefFindSetRightBit | DefFromBCD | DefIncrement | DefIndex |
- * DefLAnd | DefLEqual | DefLGreater | DefLGreaterEqual | DefLLess | DefLLessEqual |
- * DefMid | DefLNot | DefLNotEqual | DefLoad | DefLoadTable | DefLOr | DefMatch | DefMod |
- * DefMultiply | DefNAnd | DefNOr | DefNot | DefObjectType | DefOr | DefPackage |
- * DefVarPackage | DefRefOf | DefShiftLeft | DefShiftRight | DefSizeOf | DefStore |
- * DefSubtract | DefTimer | DefToBCD | DefToBuffer | DefToDecimalString |
- * DefToHexString | DefToInteger | DefToString | DefWait | DefXOr | MethodInvocation
- */
- comment_scope(
- DebugVerbosity::AllScopes,
- "ExpressionOpcode",
- choice!(
- def_add(),
- def_and(),
- def_buffer(),
- def_concat(),
- def_concat_res(),
- def_increment(),
- def_decrement(),
- def_l_equal(),
- def_l_greater(),
- def_l_greater_equal(),
- def_l_less(),
- def_l_less_equal(),
- def_l_not_equal(),
- def_l_and(),
- def_l_or(),
- def_mid(),
- def_object_type(),
- def_package(),
- def_shift_left(),
- def_shift_right(),
- def_store(),
- def_to_integer(),
- def_cond_ref_of(),
- def_size_of(),
- method_invocation() // XXX: this must always appear last. See how we have to parse it to see why.
- ),
- )
- }
- pub fn def_add<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
- where
- 'c: 'a,
- {
- /*
- * DefAdd := 0x72 Operand Operand Target
- * Operand := TermArg => Integer
- */
- opcode(opcode::DEF_ADD_OP)
- .then(comment_scope(
- DebugVerbosity::AllScopes,
- "DefAdd",
- term_arg().then(term_arg()).then(target()).map_with_context(
- |((left_arg, right_arg), target), context| {
- let left = try_with_context!(context, left_arg.as_integer(context));
- let right = try_with_context!(context, right_arg.as_integer(context));
- let result = AmlValue::Integer(left.wrapping_add(right));
- try_with_context!(context, context.store(target, result.clone()));
- (Ok(result), context)
- },
- ),
- ))
- .map(|((), result)| Ok(result))
- }
- pub fn def_and<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
- where
- 'c: 'a,
- {
- /*
- * DefAnd := 0x7b Operand Operand Target
- * Operand := TermArg => Integer
- */
- opcode(opcode::DEF_AND_OP)
- .then(comment_scope(
- DebugVerbosity::AllScopes,
- "DefAnd",
- term_arg().then(term_arg()).then(target()).map_with_context(
- |((left_arg, right_arg), target), context| {
- let left = try_with_context!(context, left_arg.as_integer(context));
- let right = try_with_context!(context, right_arg.as_integer(context));
- let result = AmlValue::Integer(left & right);
- try_with_context!(context, context.store(target, result.clone()));
- (Ok(result), context)
- },
- ),
- ))
- .map(|((), result)| Ok(result))
- }
- pub fn def_buffer<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
- where
- 'c: 'a,
- {
- /*
- * DefBuffer := 0x11 PkgLength BufferSize ByteList
- * BufferSize := TermArg => Integer
- *
- * XXX: The spec says that zero-length buffers (e.g. the PkgLength is 0) are illegal, but
- * we've encountered them in QEMU-generated tables, so we return an empty buffer in these
- * cases.
- *
- * Uninitialized elements are initialized to zero.
- */
- opcode(opcode::DEF_BUFFER_OP)
- .then(comment_scope(
- DebugVerbosity::AllScopes,
- "DefBuffer",
- pkg_length().then(term_arg()).feed(|(pkg_length, buffer_size)| {
- take_to_end_of_pkglength(pkg_length).map_with_context(move |bytes, context| {
- let buffer_size = try_with_context!(context, buffer_size.as_integer(context)) as usize;
- if buffer_size < bytes.len() {
- return (Err(Propagate::Err(AmlError::MalformedBuffer)), context);
- }
- let mut buffer = vec![0; buffer_size];
- (&mut buffer[0..bytes.len()]).copy_from_slice(bytes);
- (Ok(buffer), context)
- })
- }),
- ))
- .map(|((), buffer)| Ok(AmlValue::Buffer(Arc::new(spinning_top::Spinlock::new(buffer)))))
- }
- pub fn def_concat<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
- where
- 'c: 'a,
- {
- /*
- * DefConcat := 0x73 Data Data Target
- * Data := TermArg => ComputationalData
- */
- opcode(opcode::DEF_CONCAT_OP)
- .then(comment_scope(
- DebugVerbosity::AllScopes,
- "DefConcat",
- term_arg().then(term_arg()).then(target()).map_with_context(|((left, right), target), context| {
- let result = match left.as_concat_type() {
- AmlValue::Integer(left) => {
- let right = try_with_context!(context, right.as_integer(context));
- let mut buffer = Vec::with_capacity(mem::size_of::<u64>() * 2);
- buffer.extend_from_slice(&left.to_le_bytes());
- buffer.extend_from_slice(&right.to_le_bytes());
- AmlValue::Buffer(Arc::new(spinning_top::Spinlock::new(buffer)))
- }
- AmlValue::Buffer(left) => {
- let mut new: Vec<u8> = left.lock().deref().clone();
- new.extend(try_with_context!(context, right.as_buffer(context)).lock().iter());
- AmlValue::Buffer(Arc::new(spinning_top::Spinlock::new(new)))
- }
- AmlValue::String(left) => {
- let right = match right.as_concat_type() {
- AmlValue::String(right) => right,
- AmlValue::Integer(_) => try_with_context!(context, right.as_string(context)),
- AmlValue::Buffer(_) => try_with_context!(context, right.as_string(context)),
- _ => panic!("Invalid type returned from `as_concat_type`"),
- };
- AmlValue::String(left + &right)
- }
- _ => panic!("Invalid type returned from `as_concat_type`"),
- };
- try_with_context!(context, context.store(target, result.clone()));
- (Ok(result), context)
- }),
- ))
- .map(|((), result)| Ok(result))
- }
- pub fn def_concat_res<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
- where
- 'c: 'a,
- {
- /*
- * DefConcatRes := 0x84 BufData BufData Target
- * BufData := TermArg => Buffer
- */
- opcode(opcode::DEF_CONCAT_RES_OP)
- .then(comment_scope(
- DebugVerbosity::AllScopes,
- "DefConcatRes",
- term_arg().then(term_arg()).then(target()).map_with_context(|((left, right), target), context| {
- let left = try_with_context!(context, left.as_buffer(context));
- let right = try_with_context!(context, right.as_buffer(context));
- let left_len = left.lock().len();
- let right_len = right.lock().len();
- if left_len == 1 || right_len == 1 {
- return (Err(Propagate::Err(AmlError::ResourceDescriptorTooShort)), context);
- }
- /*
- * `left` and `right` are buffers of resource descriptors, which we're trying to concatenate into a
- * new, single buffer containing all of the descriptors from the source buffers. We need to strip
- * off the end tags (2 bytes from each buffer), and then add our own end tag.
- *
- * XXX: either buffer may be empty (contains no tags), and so our arithmetic has to be careful.
- */
- let result = {
- let mut result =
- Vec::with_capacity(left_len.saturating_sub(2) + right_len.saturating_sub(2) + 2);
- let left_contents = left.lock();
- let right_contents = right.lock();
- result.extend_from_slice(if left_len == 0 { &[] } else { &left_contents[..(left_len - 2)] });
- result.extend_from_slice(if right_len == 0 {
- &[]
- } else {
- &right_contents[..(right_len - 2)]
- });
- /*
- * Construct a new end tag, including a new checksum:
- * | Bits | Field | Value |
- * |-------------|-------------------|---------------------------|
- * | 0-2 | Length - n bytes | 1 (for checksum) |
- * | 3-6 | Small item type | 0x0f = end tag descriptor |
- * | 7 | 0 = small item | 0 |
- */
- result.push(0b01111001);
- result.push(
- result.iter().fold(0u8, |checksum, byte| checksum.wrapping_add(*byte)).wrapping_neg(),
- );
- AmlValue::Buffer(Arc::new(spinning_top::Spinlock::new(result)))
- };
- try_with_context!(context, context.store(target, result.clone()));
- (Ok(result), context)
- }),
- ))
- .map(|((), result)| Ok(result))
- }
- fn def_increment<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
- where
- 'c: 'a,
- {
- /*
- * DefIncrement := 0x75 SuperName
- */
- opcode(opcode::DEF_INCREMENT_OP)
- .then(comment_scope(
- DebugVerbosity::AllScopes,
- "DefIncrement",
- super_name().map_with_context(|addend, context| {
- let value = try_with_context!(context, context.read_target(&addend));
- let value = try_with_context!(context, value.as_integer(context));
- let new_value = AmlValue::Integer(value + 1);
- try_with_context!(context, context.store(addend, new_value.clone()));
- (Ok(new_value), context)
- }),
- ))
- .map(|((), result)| Ok(result))
- }
- fn def_decrement<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
- where
- 'c: 'a,
- {
- /*
- * DefDecrement := 0x76 SuperName
- */
- opcode(opcode::DEF_DECREMENT_OP)
- .then(comment_scope(
- DebugVerbosity::AllScopes,
- "DefDecrement",
- super_name().map_with_context(|minuend, context| {
- let value = try_with_context!(context, context.read_target(&minuend));
- let value = try_with_context!(context, value.as_integer(context));
- let new_value = AmlValue::Integer(value - 1);
- try_with_context!(context, context.store(minuend, new_value.clone()));
- (Ok(new_value), context)
- }),
- ))
- .map(|((), result)| Ok(result))
- }
- fn def_l_and<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
- where
- 'c: 'a,
- {
- /*
- * DefLAnd := 0x90 Operand Operand
- * Operand := TermArg => Integer
- */
- opcode(opcode::DEF_L_AND_OP)
- .then(comment_scope(
- DebugVerbosity::AllScopes,
- "DefLOr",
- term_arg().then(term_arg()).map_with_context(|(left_arg, right_arg), context| {
- let left = try_with_context!(context, left_arg.as_bool());
- let right = try_with_context!(context, right_arg.as_bool());
- (Ok(AmlValue::Boolean(left && right)), context)
- }),
- ))
- .map(|((), result)| Ok(result))
- }
- fn def_l_or<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
- where
- 'c: 'a,
- {
- /*
- * DefLOr := 0x91 Operand Operand
- * Operand := TermArg => Integer
- */
- opcode(opcode::DEF_L_OR_OP)
- .then(comment_scope(
- DebugVerbosity::AllScopes,
- "DefLOr",
- term_arg().then(term_arg()).map_with_context(|(left_arg, right_arg), context| {
- let left = try_with_context!(context, left_arg.as_bool());
- let right = try_with_context!(context, right_arg.as_bool());
- (Ok(AmlValue::Boolean(left || right)), context)
- }),
- ))
- .map(|((), result)| Ok(result))
- }
- fn def_l_equal<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
- where
- 'c: 'a,
- {
- /*
- * DefLEqual := 0x93 Operand Operand
- * Operand := TermArg => Integer
- */
- opcode(opcode::DEF_L_EQUAL_OP)
- .then(comment_scope(
- DebugVerbosity::AllScopes,
- "DefLEqual",
- term_arg().then(term_arg()).map_with_context(|(left_arg, right_arg), context| {
- let ord = try_with_context!(context, left_arg.cmp(right_arg, context));
- (Ok(AmlValue::Boolean(ord == Ordering::Equal)), context)
- }),
- ))
- .map(|((), result)| Ok(result))
- }
- fn def_l_greater<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
- where
- 'c: 'a,
- {
- /*
- * DefLGreater := 0x94 Operand Operand
- */
- opcode(opcode::DEF_L_GREATER_OP)
- .then(comment_scope(
- DebugVerbosity::AllScopes,
- "DefLGreater",
- term_arg().then(term_arg()).map_with_context(|(left_arg, right_arg), context| {
- let ord = try_with_context!(context, left_arg.cmp(right_arg, context));
- (Ok(AmlValue::Boolean(ord == Ordering::Greater)), context)
- }),
- ))
- .map(|((), result)| Ok(result))
- }
- fn def_l_greater_equal<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
- where
- 'c: 'a,
- {
- /*
- * DefLGreaterEqual := LNotOp(0x92) LLessOp(0x95) Operand Operand
- */
- opcode(opcode::DEF_L_NOT_OP)
- .then(opcode(opcode::DEF_L_LESS_OP))
- .then(comment_scope(
- DebugVerbosity::AllScopes,
- "DefLGreaterEqual",
- term_arg().then(term_arg()).map_with_context(|(left_arg, right_arg), context| {
- let ord = try_with_context!(context, left_arg.cmp(right_arg, context));
- (Ok(AmlValue::Boolean(ord != Ordering::Less)), context)
- }),
- ))
- .map(|(((), ()), result)| Ok(result))
- }
- fn def_l_less<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
- where
- 'c: 'a,
- {
- /*
- * DefLLess := 0x95 Operand Operand
- */
- opcode(opcode::DEF_L_LESS_OP)
- .then(comment_scope(
- DebugVerbosity::AllScopes,
- "DefLLess",
- term_arg().then(term_arg()).map_with_context(|(left_arg, right_arg), context| {
- let ord = try_with_context!(context, left_arg.cmp(right_arg, context));
- (Ok(AmlValue::Boolean(ord == Ordering::Less)), context)
- }),
- ))
- .map(|((), result)| Ok(result))
- }
- fn def_l_less_equal<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
- where
- 'c: 'a,
- {
- /*
- * DefLLessEqual := LNotOp(0x92) LGreaterOp(0x94) Operand Operand
- */
- opcode(opcode::DEF_L_NOT_OP)
- .then(opcode(opcode::DEF_L_GREATER_OP))
- .then(comment_scope(
- DebugVerbosity::AllScopes,
- "DefLLessEqual",
- term_arg().then(term_arg()).map_with_context(|(left_arg, right_arg), context| {
- let ord = try_with_context!(context, left_arg.cmp(right_arg, context));
- (Ok(AmlValue::Boolean(ord != Ordering::Greater)), context)
- }),
- ))
- .map(|(((), ()), result)| Ok(result))
- }
- fn def_l_not_equal<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
- where
- 'c: 'a,
- {
- /*
- * DefLNotEqual := LNotOp(0x92) LEqualOp(0x93) Operand Operand
- */
- opcode(opcode::DEF_L_NOT_OP)
- .then(opcode(opcode::DEF_L_EQUAL_OP))
- .then(comment_scope(
- DebugVerbosity::AllScopes,
- "DefLNotEqual",
- term_arg().then(term_arg()).map_with_context(|(left_arg, right_arg), context| {
- let ord = try_with_context!(context, left_arg.cmp(right_arg, context));
- (Ok(AmlValue::Boolean(ord != Ordering::Equal)), context)
- }),
- ))
- .map(|(((), ()), result)| Ok(result))
- }
- fn def_mid<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
- where
- 'c: 'a,
- {
- /*
- * DefMid := 0x9e MidObj TermArg TermArg Target
- * MidObj := TermArg => Buffer | String
- */
- opcode(opcode::DEF_MID_OP)
- .then(comment_scope(
- DebugVerbosity::AllScopes,
- "DefMid",
- term_arg().then(term_arg()).then(term_arg()).then(target()).map_with_context(
- |(((source, index), length), target), context| {
- let index = try_with_context!(context, index.as_integer(context)) as usize;
- let length = try_with_context!(context, length.as_integer(context)) as usize;
- let result = try_with_context!(
- context,
- match source {
- AmlValue::Buffer(bytes) => {
- let foo = bytes.lock();
- if index >= foo.len() {
- Ok(AmlValue::Buffer(Arc::new(spinning_top::Spinlock::new(vec![]))))
- } else if (index + length) >= foo.len() {
- Ok(AmlValue::Buffer(Arc::new(spinning_top::Spinlock::new(
- foo[index..].to_vec(),
- ))))
- } else {
- Ok(AmlValue::Buffer(Arc::new(spinning_top::Spinlock::new(
- foo[index..(index + length)].to_vec(),
- ))))
- }
- }
- /*
- * XXX: The spec conflates characters and bytes, so we effectively ignore unicode and do
- * this bytewise, to hopefully match other implementations.
- */
- AmlValue::String(string) => {
- if index >= string.len() {
- Ok(AmlValue::String(String::new()))
- } else if (index + length) >= string.len() {
- Ok(AmlValue::String(string[index..].to_string()))
- } else {
- Ok(AmlValue::String(string[index..(index + length)].to_string()))
- }
- }
- _ => Err(AmlError::TypeCannotBeSliced(source.type_of())),
- }
- );
- try_with_context!(context, context.store(target, result.clone()));
- (Ok(result), context)
- },
- ),
- ))
- .map(|((), result)| Ok(result))
- }
- pub fn def_object_type<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
- where
- 'c: 'a,
- {
- /*
- * DefObjectType := 0x8e <SimpleName | DebugObj | DefRefOf | DefDerefOf | DefIndex>
- *
- * Returns an integer representing the type of an AML object. If executed on an object that is a reference to a
- * value (e.g. produced by `Alias`, `RefOf`, or `Index`), the type of the base object is returned. For typeless
- * objects, such as scopes, a type of `0 - Uninitialized` is returned.
- *
- * 0 = Uninitialized
- * 1 = Integer
- * 2 = String
- * 3 = Buffer
- * 4 = Package
- * 5 = Field Unit
- * 6 = Device
- * 7 = Event
- * 8 = Method
- * 9 = Mutex
- * 10 = Operation Region
- * 11 = Power Resource
- * 12 = Processor
- * 13 = Thermal Zone
- * 14 = Buffer Field
- * 15 = Reserved
- * 16 = Debug Object
- * >16 = *Reserved*
- */
- // TODO: this doesn't correctly handle taking the type of a namespace node (e.g. `\_SB`), but I'm not sure any
- // other implementations do either?
- opcode(opcode::DEF_OBJECT_TYPE_OP)
- .then(comment_scope(
- DebugVerbosity::AllScopes,
- "DefObjectType",
- choice!(
- simple_name().map_with_context(|target, context| {
- let value = try_with_context!(context, context.read_target(&target));
- let typ = match value.type_of() {
- AmlType::Uninitialized => 0,
- AmlType::Integer => 1,
- AmlType::String => 2,
- AmlType::Buffer => 3,
- AmlType::RawDataBuffer => 3, // TODO: not sure if this is correct
- AmlType::Package => 4,
- AmlType::FieldUnit => 5,
- AmlType::Device => 6,
- AmlType::Event => 7,
- AmlType::Method => 8,
- AmlType::Mutex => 9,
- AmlType::OpRegion => 10,
- AmlType::PowerResource => 11,
- AmlType::Processor => 12,
- AmlType::ThermalZone => 13,
- AmlType::BufferField => 14,
- AmlType::DebugObject => 16,
- // TODO: what to do with this?
- AmlType::DdbHandle => 0,
- AmlType::ObjReference => todo!(),
- };
- (Ok(AmlValue::Integer(typ)), context)
- }),
- debug_obj().map(|()| Ok(AmlValue::Integer(16)))
- ),
- ))
- .map(|((), result)| Ok(result))
- }
- pub fn def_package<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
- where
- 'c: 'a,
- {
- /*
- * DefPackage := 0x12 PkgLength NumElements PackageElementList
- * NumElements := ByteData
- * PackageElementList := Nothing | <PackageElement PackageElementList>
- * PackageElement := DataRefObject | NameString
- */
- opcode(opcode::DEF_PACKAGE_OP)
- .then(comment_scope(
- DebugVerbosity::AllScopes,
- "DefPackage",
- pkg_length().then(take()).feed(|(pkg_length, num_elements)| {
- move |mut input, mut context| {
- let mut package_contents = Vec::new();
- while pkg_length.still_parsing(input) {
- let (new_input, new_context, value) = package_element().parse(input, context)?;
- input = new_input;
- context = new_context;
- package_contents.push(value);
- }
- if package_contents.len() != num_elements as usize {
- return Err((input, context, Propagate::Err(AmlError::MalformedPackage)));
- }
- Ok((input, context, AmlValue::Package(package_contents)))
- }
- }),
- ))
- .map(|((), package)| Ok(package))
- }
- pub fn package_element<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
- where
- 'c: 'a,
- {
- choice!(data_ref_object(), name_string().map(|string| Ok(AmlValue::String(string.as_string()))))
- }
- fn def_shift_left<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
- where
- 'c: 'a,
- {
- /*
- * DefShiftLeft := 0x79 Operand ShiftCount Target
- * Operand := TermArg => Integer
- * ShiftCount := TermArg => Integer
- */
- opcode(opcode::DEF_SHIFT_LEFT)
- .then(comment_scope(DebugVerbosity::Scopes, "DefShiftLeft", term_arg().then(term_arg()).then(target())))
- .map_with_context(|((), ((operand, shift_count), target)), context| {
- let operand = try_with_context!(context, operand.as_integer(context));
- let shift_count = try_with_context!(context, shift_count.as_integer(context));
- let shift_count =
- try_with_context!(context, shift_count.try_into().map_err(|_| AmlError::InvalidShiftLeft));
- let result = AmlValue::Integer(try_with_context!(
- context,
- operand.checked_shl(shift_count).ok_or(AmlError::InvalidShiftLeft)
- ));
- try_with_context!(context, context.store(target, result.clone()));
- (Ok(result), context)
- })
- }
- fn def_shift_right<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
- where
- 'c: 'a,
- {
- /*
- * DefShiftRight := 0x7a Operand ShiftCount Target
- * Operand := TermArg => Integer
- * ShiftCount := TermArg => Integer
- */
- opcode(opcode::DEF_SHIFT_RIGHT)
- .then(comment_scope(DebugVerbosity::Scopes, "DefShiftRight", term_arg().then(term_arg()).then(target())))
- .map_with_context(|((), ((operand, shift_count), target)), context| {
- let operand = try_with_context!(context, operand.as_integer(context));
- let shift_count = try_with_context!(context, shift_count.as_integer(context));
- let shift_count =
- try_with_context!(context, shift_count.try_into().map_err(|_| AmlError::InvalidShiftRight));
- let result = AmlValue::Integer(try_with_context!(
- context,
- operand.checked_shr(shift_count).ok_or(AmlError::InvalidShiftRight)
- ));
- try_with_context!(context, context.store(target, result.clone()));
- (Ok(result), context)
- })
- }
- fn def_store<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
- where
- 'c: 'a,
- {
- /*
- * DefStore := 0x70 TermArg SuperName
- *
- * Implicit conversion is only applied when the destination target is a `Name` - not when we
- * are storing into a method local or argument (these stores are semantically identical to
- * CopyObject). We must also make sure to return a copy of the data that is in the destination
- * after the store (as opposed to the data we think we put into it), because some stores can
- * alter the data during the store.
- */
- opcode(opcode::DEF_STORE_OP)
- .then(comment_scope(DebugVerbosity::Scopes, "DefStore", term_arg().then(super_name())))
- .map_with_context(|((), (value, target)), context| {
- (Ok(try_with_context!(context, context.store(target, value))), context)
- })
- }
- fn def_to_integer<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
- where
- 'c: 'a,
- {
- /*
- * DefToInteger := 0x99 Operand Target
- * Operand := TermArg
- */
- opcode(opcode::DEF_TO_INTEGER_OP)
- .then(comment_scope(DebugVerbosity::AllScopes, "DefToInteger", term_arg().then(target())))
- .map_with_context(|((), (operand, target)), context| {
- let result = match operand {
- AmlValue::Integer(value) => AmlValue::Integer(value),
- AmlValue::Buffer(data) => {
- AmlValue::Integer(try_with_context!(context, AmlValue::Buffer(data).as_integer(context)))
- }
- AmlValue::String(string) => AmlValue::Integer(try_with_context!(
- context,
- if string.starts_with("0x") {
- u64::from_str_radix(string.trim_start_matches("0x"), 16)
- } else {
- string.parse::<u64>()
- }
- .map_err(|_| AmlError::IncompatibleValueConversion {
- current: AmlType::String,
- target: AmlType::Integer,
- })
- )),
- _ => {
- return (
- Err(Propagate::Err(AmlError::IncompatibleValueConversion {
- current: operand.type_of(),
- target: AmlType::Integer,
- })),
- context,
- )
- }
- };
- try_with_context!(context, context.store(target, result.clone()));
- (Ok(result), context)
- })
- }
- fn def_size_of<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
- where
- 'c: 'a,
- {
- /*
- * SizeOf := 0x87 SuperName
- */
- opcode(opcode::DEF_SIZE_OF_OP)
- .then(comment_scope(
- DebugVerbosity::AllScopes,
- "DefSizeOf",
- super_name().map_with_context(|target, context| {
- let value = try_with_context!(context, context.read_target(&target));
- let size_of = try_with_context!(context, value.size_of());
- (Ok(AmlValue::Integer(size_of)), context)
- }),
- ))
- .map(|((), value)| Ok(value))
- }
- fn method_invocation<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
- where
- 'c: 'a,
- {
- /*
- * MethodInvocation := NameString TermArgList
- *
- * MethodInvocation is the worst of the AML structures, because you're meant to figure out how much you're
- * meant to parse using the name of the method (by knowing from its definition how how many arguments it
- * takes). However, the definition of a method can in theory appear after an invocation of that method, and
- * so parsing them properly can be very difficult.
- * NOTE: We don't support the case of the definition appearing after the invocation.
- */
- comment_scope(
- DebugVerbosity::Scopes,
- "MethodInvocation",
- name_string()
- .map_with_context(move |name, context| {
- let (full_path, handle) =
- try_with_context!(context, context.namespace.search(&name, &context.current_scope)).clone();
- /*
- * `None` if the path is not a method and so doesn't have arguments, or `Some(the number of
- * arguments to parse)` if it's a method.
- */
- let num_args = if let AmlValue::Method { flags, .. } =
- try_with_context!(context, context.namespace.get(handle))
- {
- Some(flags.arg_count())
- } else {
- None
- };
- (Ok((full_path, num_args)), context)
- })
- .feed(|(path, num_args)| {
- n_of(term_arg(), num_args.unwrap_or(0) as usize).map_with_context(move |arg_list, context| {
- if num_args.is_some() {
- let args = try_with_context!(context, Args::from_list(arg_list));
- let result = context.invoke_method(&path, args);
- (Ok(try_with_context!(context, result)), context)
- } else {
- (Ok(try_with_context!(context, context.namespace.get_by_path(&path)).clone()), context)
- }
- })
- }),
- )
- }
|