1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093 |
- use crate::{
- expression::{def_buffer, def_package, expression_opcode},
- misc::{arg_obj, local_obj},
- name_object::{name_seg, name_string, target, Target},
- namespace::{AmlName, LevelType},
- opcode::{self, ext_opcode, opcode},
- parser::{
- choice,
- comment_scope,
- take,
- take_to_end_of_pkglength,
- take_u16,
- take_u32,
- take_u64,
- try_with_context,
- ParseResult,
- Parser,
- Propagate,
- },
- pkg_length::{pkg_length, region_pkg_length, PkgLength},
- statement::statement_opcode,
- value::{AmlValue, FieldFlags, MethodCode, MethodFlags, RegionSpace},
- AmlContext,
- AmlError,
- AmlHandle,
- DebugVerbosity,
- };
- use alloc::{string::String, sync::Arc, vec::Vec};
- use core::str;
- /// `TermList`s are usually found within explicit-length objects (so they have a `PkgLength`
- /// elsewhere in the structure), so this takes a number of bytes to parse.
- pub fn term_list<'a, 'c>(list_length: PkgLength) -> impl Parser<'a, 'c, ()>
- where
- 'c: 'a,
- {
- /*
- * TermList := Nothing | <TermObj TermList>
- */
- // TODO: why does this use still_parsing, instead of just taking the whole thing and parsing it til it's empty?
- move |mut input: &'a [u8], mut context: &'c mut AmlContext| {
- while list_length.still_parsing(input) {
- // TODO: currently, we ignore the value of the expression. We may need to propagate
- // this.
- let (new_input, new_context, _) = term_object().parse(input, context)?;
- input = new_input;
- context = new_context;
- }
- Ok((input, context, ()))
- }
- }
- pub fn term_object<'a, 'c>() -> impl Parser<'a, 'c, Option<AmlValue>>
- where
- 'c: 'a,
- {
- /*
- * TermObj := NamespaceModifierObj | NamedObj | StatementOpcode | ExpressionOpcode
- */
- comment_scope(
- DebugVerbosity::AllScopes,
- "TermObj",
- choice!(
- namespace_modifier().map(|()| Ok(None)),
- named_obj().map(|()| Ok(None)),
- statement_opcode().map(|()| Ok(None)),
- expression_opcode().map(|value| Ok(Some(value)))
- ),
- )
- }
- pub fn namespace_modifier<'a, 'c>() -> impl Parser<'a, 'c, ()>
- where
- 'c: 'a,
- {
- /*
- * NamespaceModifierObj := DefAlias | DefName | DefScope
- */
- choice!(def_alias(), def_name(), def_scope())
- }
- pub fn named_obj<'a, 'c>() -> impl Parser<'a, 'c, ()>
- where
- 'c: 'a,
- {
- /*
- * NamedObj := DefBankField | DefCreateBitField | DefCreateByteField | DefCreateWordField | DefCreateDWordField |
- * DefCreateQWordField | DefCreateField | DefDataRegion | DefExternal | DefOpRegion | DefPowerRes |
- * DefProcessor | DefThermalZone | DefMethod | DefMutex
- *
- * XXX: DefMethod and DefMutex (at least) are not included in any rule in the AML grammar,
- * but are defined in the NamedObj section so we assume they're part of NamedObj
- */
- comment_scope(
- DebugVerbosity::AllScopes,
- "NamedObj",
- choice!(
- def_create_bit_field(),
- def_create_byte_field(),
- def_create_word_field(),
- def_create_dword_field(),
- def_create_qword_field(),
- def_create_field(),
- def_op_region(),
- def_field(),
- def_method(),
- def_external(),
- def_device(),
- def_processor(),
- def_power_res(),
- def_thermal_zone(),
- def_mutex()
- ),
- )
- }
- pub fn def_name<'a, 'c>() -> impl Parser<'a, 'c, ()>
- where
- 'c: 'a,
- {
- /*
- * DefName := 0x08 NameString DataRefObject
- */
- opcode(opcode::DEF_NAME_OP)
- .then(comment_scope(
- DebugVerbosity::Scopes,
- "DefName",
- name_string().then(data_ref_object()).map_with_context(|(name, data_ref_object), context| {
- try_with_context!(
- context,
- context.namespace.add_value_at_resolved_path(name, &context.current_scope, data_ref_object)
- );
- (Ok(()), context)
- }),
- ))
- .discard_result()
- }
- pub fn def_alias<'a, 'c>() -> impl Parser<'a, 'c, ()>
- where
- 'c: 'a,
- {
- /*
- * DefAlias := 0x06 NameString NameString
- * The second name refers to the same object as the first
- */
- opcode(opcode::DEF_ALIAS_OP)
- .then(comment_scope(
- DebugVerbosity::Scopes,
- "DefAlias",
- name_string().then(name_string()).map_with_context(|(target, alias), context| {
- try_with_context!(
- context,
- context.namespace.add_alias_at_resolved_path(alias, &context.current_scope, target)
- );
- (Ok(()), context)
- }),
- ))
- .discard_result()
- }
- pub fn def_scope<'a, 'c>() -> impl Parser<'a, 'c, ()>
- where
- 'c: 'a,
- {
- /*
- * DefScope := 0x10 PkgLength NameString TermList
- */
- opcode(opcode::DEF_SCOPE_OP)
- .then(comment_scope(
- DebugVerbosity::Scopes,
- "DefScope",
- pkg_length()
- .then(name_string())
- .map_with_context(|(length, name), context| {
- let previous_scope = context.current_scope.clone();
- context.current_scope = try_with_context!(context, name.resolve(&context.current_scope));
- context.comment(
- DebugVerbosity::Scopes,
- &(String::from("Scope name: ") + &context.current_scope.as_string()),
- );
- try_with_context!(
- context,
- context.namespace.add_level(context.current_scope.clone(), LevelType::Scope)
- );
- (Ok((length, previous_scope)), context)
- })
- .feed(|(pkg_length, previous_scope)| {
- term_list(pkg_length).map(move |_| Ok(previous_scope.clone()))
- })
- .map_with_context(|previous_scope, context| {
- context.current_scope = previous_scope;
- (Ok(()), context)
- }),
- ))
- .discard_result()
- }
- pub fn def_create_bit_field<'a, 'c>() -> impl Parser<'a, 'c, ()>
- where
- 'c: 'a,
- {
- /*
- * DefCreateBitField := 0x8d SourceBuf BitIndex NameString
- * SourceBuf := TermArg => Buffer
- * BitIndex := TermArg => Integer
- */
- opcode(opcode::DEF_CREATE_BIT_FIELD_OP)
- .then(comment_scope(
- DebugVerbosity::AllScopes,
- "DefCreateBitField",
- term_arg().then(term_arg()).then(name_string()).map_with_context(
- |((source, index), name), context| {
- let source_data: Arc<spinning_top::Spinlock<Vec<u8>>> =
- try_with_context!(context, source.as_buffer(context)).clone();
- let index = try_with_context!(context, index.as_integer(context));
- try_with_context!(
- context,
- context.namespace.add_value_at_resolved_path(
- name,
- &context.current_scope,
- AmlValue::BufferField { buffer_data: source_data, offset: index, length: 1 }
- )
- );
- (Ok(()), context)
- },
- ),
- ))
- .discard_result()
- }
- pub fn def_create_byte_field<'a, 'c>() -> impl Parser<'a, 'c, ()>
- where
- 'c: 'a,
- {
- /*
- * DefCreateByteField := 0x8c SourceBuf ByteIndex NameString
- * SourceBuf := TermArg => Buffer
- * ByteIndex := TermArg => Integer
- */
- opcode(opcode::DEF_CREATE_BYTE_FIELD_OP)
- .then(comment_scope(
- DebugVerbosity::AllScopes,
- "DefCreateByteField",
- term_arg().then(term_arg()).then(name_string()).map_with_context(
- |((source, index), name), context| {
- let source_data: Arc<spinning_top::Spinlock<Vec<u8>>> =
- try_with_context!(context, source.as_buffer(context)).clone();
- let index = try_with_context!(context, index.as_integer(context));
- try_with_context!(
- context,
- context.namespace.add_value_at_resolved_path(
- name,
- &context.current_scope,
- AmlValue::BufferField { buffer_data: source_data, offset: index * 8, length: 8 }
- )
- );
- (Ok(()), context)
- },
- ),
- ))
- .discard_result()
- }
- pub fn def_create_word_field<'a, 'c>() -> impl Parser<'a, 'c, ()>
- where
- 'c: 'a,
- {
- /*
- * DefCreateWordField := 0x8b SourceBuf ByteIndex NameString
- * SourceBuf := TermArg => Buffer
- * ByteIndex := TermArg => Integer
- */
- opcode(opcode::DEF_CREATE_WORD_FIELD_OP)
- .then(comment_scope(
- DebugVerbosity::AllScopes,
- "DefCreateWordField",
- term_arg().then(term_arg()).then(name_string()).map_with_context(
- |((source, index), name), context| {
- let source_data: Arc<spinning_top::Spinlock<Vec<u8>>> =
- try_with_context!(context, source.as_buffer(context)).clone();
- let index = try_with_context!(context, index.as_integer(context));
- try_with_context!(
- context,
- context.namespace.add_value_at_resolved_path(
- name,
- &context.current_scope,
- AmlValue::BufferField { buffer_data: source_data, offset: index * 8, length: 16 }
- )
- );
- (Ok(()), context)
- },
- ),
- ))
- .discard_result()
- }
- pub fn def_create_dword_field<'a, 'c>() -> impl Parser<'a, 'c, ()>
- where
- 'c: 'a,
- {
- /*
- * DefCreateDWordField := 0x8a SourceBuf ByteIndex NameString
- * SourceBuf := TermArg => Buffer
- * ByteIndex := TermArg => Integer
- */
- opcode(opcode::DEF_CREATE_DWORD_FIELD_OP)
- .then(comment_scope(
- DebugVerbosity::AllScopes,
- "DefCreateDWordField",
- term_arg().then(term_arg()).then(name_string()).map_with_context(
- |((source, index), name), context| {
- let source_data: Arc<spinning_top::Spinlock<Vec<u8>>> =
- try_with_context!(context, source.as_buffer(context)).clone();
- let index = try_with_context!(context, index.as_integer(context));
- try_with_context!(
- context,
- context.namespace.add_value_at_resolved_path(
- name,
- &context.current_scope,
- AmlValue::BufferField { buffer_data: source_data, offset: index * 8, length: 32 }
- )
- );
- (Ok(()), context)
- },
- ),
- ))
- .discard_result()
- }
- pub fn def_create_qword_field<'a, 'c>() -> impl Parser<'a, 'c, ()>
- where
- 'c: 'a,
- {
- /*
- * DefCreateQWordField := 0x8f SourceBuf ByteIndex NameString
- * SourceBuf := TermArg => Buffer
- * ByteIndex := TermArg => Integer
- */
- opcode(opcode::DEF_CREATE_QWORD_FIELD_OP)
- .then(comment_scope(
- DebugVerbosity::AllScopes,
- "DefCreateQWordField",
- term_arg().then(term_arg()).then(name_string()).map_with_context(
- |((source, index), name), context| {
- let source_data: Arc<spinning_top::Spinlock<Vec<u8>>> =
- try_with_context!(context, source.as_buffer(context)).clone();
- let index = try_with_context!(context, index.as_integer(context));
- try_with_context!(
- context,
- context.namespace.add_value_at_resolved_path(
- name,
- &context.current_scope,
- AmlValue::BufferField { buffer_data: source_data, offset: index * 8, length: 64 }
- )
- );
- (Ok(()), context)
- },
- ),
- ))
- .discard_result()
- }
- pub fn def_create_field<'a, 'c>() -> impl Parser<'a, 'c, ()>
- where
- 'c: 'a,
- {
- /*
- * DefCreateField := ExtOpPrefix 0x13 SourceBuf BitIndex NumBits NameString
- * SourceBuf := TermArg => Buffer
- * BitIndex := TermArg => Integer
- * NumBits := TermArg => Integer
- */
- ext_opcode(opcode::EXT_DEF_CREATE_FIELD_OP)
- .then(comment_scope(
- DebugVerbosity::Scopes,
- "DefCreateField",
- term_arg().then(term_arg()).then(term_arg()).then(name_string()).map_with_context(
- |(((source, index), num_bits), name), context| {
- let source_data: Arc<spinning_top::Spinlock<Vec<u8>>> =
- try_with_context!(context, source.as_buffer(context)).clone();
- let index = try_with_context!(context, index.as_integer(context));
- let num_bits = try_with_context!(context, num_bits.as_integer(context));
- try_with_context!(
- context,
- context.namespace.add_value_at_resolved_path(
- name,
- &context.current_scope,
- AmlValue::BufferField { buffer_data: source_data, offset: index, length: num_bits }
- )
- );
- (Ok(()), context)
- },
- ),
- ))
- .discard_result()
- }
- pub fn def_op_region<'a, 'c>() -> impl Parser<'a, 'c, ()>
- where
- 'c: 'a,
- {
- /*
- * DefOpRegion := ExtOpPrefix 0x80 NameString RegionSpace RegionOffset RegionLen
- * RegionSpace := ByteData (where 0x00 = SystemMemory
- * 0x01 = SystemIO
- * 0x02 = PciConfig
- * 0x03 = EmbeddedControl
- * 0x04 = SMBus
- * 0x05 = SystemCMOS
- * 0x06 = PciBarTarget
- * 0x07 = IPMI
- * 0x08 = GeneralPurposeIO
- * 0x09 = GenericSerialBus
- * 0x80-0xff = OEM Defined)
- * ByteData := 0x00 - 0xff
- * RegionOffset := TermArg => Integer
- * RegionLen := TermArg => Integer
- */
- ext_opcode(opcode::EXT_DEF_OP_REGION_OP)
- .then(comment_scope(
- DebugVerbosity::Scopes,
- "DefOpRegion",
- name_string().then(take()).then(term_arg()).then(term_arg()).map_with_context(
- |(((name, space), offset), length), context| {
- let region = match space {
- 0x00 => RegionSpace::SystemMemory,
- 0x01 => RegionSpace::SystemIo,
- 0x02 => RegionSpace::PciConfig,
- 0x03 => RegionSpace::EmbeddedControl,
- 0x04 => RegionSpace::SMBus,
- 0x05 => RegionSpace::SystemCmos,
- 0x06 => RegionSpace::PciBarTarget,
- 0x07 => RegionSpace::IPMI,
- 0x08 => RegionSpace::GeneralPurposeIo,
- 0x09 => RegionSpace::GenericSerialBus,
- space @ 0x80..=0xff => RegionSpace::OemDefined(space),
- byte => return (Err(Propagate::Err(AmlError::InvalidRegionSpace(byte))), context),
- };
- let offset = match offset.as_integer(context) {
- Ok(offset) => offset,
- Err(err) => return (Err(Propagate::Err(err)), context),
- };
- let length = match length.as_integer(context) {
- Ok(length) => length,
- Err(err) => return (Err(Propagate::Err(err)), context),
- };
- let parent_device = match region {
- RegionSpace::PciConfig | RegionSpace::IPMI | RegionSpace::GenericSerialBus => {
- let resolved_path = try_with_context!(context, name.resolve(&context.current_scope));
- Some(try_with_context!(context, resolved_path.parent()))
- }
- _ => None,
- };
- try_with_context!(
- context,
- context.namespace.add_value_at_resolved_path(
- name,
- &context.current_scope,
- AmlValue::OpRegion { region, offset, length, parent_device }
- )
- );
- (Ok(()), context)
- },
- ),
- ))
- .discard_result()
- }
- pub fn def_field<'a, 'c>() -> impl Parser<'a, 'c, ()>
- where
- 'c: 'a,
- {
- /*
- * DefField = ExtOpPrefix 0x81 PkgLength NameString FieldFlags FieldList
- * FieldFlags := ByteData
- */
- let opregion_as_handle = name_string().map_with_context(|region_name, context| {
- /*
- * We search for the opregion that this field is referencing here as we already have the correct starting
- * scope. If we leave this to later, it becomes much harder as we also need to know the field's scope.
- */
- let (_, handle) =
- try_with_context!(context, context.namespace.search(®ion_name, &context.current_scope));
- (Ok(handle), context)
- });
- ext_opcode(opcode::EXT_DEF_FIELD_OP)
- .then(comment_scope(
- DebugVerbosity::Scopes,
- "DefField",
- pkg_length().then(opregion_as_handle).then(take()).feed(|((list_length, region_handle), flags)| {
- move |mut input: &'a [u8], mut context: &'c mut AmlContext| -> ParseResult<'a, 'c, ()> {
- /*
- * FieldList := Nothing | <FieldElement FieldList>
- */
- // TODO: can this pattern be expressed as a combinator
- let mut current_offset = 0;
- while list_length.still_parsing(input) {
- let (new_input, new_context, field_length) =
- field_element(region_handle, FieldFlags::new(flags), current_offset)
- .parse(input, context)?;
- input = new_input;
- context = new_context;
- current_offset += field_length;
- }
- Ok((input, context, ()))
- }
- }),
- ))
- .discard_result()
- }
- /// Parses a `FieldElement`. Takes the current offset within the field list, and returns the length
- /// of the field element parsed.
- pub fn field_element<'a, 'c>(
- region_handle: AmlHandle,
- flags: FieldFlags,
- current_offset: u64,
- ) -> impl Parser<'a, 'c, u64>
- where
- 'c: 'a,
- {
- /*
- * FieldElement := NamedField | ReservedField | AccessField | ExtendedAccessField |
- * ConnectField
- * NamedField := NameSeg PkgLength
- * ReservedField := 0x00 PkgLength
- * AccessField := 0x01 AccessType AccessAttrib
- * ConnectField := <0x02 NameString> | <0x02 BufferData>
- * ExtendedAccessField := 0x03 AccessType ExtendedAccessAttrib AccessLength
- *
- * AccessType := ByteData
- * AccessAttrib := ByteData
- *
- * XXX: The spec says a ConnectField can be <0x02 BufferData>, but BufferData isn't an AML
- * object (it seems to be defined in ASL). We treat BufferData as if it was encoded like
- * DefBuffer, and this seems to work so far.
- */
- // TODO: parse ConnectField and ExtendedAccessField
- /*
- * Reserved fields shouldn't actually be added to the namespace; they seem to show gaps in
- * the operation region that aren't used for anything.
- */
- let reserved_field = opcode(opcode::RESERVED_FIELD)
- .then(region_pkg_length(region_handle))
- .map(|((), length)| Ok(length.raw_length as u64));
- // TODO: work out what to do with an access field
- // let access_field = opcode(opcode::ACCESS_FIELD)
- // .then(take())
- // .then(take())
- // .map_with_context(|(((), access_type), access_attrib), context| (Ok( , context));
- // TODO: fields' start and end offsets need to be checked against their enclosing
- // OperationRegions to make sure they don't sit outside or cross the boundary.
- // This might not be a problem if a sane ASL compiler is used (which should check this
- // at compile-time), but it's better to be safe and validate that as well.
- let named_field =
- name_seg().then(region_pkg_length(region_handle)).map_with_context(move |(name_seg, length), context| {
- try_with_context!(
- context,
- context.namespace.add_value_at_resolved_path(
- AmlName::from_name_seg(name_seg),
- &context.current_scope,
- AmlValue::Field {
- region: region_handle,
- flags,
- offset: current_offset,
- length: length.raw_length as u64,
- },
- )
- );
- (Ok(length.raw_length as u64), context)
- });
- choice!(reserved_field, named_field)
- }
- pub fn def_method<'a, 'c>() -> impl Parser<'a, 'c, ()>
- where
- 'c: 'a,
- {
- /*
- * DefMethod := 0x14 PkgLength NameString MethodFlags TermList
- * MethodFlags := ByteData (where bits 0-2: ArgCount (0 to 7)
- * bit 3: SerializeFlag (0 = Not Serialized, 1 = Serialized)
- * bits 4-7: SyncLevel (0x00 to 0x0f))
- */
- opcode(opcode::DEF_METHOD_OP)
- .then(comment_scope(
- DebugVerbosity::Scopes,
- "DefMethod",
- pkg_length()
- .then(name_string())
- .then(take())
- .feed(|((length, name), flags)| {
- take_to_end_of_pkglength(length).map(move |code| Ok((name.clone(), flags, code)))
- })
- .map_with_context(|(name, flags, code), context| {
- try_with_context!(
- context,
- context.namespace.add_value_at_resolved_path(
- name,
- &context.current_scope,
- AmlValue::Method {
- flags: MethodFlags::from(flags),
- code: MethodCode::Aml(code.to_vec())
- },
- )
- );
- (Ok(()), context)
- }),
- ))
- .discard_result()
- }
- pub fn def_external<'a, 'c>() -> impl Parser<'a, 'c, ()>
- where
- 'c: 'a,
- {
- /*
- * DefExternal = 0x15 NameString ObjectType ArgumentCount
- * ObjectType := ByteData
- * ArgumentCount := ByteData (0 to 7)
- */
- opcode(opcode::DEF_EXTERNAL_OP)
- .then(comment_scope(DebugVerbosity::Scopes, "DefExternal", name_string().then(take()).then(take())))
- .discard_result()
- }
- pub fn def_device<'a, 'c>() -> impl Parser<'a, 'c, ()>
- where
- 'c: 'a,
- {
- /*
- * DefDevice := ExtOpPrefix 0x82 PkgLength NameString TermList
- */
- ext_opcode(opcode::EXT_DEF_DEVICE_OP)
- .then(comment_scope(
- DebugVerbosity::Scopes,
- "DefDevice",
- pkg_length()
- .then(name_string())
- .map_with_context(|(length, name), context| {
- let resolved_name = try_with_context!(context, name.resolve(&context.current_scope));
- try_with_context!(
- context,
- context.namespace.add_value(resolved_name.clone(), AmlValue::Device)
- );
- try_with_context!(
- context,
- context.namespace.add_level(resolved_name.clone(), LevelType::Device)
- );
- let previous_scope = context.current_scope.clone();
- context.current_scope = resolved_name;
- (Ok((length, previous_scope)), context)
- })
- .feed(|(length, previous_scope)| term_list(length).map(move |_| Ok(previous_scope.clone())))
- .map_with_context(|previous_scope, context| {
- context.current_scope = previous_scope;
- (Ok(()), context)
- }),
- ))
- .discard_result()
- }
- pub fn def_processor<'a, 'c>() -> impl Parser<'a, 'c, ()>
- where
- 'c: 'a,
- {
- /*
- * DefProcessor := ExtOpPrefix 0x83 PkgLength NameString ProcID PblkAddress PblkLen TermList
- * ProcID := ByteData
- * PblkAddress := DWordData
- * PblkLen := ByteData
- */
- ext_opcode(opcode::EXT_DEF_PROCESSOR_OP)
- .then(comment_scope(
- DebugVerbosity::Scopes,
- "DefProcessor",
- pkg_length()
- .then(name_string())
- .then(take())
- .then(take_u32())
- .then(take())
- .map_with_context(|((((pkg_length, name), proc_id), pblk_address), pblk_len), context| {
- /*
- * Legacy `Processor` objects contain data within themselves, and can also have sub-objects,
- * so we add both a level for the sub-objects, and a value for the data.
- */
- let resolved_name = try_with_context!(context, name.resolve(&context.current_scope));
- try_with_context!(
- context,
- context.namespace.add_level(resolved_name.clone(), LevelType::Processor)
- );
- try_with_context!(
- context,
- context.namespace.add_value(
- resolved_name.clone(),
- AmlValue::Processor { id: proc_id, pblk_address, pblk_len }
- )
- );
- let previous_scope = context.current_scope.clone();
- context.current_scope = resolved_name;
- (Ok((previous_scope, pkg_length)), context)
- })
- .feed(move |(previous_scope, pkg_length)| {
- term_list(pkg_length).map(move |_| Ok(previous_scope.clone()))
- })
- .map_with_context(|previous_scope, context| {
- context.current_scope = previous_scope;
- (Ok(()), context)
- }),
- ))
- .discard_result()
- }
- pub fn def_power_res<'a, 'c>() -> impl Parser<'a, 'c, ()>
- where
- 'c: 'a,
- {
- /*
- * DefPowerRes := ExtOpPrefix 0x84 PkgLength NameString SystemLevel ResourceOrder TermList
- * SystemLevel := ByteData
- * ResourceOrder := WordData
- */
- ext_opcode(opcode::EXT_DEF_POWER_RES_OP)
- .then(comment_scope(
- DebugVerbosity::Scopes,
- "DefPowerRes",
- pkg_length()
- .then(name_string())
- .then(take())
- .then(take_u16())
- .map_with_context(|(((pkg_length, name), system_level), resource_order), context| {
- /*
- * `PowerResource` objects contain data within themselves, and can also have sub-objects,
- * so we add both a level for the sub-objects, and a value for the data.
- */
- let resolved_name = try_with_context!(context, name.resolve(&context.current_scope));
- try_with_context!(
- context,
- context.namespace.add_level(resolved_name.clone(), LevelType::PowerResource)
- );
- try_with_context!(
- context,
- context.namespace.add_value(
- resolved_name.clone(),
- AmlValue::PowerResource { system_level, resource_order }
- )
- );
- let previous_scope = context.current_scope.clone();
- context.current_scope = resolved_name;
- (Ok((previous_scope, pkg_length)), context)
- })
- .feed(move |(previous_scope, pkg_length)| {
- term_list(pkg_length).map(move |_| Ok(previous_scope.clone()))
- })
- .map_with_context(|previous_scope, context| {
- context.current_scope = previous_scope;
- (Ok(()), context)
- }),
- ))
- .discard_result()
- }
- pub fn def_thermal_zone<'a, 'c>() -> impl Parser<'a, 'c, ()>
- where
- 'c: 'a,
- {
- /*
- * DefThermalZone := ExtOpPrefix 0x85 PkgLength NameString TermList
- * TODO: we use this pattern a lot (move into scope, parse a term_list, move back out). Could we simplify into
- * just a `feed` by passing a scope into term_list?
- */
- ext_opcode(opcode::EXT_DEF_THERMAL_ZONE_OP)
- .then(comment_scope(
- DebugVerbosity::Scopes,
- "DefThermalZone",
- pkg_length()
- .then(name_string())
- .map_with_context(|(pkg_length, name), context| {
- let resolved_name = try_with_context!(context, name.resolve(&context.current_scope));
- try_with_context!(
- context,
- context.namespace.add_value(resolved_name.clone(), AmlValue::ThermalZone)
- );
- try_with_context!(
- context,
- context.namespace.add_level(resolved_name.clone(), LevelType::ThermalZone)
- );
- let previous_scope = context.current_scope.clone();
- context.current_scope = resolved_name;
- (Ok((pkg_length, previous_scope)), context)
- })
- .feed(|(length, previous_scope)| term_list(length).map(move |_| Ok(previous_scope.clone())))
- .map_with_context(|previous_scope, context| {
- context.current_scope = previous_scope;
- (Ok(()), context)
- }),
- ))
- .discard_result()
- }
- pub fn def_mutex<'a, 'c>() -> impl Parser<'a, 'c, ()>
- where
- 'c: 'a,
- {
- /*
- * DefMutex := ExtOpPrefix 0x01 NameString SyncFlags
- * SyncFlags := ByteData (where bits 0-3: SyncLevel
- * bits 4-7: Reserved)
- */
- ext_opcode(opcode::EXT_DEF_MUTEX_OP)
- .then(comment_scope(
- DebugVerbosity::Scopes,
- "DefMutex",
- name_string().then(take()).map_with_context(|(name, sync_level), context| {
- try_with_context!(
- context,
- context.namespace.add_value_at_resolved_path(
- name,
- &context.current_scope,
- AmlValue::Mutex { sync_level }
- )
- );
- (Ok(()), context)
- }),
- ))
- .discard_result()
- }
- pub fn def_cond_ref_of<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
- where
- 'c: 'a,
- {
- /*
- * DefCondRefOf := ExtOpPrefix 0x12 NameString Target => boolean
- */
- ext_opcode(opcode::EXT_DEF_COND_REF_OF_OP)
- .then(comment_scope(
- DebugVerbosity::Scopes,
- "DefCondRefOf",
- name_string().then(target()).map_with_context(|(source, target), context| {
- let handle = context.namespace.search(&source, &context.current_scope);
- let result = AmlValue::Boolean(handle.is_ok());
- if let Ok((_name, _handle)) = handle {
- match target {
- Target::Null => { /* just return the result of the check */ }
- _ => return (Err(Propagate::Err(AmlError::Unimplemented)), context),
- }
- }
- (Ok(result), context)
- }),
- ))
- .map(|((), result)| Ok(result))
- }
- pub fn term_arg<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
- where
- 'c: 'a,
- {
- /*
- * TermArg := ExpressionOpcode | DataObject | ArgObj | LocalObj
- */
- comment_scope(
- DebugVerbosity::AllScopes,
- "TermArg",
- choice!(
- data_object(),
- arg_obj().map_with_context(|arg_num, context| {
- (Ok(try_with_context!(context, context.current_arg(arg_num)).clone()), context)
- }),
- local_obj().map_with_context(|local_num, context| {
- (Ok(try_with_context!(context, context.local(local_num)).clone()), context)
- }),
- expression_opcode()
- ),
- )
- }
- pub fn data_ref_object<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
- where
- 'c: 'a,
- {
- /*
- * DataRefObject := DataObject | ObjectReference | DDBHandle
- */
- comment_scope(DebugVerbosity::AllScopes, "DataRefObject", choice!(data_object()))
- }
- pub fn data_object<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
- where
- 'c: 'a,
- {
- /*
- * DataObject := DefPackage | DefVarPackage | ComputationalData
- *
- * The order of the parsers are important here, as DefPackage and DefVarPackage can be
- * accidently parsed as ComputationalDatas.
- */
- // TODO: this doesn't yet parse DefVarPackage
- comment_scope(DebugVerbosity::AllScopes, "DataObject", choice!(def_package(), computational_data()))
- }
- pub fn computational_data<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
- where
- 'c: 'a,
- {
- /*
- * ComputationalData := ByteConst | WordConst | DWordConst | QWordConst | String |
- * ConstObj | RevisionOp | DefBuffer
- * ByteConst := 0x0a ByteData
- * WordConst := 0x0b WordData
- * DWordConst := 0x0c DWordData
- * QWordConst := 0x0e QWordData
- * String := 0x0d AsciiCharList NullChar
- * ConstObj := ZeroOp(0x00) | OneOp(0x01) | OnesOp(0xff)
- * RevisionOp := ExtOpPrefix(0x5b) 0x30
- */
- let const_parser = |input: &'a [u8], context: &'c mut AmlContext| {
- let string_parser = |input: &'a [u8], context| -> ParseResult<'a, 'c, AmlValue> {
- /*
- * Using `position` isn't very efficient here, but is probably fine because the
- * strings are usually quite short.
- */
- let nul_position = match input.iter().position(|&c| c == b'\0') {
- Some(position) => position,
- None => return Err((input, context, Propagate::Err(AmlError::UnterminatedStringConstant))),
- };
- let string = String::from(match str::from_utf8(&input[0..nul_position]) {
- Ok(string) => string,
- Err(_) => return Err((input, context, Propagate::Err(AmlError::InvalidStringConstant))),
- });
- Ok((&input[(nul_position + 1)..], context, AmlValue::String(string)))
- };
- let (new_input, context, op) = take().parse(input, context)?;
- match op {
- opcode::BYTE_CONST => {
- take().map(|value| Ok(AmlValue::Integer(value as u64))).parse(new_input, context)
- }
- opcode::WORD_CONST => {
- take_u16().map(|value| Ok(AmlValue::Integer(value as u64))).parse(new_input, context)
- }
- opcode::DWORD_CONST => {
- take_u32().map(|value| Ok(AmlValue::Integer(value as u64))).parse(new_input, context)
- }
- opcode::QWORD_CONST => take_u64().map(|value| Ok(AmlValue::Integer(value))).parse(new_input, context),
- opcode::STRING_PREFIX => string_parser.parse(new_input, context),
- opcode::ZERO_OP => Ok((new_input, context, AmlValue::zero())),
- opcode::ONE_OP => Ok((new_input, context, AmlValue::one())),
- opcode::ONES_OP => Ok((new_input, context, AmlValue::ones())),
- _ => Err((input, context, Propagate::Err(AmlError::WrongParser))),
- }
- };
- comment_scope(
- DebugVerbosity::AllScopes,
- "ComputationalData",
- choice!(
- ext_opcode(opcode::EXT_REVISION_OP).map(|_| Ok(AmlValue::Integer(crate::AML_INTERPRETER_REVISION))),
- const_parser,
- def_buffer()
- ),
- )
- }
- #[cfg(test)]
- mod test {
- use super::*;
- use crate::test_utils::*;
- #[test]
- fn test_package() {
- let mut context = make_test_context();
- // The tests also check that DefPackage consumes no more input than required
- // Empty DefPackage
- check_ok_value!(
- def_package().parse(&[0x12, 0x02, 0x00, 0x12, 0x34], &mut context),
- AmlValue::Package(Vec::new()),
- &[0x12, 0x34]
- );
- // DefPackage where NumElements == package_content.len()
- check_ok_value!(
- def_package()
- .parse(&[0x12, 0x09, 0x04, 0x01, 0x0A, 0x02, 0x0A, 0x03, 0x0A, 0x04, 0x12, 0x34], &mut context),
- AmlValue::Package(alloc::vec![
- AmlValue::Integer(1),
- AmlValue::Integer(2),
- AmlValue::Integer(3),
- AmlValue::Integer(4)
- ]),
- &[0x12, 0x34]
- );
- // DefPackage where NumElements > package_content.len()
- check_ok_value!(
- def_package().parse(&[0x012, 0x05, 0x04, 0x01, 0x0A, 0x02, 0x12, 0x34], &mut context),
- AmlValue::Package(alloc::vec![
- AmlValue::Integer(1),
- AmlValue::Integer(2),
- AmlValue::Uninitialized,
- AmlValue::Uninitialized,
- ]),
- &[0x12, 0x34]
- );
- }
- #[test]
- fn test_computational_data() {
- let mut context = make_test_context();
- check_ok_value!(
- computational_data().parse(&[0x00, 0x34, 0x12], &mut context),
- AmlValue::Integer(0),
- &[0x34, 0x12]
- );
- check_ok_value!(
- computational_data().parse(&[0x01, 0x18, 0xf3], &mut context),
- AmlValue::Integer(1),
- &[0x18, 0xf3]
- );
- check_ok_value!(
- computational_data().parse(&[0xff, 0x98, 0xc3], &mut context),
- AmlValue::Integer(u64::max_value()),
- &[0x98, 0xc3]
- );
- check_ok_value!(
- computational_data().parse(&[0x5b, 0x30], &mut context),
- AmlValue::Integer(crate::AML_INTERPRETER_REVISION),
- &[]
- );
- check_ok_value!(
- computational_data().parse(&[0x0a, 0xf3, 0x35], &mut context),
- AmlValue::Integer(0xf3),
- &[0x35]
- );
- check_ok_value!(
- computational_data().parse(&[0x0b, 0xf3, 0x35], &mut context),
- AmlValue::Integer(0x35f3),
- &[]
- );
- check_ok_value!(
- computational_data().parse(&[0x0c, 0xf3, 0x35, 0x12, 0x65, 0xff, 0x00], &mut context),
- AmlValue::Integer(0x651235f3),
- &[0xff, 0x00]
- );
- check_ok_value!(
- computational_data()
- .parse(&[0x0e, 0xf3, 0x35, 0x12, 0x65, 0xff, 0x00, 0x67, 0xde, 0x28], &mut context),
- AmlValue::Integer(0xde6700ff651235f3),
- &[0x28]
- );
- check_ok_value!(
- computational_data().parse(&[0x0d, b'A', b'B', b'C', b'D', b'\0', 0xff, 0xf5], &mut context),
- AmlValue::String(String::from("ABCD")),
- &[0xff, 0xf5]
- );
- }
- }
|