2
0

term_object.rs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  1. use crate::{
  2. misc::{arg_obj, local_obj},
  3. name_object::{name_seg, name_string},
  4. namespace::{AmlName, LevelType},
  5. opcode::{self, ext_opcode, opcode},
  6. parser::{
  7. choice,
  8. comment_scope,
  9. make_parser_concrete,
  10. take,
  11. take_to_end_of_pkglength,
  12. take_u16,
  13. take_u32,
  14. take_u64,
  15. try_with_context,
  16. ParseResult,
  17. Parser,
  18. Propagate,
  19. },
  20. pkg_length::{pkg_length, PkgLength},
  21. type1::type1_opcode,
  22. type2::{def_buffer, def_package, type2_opcode},
  23. value::{AmlValue, FieldFlags, MethodCode, MethodFlags, RegionSpace},
  24. AmlContext,
  25. AmlError,
  26. AmlHandle,
  27. DebugVerbosity,
  28. };
  29. use alloc::string::String;
  30. use core::str;
  31. /// `TermList`s are usually found within explicit-length objects (so they have a `PkgLength`
  32. /// elsewhere in the structure), so this takes a number of bytes to parse.
  33. pub fn term_list<'a, 'c>(list_length: PkgLength) -> impl Parser<'a, 'c, ()>
  34. where
  35. 'c: 'a,
  36. {
  37. /*
  38. * TermList := Nothing | <TermObj TermList>
  39. */
  40. // TODO: why does this use still_parsing, instead of just taking the whole thing and parsing it til it's empty?
  41. move |mut input: &'a [u8], mut context: &'c mut AmlContext| {
  42. while list_length.still_parsing(input) {
  43. // TODO: currently, we ignore the value of the expression. We may need to propagate
  44. // this.
  45. let (new_input, new_context, _) = term_object().parse(input, context)?;
  46. input = new_input;
  47. context = new_context;
  48. }
  49. Ok((input, context, ()))
  50. }
  51. }
  52. pub fn term_object<'a, 'c>() -> impl Parser<'a, 'c, Option<AmlValue>>
  53. where
  54. 'c: 'a,
  55. {
  56. /*
  57. * TermObj := NamespaceModifierObj | NamedObj | Type1Opcode | Type2Opcode
  58. */
  59. comment_scope(
  60. DebugVerbosity::AllScopes,
  61. "TermObj",
  62. choice!(
  63. namespace_modifier().map(|()| Ok(None)),
  64. named_obj().map(|()| Ok(None)),
  65. type1_opcode().map(|()| Ok(None)),
  66. type2_opcode().map(|value| Ok(Some(value)))
  67. ),
  68. )
  69. }
  70. pub fn namespace_modifier<'a, 'c>() -> impl Parser<'a, 'c, ()>
  71. where
  72. 'c: 'a,
  73. {
  74. /*
  75. * NamespaceModifierObj := DefAlias | DefName | DefScope
  76. */
  77. choice!(def_name(), def_scope())
  78. }
  79. pub fn named_obj<'a, 'c>() -> impl Parser<'a, 'c, ()>
  80. where
  81. 'c: 'a,
  82. {
  83. /*
  84. * NamedObj := DefBankField | DefCreateBitField | DefCreateByteField | DefCreateDWordField |
  85. * DefCreateField | DefCreateQWordField | DefCreateWordField | DefDataRegion |
  86. * DefExternal | DefOpRegion | DefPowerRes | DefProcessor | DefThermalZone |
  87. * DefMethod | DefMutex
  88. *
  89. * XXX: DefMethod and DefMutex (at least) are not included in any rule in the AML grammar,
  90. * but are defined in the NamedObj section so we assume they're part of NamedObj
  91. */
  92. comment_scope(
  93. DebugVerbosity::AllScopes,
  94. "NamedObj",
  95. choice!(
  96. def_op_region(),
  97. def_field(),
  98. def_method(),
  99. def_device(),
  100. def_processor(),
  101. def_power_res(),
  102. def_thermal_zone(),
  103. def_mutex()
  104. ),
  105. )
  106. }
  107. pub fn def_name<'a, 'c>() -> impl Parser<'a, 'c, ()>
  108. where
  109. 'c: 'a,
  110. {
  111. /*
  112. * DefName := 0x08 NameString DataRefObject
  113. */
  114. opcode(opcode::DEF_NAME_OP)
  115. .then(comment_scope(
  116. DebugVerbosity::Scopes,
  117. "DefName",
  118. name_string().then(data_ref_object()).map_with_context(|(name, data_ref_object), context| {
  119. try_with_context!(
  120. context,
  121. context.namespace.add_value_at_resolved_path(name, &context.current_scope, data_ref_object)
  122. );
  123. (Ok(()), context)
  124. }),
  125. ))
  126. .discard_result()
  127. }
  128. pub fn def_scope<'a, 'c>() -> impl Parser<'a, 'c, ()>
  129. where
  130. 'c: 'a,
  131. {
  132. /*
  133. * DefScope := 0x10 PkgLength NameString TermList
  134. */
  135. opcode(opcode::DEF_SCOPE_OP)
  136. .then(comment_scope(
  137. DebugVerbosity::Scopes,
  138. "DefScope",
  139. pkg_length()
  140. .then(name_string())
  141. .map_with_context(|(length, name), context| {
  142. let previous_scope = context.current_scope.clone();
  143. context.current_scope = try_with_context!(context, name.resolve(&context.current_scope));
  144. context.comment(
  145. DebugVerbosity::Scopes,
  146. &(String::from("Scope name: ") + &context.current_scope.as_string()),
  147. );
  148. try_with_context!(
  149. context,
  150. context.namespace.add_level(context.current_scope.clone(), LevelType::Scope)
  151. );
  152. (Ok((length, previous_scope)), context)
  153. })
  154. .feed(|(pkg_length, previous_scope)| {
  155. term_list(pkg_length).map(move |_| Ok(previous_scope.clone()))
  156. })
  157. .map_with_context(|previous_scope, context| {
  158. context.current_scope = previous_scope;
  159. (Ok(()), context)
  160. }),
  161. ))
  162. .discard_result()
  163. }
  164. pub fn def_op_region<'a, 'c>() -> impl Parser<'a, 'c, ()>
  165. where
  166. 'c: 'a,
  167. {
  168. /*
  169. * DefOpRegion := ExtOpPrefix 0x80 NameString RegionSpace RegionOffset RegionLen
  170. * RegionSpace := ByteData (where 0x00 = SystemMemory
  171. * 0x01 = SystemIO
  172. * 0x02 = PciConfig
  173. * 0x03 = EmbeddedControl
  174. * 0x04 = SMBus
  175. * 0x05 = SystemCMOS
  176. * 0x06 = PciBarTarget
  177. * 0x07 = IPMI
  178. * 0x08 = GeneralPurposeIO
  179. * 0x09 = GenericSerialBus
  180. * 0x80-0xff = OEM Defined)
  181. * ByteData := 0x00 - 0xff
  182. * RegionOffset := TermArg => Integer
  183. * RegionLen := TermArg => Integer
  184. */
  185. ext_opcode(opcode::EXT_DEF_OP_REGION_OP)
  186. .then(comment_scope(
  187. DebugVerbosity::Scopes,
  188. "DefOpRegion",
  189. name_string().then(take()).then(term_arg()).then(term_arg()).map_with_context(
  190. |(((name, space), offset), length), context| {
  191. let region = match space {
  192. 0x00 => RegionSpace::SystemMemory,
  193. 0x01 => RegionSpace::SystemIo,
  194. 0x02 => RegionSpace::PciConfig,
  195. 0x03 => RegionSpace::EmbeddedControl,
  196. 0x04 => RegionSpace::SMBus,
  197. 0x05 => RegionSpace::SystemCmos,
  198. 0x06 => RegionSpace::PciBarTarget,
  199. 0x07 => RegionSpace::IPMI,
  200. 0x08 => RegionSpace::GeneralPurposeIo,
  201. 0x09 => RegionSpace::GenericSerialBus,
  202. space @ 0x80..=0xff => RegionSpace::OemDefined(space),
  203. byte => return (Err(Propagate::Err(AmlError::InvalidRegionSpace(byte))), context),
  204. };
  205. let offset = match offset.as_integer(context) {
  206. Ok(offset) => offset,
  207. Err(err) => return (Err(Propagate::Err(err)), context),
  208. };
  209. let length = match length.as_integer(context) {
  210. Ok(length) => length,
  211. Err(err) => return (Err(Propagate::Err(err)), context),
  212. };
  213. let parent_device = match region {
  214. RegionSpace::PciConfig | RegionSpace::IPMI | RegionSpace::GenericSerialBus => {
  215. let resolved_path = try_with_context!(context, name.resolve(&context.current_scope));
  216. Some(try_with_context!(context, resolved_path.parent()))
  217. }
  218. _ => None,
  219. };
  220. try_with_context!(
  221. context,
  222. context.namespace.add_value_at_resolved_path(
  223. name,
  224. &context.current_scope,
  225. AmlValue::OpRegion { region, offset, length, parent_device }
  226. )
  227. );
  228. (Ok(()), context)
  229. },
  230. ),
  231. ))
  232. .discard_result()
  233. }
  234. pub fn def_field<'a, 'c>() -> impl Parser<'a, 'c, ()>
  235. where
  236. 'c: 'a,
  237. {
  238. /*
  239. * DefField = ExtOpPrefix 0x81 PkgLength NameString FieldFlags FieldList
  240. * FieldFlags := ByteData
  241. */
  242. let opregion_as_handle = name_string().map_with_context(|region_name, context| {
  243. /*
  244. * We search for the opregion that this field is referencing here as we already have the correct starting
  245. * scope. If we leave this to later, it becomes much harder as we also need to know the field's scope.
  246. */
  247. let (_, handle) =
  248. try_with_context!(context, context.namespace.search(&region_name, &context.current_scope));
  249. (Ok(handle), context)
  250. });
  251. ext_opcode(opcode::EXT_DEF_FIELD_OP)
  252. .then(comment_scope(
  253. DebugVerbosity::Scopes,
  254. "DefField",
  255. pkg_length().then(opregion_as_handle).then(take()).feed(|((list_length, region_handle), flags)| {
  256. move |mut input: &'a [u8], mut context: &'c mut AmlContext| -> ParseResult<'a, 'c, ()> {
  257. /*
  258. * FieldList := Nothing | <FieldElement FieldList>
  259. */
  260. // TODO: can this pattern be expressed as a combinator
  261. let mut current_offset = 0;
  262. while list_length.still_parsing(input) {
  263. let (new_input, new_context, field_length) =
  264. field_element(region_handle, FieldFlags::new(flags), current_offset)
  265. .parse(input, context)?;
  266. input = new_input;
  267. context = new_context;
  268. current_offset += field_length;
  269. }
  270. Ok((input, context, ()))
  271. }
  272. }),
  273. ))
  274. .discard_result()
  275. }
  276. /// Parses a `FieldElement`. Takes the current offset within the field list, and returns the length
  277. /// of the field element parsed.
  278. pub fn field_element<'a, 'c>(
  279. region_handle: AmlHandle,
  280. flags: FieldFlags,
  281. current_offset: u64,
  282. ) -> impl Parser<'a, 'c, u64>
  283. where
  284. 'c: 'a,
  285. {
  286. /*
  287. * FieldElement := NamedField | ReservedField | AccessField | ExtendedAccessField |
  288. * ConnectField
  289. * NamedField := NameSeg PkgLength
  290. * ReservedField := 0x00 PkgLength
  291. * AccessField := 0x01 AccessType AccessAttrib
  292. * ConnectField := <0x02 NameString> | <0x02 BufferData>
  293. * ExtendedAccessField := 0x03 AccessType ExtendedAccessAttrib AccessLength
  294. *
  295. * AccessType := ByteData
  296. * AccessAttrib := ByteData
  297. *
  298. * XXX: The spec says a ConnectField can be <0x02 BufferData>, but BufferData isn't an AML
  299. * object (it seems to be defined in ASL). We treat BufferData as if it was encoded like
  300. * DefBuffer, and this seems to work so far.
  301. */
  302. // TODO: parse ConnectField and ExtendedAccessField
  303. /*
  304. * Reserved fields shouldn't actually be added to the namespace; they seem to show gaps in
  305. * the operation region that aren't used for anything.
  306. */
  307. let reserved_field =
  308. opcode(opcode::RESERVED_FIELD).then(pkg_length()).map(|((), length)| Ok(length.raw_length as u64));
  309. // TODO: work out what to do with an access field
  310. // let access_field = opcode(opcode::ACCESS_FIELD)
  311. // .then(take())
  312. // .then(take())
  313. // .map_with_context(|(((), access_type), access_attrib), context| (Ok( , context));
  314. let named_field = name_seg().then(pkg_length()).map_with_context(move |(name_seg, length), context| {
  315. try_with_context!(
  316. context,
  317. context.namespace.add_value_at_resolved_path(
  318. AmlName::from_name_seg(name_seg),
  319. &context.current_scope,
  320. AmlValue::Field {
  321. region: region_handle,
  322. flags,
  323. offset: current_offset,
  324. length: length.raw_length as u64,
  325. },
  326. )
  327. );
  328. (Ok(length.raw_length as u64), context)
  329. });
  330. choice!(reserved_field, named_field)
  331. }
  332. pub fn def_method<'a, 'c>() -> impl Parser<'a, 'c, ()>
  333. where
  334. 'c: 'a,
  335. {
  336. /*
  337. * DefMethod := 0x14 PkgLength NameString MethodFlags TermList
  338. * MethodFlags := ByteData (where bits 0-2: ArgCount (0 to 7)
  339. * bit 3: SerializeFlag (0 = Not Serialized, 1 = Serialized)
  340. * bits 4-7: SyncLevel (0x00 to 0x0f))
  341. */
  342. opcode(opcode::DEF_METHOD_OP)
  343. .then(comment_scope(
  344. DebugVerbosity::Scopes,
  345. "DefMethod",
  346. pkg_length()
  347. .then(name_string())
  348. .then(take())
  349. .feed(|((length, name), flags)| {
  350. take_to_end_of_pkglength(length).map(move |code| Ok((name.clone(), flags, code)))
  351. })
  352. .map_with_context(|(name, flags, code), context| {
  353. try_with_context!(
  354. context,
  355. context.namespace.add_value_at_resolved_path(
  356. name,
  357. &context.current_scope,
  358. AmlValue::Method {
  359. flags: MethodFlags::from(flags),
  360. code: MethodCode::Aml(code.to_vec())
  361. },
  362. )
  363. );
  364. (Ok(()), context)
  365. }),
  366. ))
  367. .discard_result()
  368. }
  369. pub fn def_device<'a, 'c>() -> impl Parser<'a, 'c, ()>
  370. where
  371. 'c: 'a,
  372. {
  373. /*
  374. * DefDevice := ExtOpPrefix 0x82 PkgLength NameString TermList
  375. */
  376. ext_opcode(opcode::EXT_DEF_DEVICE_OP)
  377. .then(comment_scope(
  378. DebugVerbosity::Scopes,
  379. "DefDevice",
  380. pkg_length()
  381. .then(name_string())
  382. .map_with_context(|(length, name), context| {
  383. let resolved_name = try_with_context!(context, name.resolve(&context.current_scope));
  384. try_with_context!(
  385. context,
  386. context.namespace.add_level(resolved_name.clone(), LevelType::Device)
  387. );
  388. let previous_scope = context.current_scope.clone();
  389. context.current_scope = resolved_name;
  390. (Ok((length, previous_scope)), context)
  391. })
  392. .feed(|(length, previous_scope)| term_list(length).map(move |_| Ok(previous_scope.clone())))
  393. .map_with_context(|previous_scope, context| {
  394. context.current_scope = previous_scope;
  395. (Ok(()), context)
  396. }),
  397. ))
  398. .discard_result()
  399. }
  400. pub fn def_processor<'a, 'c>() -> impl Parser<'a, 'c, ()>
  401. where
  402. 'c: 'a,
  403. {
  404. /*
  405. * DefProcessor := ExtOpPrefix 0x83 PkgLength NameString ProcID PblkAddress PblkLen TermList
  406. * ProcID := ByteData
  407. * PblkAddress := DWordData
  408. * PblkLen := ByteData
  409. */
  410. ext_opcode(opcode::EXT_DEF_PROCESSOR_OP)
  411. .then(comment_scope(
  412. DebugVerbosity::Scopes,
  413. "DefProcessor",
  414. pkg_length()
  415. .then(name_string())
  416. .then(take())
  417. .then(take_u32())
  418. .then(take())
  419. .map_with_context(|((((pkg_length, name), proc_id), pblk_address), pblk_len), context| {
  420. /*
  421. * Legacy `Processor` objects contain data within themselves, and can also have sub-objects,
  422. * so we add both a level for the sub-objects, and a value for the data.
  423. */
  424. let resolved_name = try_with_context!(context, name.resolve(&context.current_scope));
  425. try_with_context!(
  426. context,
  427. context.namespace.add_level(resolved_name.clone(), LevelType::Processor)
  428. );
  429. try_with_context!(
  430. context,
  431. context.namespace.add_value(
  432. resolved_name.clone(),
  433. AmlValue::Processor { id: proc_id, pblk_address, pblk_len }
  434. )
  435. );
  436. let previous_scope = context.current_scope.clone();
  437. context.current_scope = resolved_name;
  438. (Ok((previous_scope, pkg_length)), context)
  439. })
  440. .feed(move |(previous_scope, pkg_length)| {
  441. term_list(pkg_length).map(move |_| Ok(previous_scope.clone()))
  442. })
  443. .map_with_context(|previous_scope, context| {
  444. context.current_scope = previous_scope;
  445. (Ok(()), context)
  446. }),
  447. ))
  448. .discard_result()
  449. }
  450. pub fn def_power_res<'a, 'c>() -> impl Parser<'a, 'c, ()>
  451. where
  452. 'c: 'a,
  453. {
  454. /*
  455. * DefPowerRes := ExtOpPrefix 0x84 PkgLength NameString SystemLevel ResourceOrder TermList
  456. * SystemLevel := ByteData
  457. * ResourceOrder := WordData
  458. */
  459. ext_opcode(opcode::EXT_DEF_POWER_RES_OP)
  460. .then(comment_scope(
  461. DebugVerbosity::Scopes,
  462. "DefPowerRes",
  463. pkg_length()
  464. .then(name_string())
  465. .then(take())
  466. .then(take_u16())
  467. .map_with_context(|(((pkg_length, name), system_level), resource_order), context| {
  468. /*
  469. * `PowerResource` objects contain data within themselves, and can also have sub-objects,
  470. * so we add both a level for the sub-objects, and a value for the data.
  471. */
  472. let resolved_name = try_with_context!(context, name.resolve(&context.current_scope));
  473. try_with_context!(
  474. context,
  475. context.namespace.add_level(resolved_name.clone(), LevelType::PowerResource)
  476. );
  477. try_with_context!(
  478. context,
  479. context.namespace.add_value(
  480. resolved_name.clone(),
  481. AmlValue::PowerResource { system_level, resource_order }
  482. )
  483. );
  484. let previous_scope = context.current_scope.clone();
  485. context.current_scope = resolved_name;
  486. (Ok((previous_scope, pkg_length)), context)
  487. })
  488. .feed(move |(previous_scope, pkg_length)| {
  489. term_list(pkg_length).map(move |_| Ok(previous_scope.clone()))
  490. })
  491. .map_with_context(|previous_scope, context| {
  492. context.current_scope = previous_scope;
  493. (Ok(()), context)
  494. }),
  495. ))
  496. .discard_result()
  497. }
  498. pub fn def_thermal_zone<'a, 'c>() -> impl Parser<'a, 'c, ()>
  499. where
  500. 'c: 'a,
  501. {
  502. /*
  503. * DefThermalZone := ExtOpPrefix 0x85 PkgLength NameString TermList
  504. * TODO: we use this pattern a lot (move into scope, parse a term_list, move back out). Could we simplify into
  505. * just a `feed` by passing a scope into term_list?
  506. */
  507. ext_opcode(opcode::EXT_DEF_THERMAL_ZONE_OP)
  508. .then(comment_scope(
  509. DebugVerbosity::Scopes,
  510. "DefThermalZone",
  511. pkg_length()
  512. .then(name_string())
  513. .map_with_context(|(pkg_length, name), context| {
  514. let resolved_name = try_with_context!(context, name.resolve(&context.current_scope));
  515. try_with_context!(
  516. context,
  517. context.namespace.add_level(resolved_name.clone(), LevelType::ThermalZone)
  518. );
  519. let previous_scope = context.current_scope.clone();
  520. context.current_scope = resolved_name;
  521. (Ok((pkg_length, previous_scope)), context)
  522. })
  523. .feed(|(length, previous_scope)| term_list(length).map(move |_| Ok(previous_scope.clone())))
  524. .map_with_context(|previous_scope, context| {
  525. context.current_scope = previous_scope;
  526. (Ok(()), context)
  527. }),
  528. ))
  529. .discard_result()
  530. }
  531. pub fn def_mutex<'a, 'c>() -> impl Parser<'a, 'c, ()>
  532. where
  533. 'c: 'a,
  534. {
  535. /*
  536. * DefMutex := ExtOpPrefix 0x01 NameString SyncFlags
  537. * SyncFlags := ByteData (where bits 0-3: SyncLevel
  538. * bits 4-7: Reserved)
  539. */
  540. ext_opcode(opcode::EXT_DEF_MUTEX_OP)
  541. .then(comment_scope(
  542. DebugVerbosity::Scopes,
  543. "DefMutex",
  544. name_string().then(take()).map_with_context(|(name, sync_level), context| {
  545. try_with_context!(
  546. context,
  547. context.namespace.add_value_at_resolved_path(
  548. name,
  549. &context.current_scope,
  550. AmlValue::Mutex { sync_level }
  551. )
  552. );
  553. (Ok(()), context)
  554. }),
  555. ))
  556. .discard_result()
  557. }
  558. pub fn term_arg<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
  559. where
  560. 'c: 'a,
  561. {
  562. /*
  563. * TermArg := Type2Opcode | DataObject | ArgObj | LocalObj
  564. */
  565. comment_scope(
  566. DebugVerbosity::AllScopes,
  567. "TermArg",
  568. choice!(
  569. data_object(),
  570. arg_obj().map_with_context(|arg_num, context| {
  571. (Ok(try_with_context!(context, context.current_arg(arg_num)).clone()), context)
  572. }),
  573. local_obj().map_with_context(|local_num, context| {
  574. (Ok(try_with_context!(context, context.local(local_num)).clone()), context)
  575. }),
  576. make_parser_concrete!(type2_opcode())
  577. ),
  578. )
  579. }
  580. pub fn data_ref_object<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
  581. where
  582. 'c: 'a,
  583. {
  584. /*
  585. * DataRefObject := DataObject | ObjectReference | DDBHandle
  586. */
  587. comment_scope(DebugVerbosity::AllScopes, "DataRefObject", choice!(data_object()))
  588. }
  589. pub fn data_object<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
  590. where
  591. 'c: 'a,
  592. {
  593. /*
  594. * DataObject := DefPackage | DefVarPackage | ComputationalData
  595. *
  596. * The order of the parsers are important here, as DefPackage and DefVarPackage can be
  597. * accidently parsed as ComputationalDatas.
  598. */
  599. // TODO: this doesn't yet parse DefVarPackage
  600. comment_scope(DebugVerbosity::AllScopes, "DataObject", choice!(def_package(), computational_data()))
  601. }
  602. pub fn computational_data<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
  603. where
  604. 'c: 'a,
  605. {
  606. /*
  607. * ComputationalData := ByteConst | WordConst | DWordConst | QWordConst | String |
  608. * ConstObj | RevisionOp | DefBuffer
  609. * ByteConst := 0x0a ByteData
  610. * WordConst := 0x0b WordData
  611. * DWordConst := 0x0c DWordData
  612. * QWordConst := 0x0e QWordData
  613. * String := 0x0d AsciiCharList NullChar
  614. * ConstObj := ZeroOp(0x00) | OneOp(0x01) | OnesOp(0xff)
  615. * RevisionOp := ExtOpPrefix(0x5b) 0x30
  616. */
  617. let const_parser = |input: &'a [u8], context: &'c mut AmlContext| {
  618. let string_parser = |input: &'a [u8], context| -> ParseResult<'a, 'c, AmlValue> {
  619. /*
  620. * Using `position` isn't very efficient here, but is probably fine because the
  621. * strings are usually quite short.
  622. */
  623. let nul_position = match input.iter().position(|&c| c == b'\0') {
  624. Some(position) => position,
  625. None => return Err((input, context, Propagate::Err(AmlError::UnterminatedStringConstant))),
  626. };
  627. let string = String::from(match str::from_utf8(&input[0..nul_position]) {
  628. Ok(string) => string,
  629. Err(_) => return Err((input, context, Propagate::Err(AmlError::InvalidStringConstant))),
  630. });
  631. Ok((&input[(nul_position + 1)..], context, AmlValue::String(string)))
  632. };
  633. let (new_input, context, op) = take().parse(input, context)?;
  634. match op {
  635. opcode::BYTE_CONST => {
  636. take().map(|value| Ok(AmlValue::Integer(value as u64))).parse(new_input, context)
  637. }
  638. opcode::WORD_CONST => {
  639. take_u16().map(|value| Ok(AmlValue::Integer(value as u64))).parse(new_input, context)
  640. }
  641. opcode::DWORD_CONST => {
  642. take_u32().map(|value| Ok(AmlValue::Integer(value as u64))).parse(new_input, context)
  643. }
  644. opcode::QWORD_CONST => take_u64().map(|value| Ok(AmlValue::Integer(value))).parse(new_input, context),
  645. opcode::STRING_PREFIX => string_parser.parse(new_input, context),
  646. opcode::ZERO_OP => Ok((new_input, context, AmlValue::zero())),
  647. opcode::ONE_OP => Ok((new_input, context, AmlValue::one())),
  648. opcode::ONES_OP => Ok((new_input, context, AmlValue::ones())),
  649. _ => Err((input, context, Propagate::Err(AmlError::WrongParser))),
  650. }
  651. };
  652. comment_scope(
  653. DebugVerbosity::AllScopes,
  654. "ComputationalData",
  655. choice!(
  656. ext_opcode(opcode::EXT_REVISION_OP).map(|_| Ok(AmlValue::Integer(crate::AML_INTERPRETER_REVISION))),
  657. const_parser,
  658. make_parser_concrete!(def_buffer())
  659. ),
  660. )
  661. }
  662. #[cfg(test)]
  663. mod test {
  664. use super::*;
  665. use crate::test_utils::*;
  666. #[test]
  667. fn test_computational_data() {
  668. let mut context = make_test_context();
  669. check_ok_value!(
  670. computational_data().parse(&[0x00, 0x34, 0x12], &mut context),
  671. AmlValue::Integer(0),
  672. &[0x34, 0x12]
  673. );
  674. check_ok_value!(
  675. computational_data().parse(&[0x01, 0x18, 0xf3], &mut context),
  676. AmlValue::Integer(1),
  677. &[0x18, 0xf3]
  678. );
  679. check_ok_value!(
  680. computational_data().parse(&[0xff, 0x98, 0xc3], &mut context),
  681. AmlValue::Integer(u64::max_value()),
  682. &[0x98, 0xc3]
  683. );
  684. check_ok_value!(
  685. computational_data().parse(&[0x5b, 0x30], &mut context),
  686. AmlValue::Integer(crate::AML_INTERPRETER_REVISION),
  687. &[]
  688. );
  689. check_ok_value!(
  690. computational_data().parse(&[0x0a, 0xf3, 0x35], &mut context),
  691. AmlValue::Integer(0xf3),
  692. &[0x35]
  693. );
  694. check_ok_value!(
  695. computational_data().parse(&[0x0b, 0xf3, 0x35], &mut context),
  696. AmlValue::Integer(0x35f3),
  697. &[]
  698. );
  699. check_ok_value!(
  700. computational_data().parse(&[0x0c, 0xf3, 0x35, 0x12, 0x65, 0xff, 0x00], &mut context),
  701. AmlValue::Integer(0x651235f3),
  702. &[0xff, 0x00]
  703. );
  704. check_ok_value!(
  705. computational_data()
  706. .parse(&[0x0e, 0xf3, 0x35, 0x12, 0x65, 0xff, 0x00, 0x67, 0xde, 0x28], &mut context),
  707. AmlValue::Integer(0xde6700ff651235f3),
  708. &[0x28]
  709. );
  710. check_ok_value!(
  711. computational_data().parse(&[0x0d, b'A', b'B', b'C', b'D', b'\0', 0xff, 0xf5], &mut context),
  712. AmlValue::String(String::from("ABCD")),
  713. &[0xff, 0xf5]
  714. );
  715. }
  716. }