value.rs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. use crate::{misc::ArgNum, AmlContext, AmlError, AmlHandle, AmlName};
  2. use alloc::{
  3. string::{String, ToString},
  4. sync::Arc,
  5. vec::Vec,
  6. };
  7. use bit_field::BitField;
  8. use core::{cmp, fmt, fmt::Debug};
  9. use spinning_top::Spinlock;
  10. #[derive(Clone, Copy, PartialEq, Eq, Debug)]
  11. pub enum RegionSpace {
  12. SystemMemory,
  13. SystemIo,
  14. PciConfig,
  15. EmbeddedControl,
  16. SMBus,
  17. SystemCmos,
  18. PciBarTarget,
  19. IPMI,
  20. GeneralPurposeIo,
  21. GenericSerialBus,
  22. OemDefined(u8),
  23. }
  24. #[derive(Clone, Copy, PartialEq, Eq, Debug)]
  25. pub enum FieldAccessType {
  26. Any,
  27. Byte,
  28. Word,
  29. DWord,
  30. QWord,
  31. Buffer,
  32. }
  33. #[derive(Clone, Copy, PartialEq, Eq, Debug)]
  34. pub enum FieldUpdateRule {
  35. Preserve,
  36. WriteAsOnes,
  37. WriteAsZeros,
  38. }
  39. // TODO: custom debug impl
  40. #[derive(Clone, Copy, PartialEq, Eq, Debug)]
  41. pub struct FieldFlags(u8);
  42. impl FieldFlags {
  43. pub fn new(value: u8) -> FieldFlags {
  44. FieldFlags(value)
  45. }
  46. pub fn access_type(&self) -> Result<FieldAccessType, AmlError> {
  47. match self.0.get_bits(0..4) {
  48. 0 => Ok(FieldAccessType::Any),
  49. 1 => Ok(FieldAccessType::Byte),
  50. 2 => Ok(FieldAccessType::Word),
  51. 3 => Ok(FieldAccessType::DWord),
  52. 4 => Ok(FieldAccessType::QWord),
  53. 5 => Ok(FieldAccessType::Buffer),
  54. _ => Err(AmlError::InvalidFieldFlags),
  55. }
  56. }
  57. pub fn lock_rule(&self) -> bool {
  58. self.0.get_bit(4)
  59. }
  60. pub fn field_update_rule(&self) -> Result<FieldUpdateRule, AmlError> {
  61. match self.0.get_bits(5..7) {
  62. 0 => Ok(FieldUpdateRule::Preserve),
  63. 1 => Ok(FieldUpdateRule::WriteAsOnes),
  64. 2 => Ok(FieldUpdateRule::WriteAsZeros),
  65. _ => Err(AmlError::InvalidFieldFlags),
  66. }
  67. }
  68. }
  69. #[derive(Clone, Copy, PartialEq, Eq, Debug)]
  70. pub struct MethodFlags(u8);
  71. impl MethodFlags {
  72. pub fn new(arg_count: u8, serialize: bool, sync_level: u8) -> MethodFlags {
  73. assert!(arg_count <= 7);
  74. assert!(sync_level <= 15);
  75. let mut value = 0;
  76. value.set_bits(0..3, arg_count);
  77. value.set_bit(3, serialize);
  78. value.set_bits(4..8, sync_level);
  79. MethodFlags(value)
  80. }
  81. pub fn from(value: u8) -> MethodFlags {
  82. MethodFlags(value)
  83. }
  84. pub fn arg_count(&self) -> u8 {
  85. self.0.get_bits(0..3)
  86. }
  87. pub fn serialize(&self) -> bool {
  88. self.0.get_bit(3)
  89. }
  90. pub fn sync_level(&self) -> u8 {
  91. self.0.get_bits(4..8)
  92. }
  93. }
  94. /// Representation of the return value of a `_STA` method, which represents the status of an object. It must be
  95. /// evaluated, if present, before evaluating the `_INI` method for an device.
  96. ///
  97. /// The `Default` implementation of this type is the correct value to use if a device doesn't have a `_STA` object
  98. /// to evaluate.
  99. #[derive(Clone, Copy, PartialEq, Eq, Debug)]
  100. pub struct StatusObject {
  101. /// Whether the device is physically present. If this is `false`, `enabled` should also be `false` (i.e. a
  102. /// device that is not present can't be enabled). However, this is not enforced here if the firmware is doing
  103. /// something wrong.
  104. pub present: bool,
  105. /// Whether the device is enabled. Both `present` and `enabled` must be `true` for the device to decode its
  106. /// hardware resources.
  107. pub enabled: bool,
  108. pub show_in_ui: bool,
  109. pub functional: bool,
  110. /// Only applicable for Control Method Battery Devices (`PNP0C0A`). For all other devices, ignore this value.
  111. pub battery_present: bool,
  112. }
  113. impl Default for StatusObject {
  114. fn default() -> Self {
  115. StatusObject { present: true, enabled: true, show_in_ui: true, functional: true, battery_present: true }
  116. }
  117. }
  118. #[derive(Clone, Copy, PartialEq, Eq, Debug)]
  119. pub enum AmlType {
  120. Uninitialized,
  121. Buffer,
  122. BufferField,
  123. /// Handle to a definition block handle. Returned by the `Load` operator.
  124. DdbHandle,
  125. DebugObject,
  126. Event,
  127. FieldUnit,
  128. Device,
  129. Integer,
  130. Method,
  131. Mutex,
  132. ObjReference,
  133. OpRegion,
  134. Package,
  135. PowerResource,
  136. Processor,
  137. RawDataBuffer,
  138. String,
  139. ThermalZone,
  140. }
  141. #[derive(Clone)]
  142. pub enum MethodCode {
  143. Aml(Vec<u8>),
  144. Native(Arc<dyn Fn(&mut AmlContext) -> Result<AmlValue, AmlError> + Send + Sync>),
  145. }
  146. impl fmt::Debug for MethodCode {
  147. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  148. match self {
  149. MethodCode::Aml(ref code) => write!(f, "AML({:x?})", code),
  150. MethodCode::Native(_) => write!(f, "(native method)"),
  151. }
  152. }
  153. }
  154. #[derive(Clone, Debug)]
  155. pub enum AmlValue {
  156. Boolean(bool),
  157. Integer(u64),
  158. String(String),
  159. /// Describes an operation region. Some regions require other objects to be declared under their parent device
  160. /// (e.g. an `_ADR` object for a `PciConfig` region), in which case an absolute path to the object is stored in
  161. /// `parent_device`.
  162. OpRegion {
  163. region: RegionSpace,
  164. offset: u64,
  165. length: u64,
  166. parent_device: Option<AmlName>,
  167. },
  168. /// Describes a field unit within an operation region.
  169. Field {
  170. region: AmlHandle,
  171. flags: FieldFlags,
  172. offset: u64,
  173. length: u64,
  174. },
  175. Device,
  176. Method {
  177. flags: MethodFlags,
  178. code: MethodCode,
  179. },
  180. Buffer(Arc<Spinlock<Vec<u8>>>),
  181. BufferField {
  182. buffer_data: Arc<Spinlock<Vec<u8>>>,
  183. /// In bits.
  184. offset: u64,
  185. /// In bits.
  186. length: u64,
  187. },
  188. Processor {
  189. id: u8,
  190. pblk_address: u32,
  191. pblk_len: u8,
  192. },
  193. Mutex {
  194. sync_level: u8,
  195. },
  196. // TODO: I think this will need to be `Arc`ed as well, as `Index` can be used on both Buffers and Packages
  197. Package(Vec<AmlValue>),
  198. PowerResource {
  199. system_level: u8,
  200. resource_order: u16,
  201. },
  202. ThermalZone,
  203. }
  204. impl AmlValue {
  205. pub fn zero() -> AmlValue {
  206. AmlValue::Integer(0)
  207. }
  208. pub fn one() -> AmlValue {
  209. AmlValue::Integer(1)
  210. }
  211. pub fn ones() -> AmlValue {
  212. AmlValue::Integer(u64::max_value())
  213. }
  214. pub fn native_method<F>(arg_count: u8, serialize: bool, sync_level: u8, f: F) -> AmlValue
  215. where
  216. F: (Fn(&mut AmlContext) -> Result<AmlValue, AmlError>) + 'static + Send + Sync,
  217. {
  218. let flags = MethodFlags::new(arg_count, serialize, sync_level);
  219. AmlValue::Method { flags, code: MethodCode::Native(Arc::new(f)) }
  220. }
  221. pub fn type_of(&self) -> AmlType {
  222. match self {
  223. AmlValue::Boolean(_) => AmlType::Integer,
  224. AmlValue::Integer(_) => AmlType::Integer,
  225. AmlValue::String(_) => AmlType::String,
  226. AmlValue::OpRegion { .. } => AmlType::OpRegion,
  227. AmlValue::Field { .. } => AmlType::FieldUnit,
  228. AmlValue::Device => AmlType::Device,
  229. AmlValue::Method { .. } => AmlType::Method,
  230. AmlValue::Buffer(_) => AmlType::Buffer,
  231. AmlValue::BufferField { .. } => AmlType::BufferField,
  232. AmlValue::Processor { .. } => AmlType::Processor,
  233. AmlValue::Mutex { .. } => AmlType::Mutex,
  234. AmlValue::Package(_) => AmlType::Package,
  235. AmlValue::PowerResource { .. } => AmlType::PowerResource,
  236. AmlValue::ThermalZone => AmlType::ThermalZone,
  237. }
  238. }
  239. pub fn as_bool(&self) -> Result<bool, AmlError> {
  240. match self {
  241. AmlValue::Boolean(value) => Ok(*value),
  242. AmlValue::Integer(value) => Ok(*value != 0),
  243. _ => Err(AmlError::IncompatibleValueConversion { current: self.type_of(), target: AmlType::Integer }),
  244. }
  245. }
  246. pub fn as_integer(&self, context: &AmlContext) -> Result<u64, AmlError> {
  247. match self {
  248. AmlValue::Integer(value) => Ok(*value),
  249. AmlValue::Boolean(value) => Ok(if *value { u64::max_value() } else { 0 }),
  250. AmlValue::Buffer(ref bytes) => {
  251. /*
  252. * "The first 8 bytes of the buffer are converted to an integer, taking the first
  253. * byte as the least significant byte of the integer. A zero-length buffer is
  254. * illegal." - §19.6.140
  255. *
  256. * XXX: Buffers with length `0` appear in real tables, so we return `0` for them.
  257. */
  258. let bytes = bytes.lock();
  259. let bytes = if bytes.len() > 8 { &bytes[0..8] } else { &bytes[..] };
  260. Ok(bytes.iter().rev().fold(0: u64, |mut i, &popped| {
  261. i <<= 8;
  262. i += popped as u64;
  263. i
  264. }))
  265. }
  266. /*
  267. * Read from a field or buffer field. These can return either a `Buffer` or an `Integer`, so we make sure to call
  268. * `as_integer` on the result.
  269. */
  270. AmlValue::Field { .. } => self.read_field(context)?.as_integer(context),
  271. AmlValue::BufferField { .. } => self.read_buffer_field(context)?.as_integer(context),
  272. _ => Err(AmlError::IncompatibleValueConversion { current: self.type_of(), target: AmlType::Integer }),
  273. }
  274. }
  275. pub fn as_buffer(&self, context: &AmlContext) -> Result<Arc<Spinlock<Vec<u8>>>, AmlError> {
  276. match self {
  277. AmlValue::Buffer(ref bytes) => Ok(bytes.clone()),
  278. // TODO: implement conversion of String and Integer to Buffer
  279. AmlValue::Field { .. } => self.read_field(context)?.as_buffer(context),
  280. AmlValue::BufferField { .. } => self.read_buffer_field(context)?.as_buffer(context),
  281. _ => Err(AmlError::IncompatibleValueConversion { current: self.type_of(), target: AmlType::Buffer }),
  282. }
  283. }
  284. pub fn as_string(&self, context: &AmlContext) -> Result<String, AmlError> {
  285. match self {
  286. AmlValue::String(ref string) => Ok(string.clone()),
  287. // TODO: implement conversion of Buffer to String
  288. AmlValue::Field { .. } => self.read_field(context)?.as_string(context),
  289. _ => Err(AmlError::IncompatibleValueConversion { current: self.type_of(), target: AmlType::String }),
  290. }
  291. }
  292. /// Converts an `AmlValue` to the representation that should be used when concatenating it with other values,
  293. /// primarily by the `DefConcat` opcode. This will always produce a `AmlValue::Integer`, `AmlValue::String`, or
  294. /// `AmlValue::Buffer`, with other types being converted to strings containing the name of their type.
  295. pub fn as_concat_type(&self) -> AmlValue {
  296. match self.type_of() {
  297. AmlType::Integer => self.clone(),
  298. AmlType::String => self.clone(),
  299. AmlType::Buffer => self.clone(),
  300. AmlType::Uninitialized => AmlValue::String("[Uninitialized]".to_string()),
  301. AmlType::BufferField => AmlValue::String("[Buffer Field]".to_string()),
  302. AmlType::DdbHandle => AmlValue::String("[Ddb Handle]".to_string()),
  303. AmlType::DebugObject => AmlValue::String("[Debug Object]".to_string()),
  304. AmlType::Event => AmlValue::String("[Event]".to_string()),
  305. AmlType::FieldUnit => AmlValue::String("[Field]".to_string()),
  306. AmlType::Device => AmlValue::String("[Device]".to_string()),
  307. AmlType::Method => AmlValue::String("[Control Method]".to_string()),
  308. AmlType::Mutex => AmlValue::String("[Mutex]".to_string()),
  309. AmlType::ObjReference => AmlValue::String("[Obj Reference]".to_string()),
  310. AmlType::OpRegion => AmlValue::String("[Operation Region]".to_string()),
  311. AmlType::Package => AmlValue::String("[Package]".to_string()),
  312. AmlType::Processor => AmlValue::String("[Processor]".to_string()),
  313. AmlType::PowerResource => AmlValue::String("[Power Resource]".to_string()),
  314. AmlType::RawDataBuffer => AmlValue::String("[Raw Data Buffer]".to_string()),
  315. AmlType::ThermalZone => AmlValue::String("[Thermal Zone]".to_string()),
  316. }
  317. }
  318. /// Turns an `AmlValue` returned from a `_STA` method into a `StatusObject`. Should only be called for values
  319. /// returned from `_STA`. If you need a `StatusObject`, but the device does not have a `_STA` method, use
  320. /// `StatusObject::default()`.
  321. pub fn as_status(&self) -> Result<StatusObject, AmlError> {
  322. match self {
  323. AmlValue::Integer(value) => {
  324. /*
  325. * Bits 5+ are reserved and are expected to be cleared.
  326. */
  327. if value.get_bits(5..64) != 0 {
  328. return Err(AmlError::InvalidStatusObject);
  329. }
  330. Ok(StatusObject {
  331. present: value.get_bit(0),
  332. enabled: value.get_bit(1),
  333. show_in_ui: value.get_bit(2),
  334. functional: value.get_bit(3),
  335. battery_present: value.get_bit(4),
  336. })
  337. }
  338. _ => Err(AmlError::InvalidStatusObject),
  339. }
  340. }
  341. /// Convert this value to a value of the same data, but with the given AML type, if possible,
  342. /// by converting the implicit conversions described in §19.3.5 of the spec.
  343. ///
  344. /// The implicit conversions applied are:
  345. /// `Buffer` from: `Integer`, `String`, `Debug`
  346. /// `BufferField` from: `Integer`, `Buffer`, `String`, `Debug`
  347. /// `DdbHandle` from: `Integer`, `Debug`
  348. /// `FieldUnit` from: `Integer`,`Buffer`, `String`, `Debug`
  349. /// `Integer` from: `Buffer`, `BufferField`, `DdbHandle`, `FieldUnit`, `String`, `Debug`
  350. /// `Package` from: `Debug`
  351. /// `String` from: `Integer`, `Buffer`, `Debug`
  352. pub fn as_type(&self, desired_type: AmlType, context: &AmlContext) -> Result<AmlValue, AmlError> {
  353. // If the value is already of the correct type, just return it as is
  354. if self.type_of() == desired_type {
  355. return Ok(self.clone());
  356. }
  357. // TODO: implement all of the rules
  358. match desired_type {
  359. AmlType::Integer => self.as_integer(context).map(|value| AmlValue::Integer(value)),
  360. AmlType::Buffer => self.as_buffer(context).map(|value| AmlValue::Buffer(value)),
  361. AmlType::FieldUnit => panic!(
  362. "Can't implicitly convert to FieldUnit. This must be special-cased by the caller for now :("
  363. ),
  364. _ => Err(AmlError::IncompatibleValueConversion { current: self.type_of(), target: desired_type }),
  365. }
  366. }
  367. /// Reads from a field of an opregion, returning either a `AmlValue::Integer` or an `AmlValue::Buffer`,
  368. /// depending on the size of the field.
  369. pub fn read_field(&self, context: &AmlContext) -> Result<AmlValue, AmlError> {
  370. if let AmlValue::Field { region, flags, offset, length } = self {
  371. let maximum_access_size = {
  372. if let AmlValue::OpRegion { region, .. } = context.namespace.get(*region)? {
  373. match region {
  374. RegionSpace::SystemMemory => 64,
  375. RegionSpace::SystemIo | RegionSpace::PciConfig => 32,
  376. _ => unimplemented!(),
  377. }
  378. } else {
  379. return Err(AmlError::FieldRegionIsNotOpRegion);
  380. }
  381. };
  382. let minimum_access_size = match flags.access_type()? {
  383. FieldAccessType::Any => 8,
  384. FieldAccessType::Byte => 8,
  385. FieldAccessType::Word => 16,
  386. FieldAccessType::DWord => 32,
  387. FieldAccessType::QWord => 64,
  388. FieldAccessType::Buffer => 8, // TODO
  389. };
  390. /*
  391. * Find the access size, as either the minimum access size allowed by the region, or the field length
  392. * rounded up to the next power-of-2, whichever is larger.
  393. */
  394. let access_size = u64::max(minimum_access_size, length.next_power_of_two());
  395. /*
  396. * TODO: we need to decide properly how to read from the region itself. Complications:
  397. * - if the region has a minimum access size greater than the desired length, we need to read the
  398. * minimum and mask it (reading a byte from a WordAcc region)
  399. * - if the desired length is larger than we can read, we need to do multiple reads
  400. */
  401. Ok(AmlValue::Integer(
  402. context.read_region(*region, *offset, access_size)?.get_bits(0..(*length as usize)),
  403. ))
  404. } else {
  405. Err(AmlError::IncompatibleValueConversion { current: self.type_of(), target: AmlType::FieldUnit })
  406. }
  407. }
  408. pub fn write_field(&mut self, value: AmlValue, context: &mut AmlContext) -> Result<(), AmlError> {
  409. /*
  410. * If the field's update rule is `Preserve`, we need to read the initial value of the field, so we can
  411. * overwrite the correct bits. We destructure the field to do the actual write, so we read from it if
  412. * needed here, otherwise the borrow-checker doesn't understand.
  413. */
  414. let field_update_rule = if let AmlValue::Field { region, flags, offset, length } = self {
  415. flags.field_update_rule()?
  416. } else {
  417. return Err(AmlError::IncompatibleValueConversion {
  418. current: self.type_of(),
  419. target: AmlType::FieldUnit,
  420. });
  421. };
  422. let mut field_value = match field_update_rule {
  423. FieldUpdateRule::Preserve => self.read_field(context)?.as_integer(context)?,
  424. FieldUpdateRule::WriteAsOnes => 0xffffffff_ffffffff,
  425. FieldUpdateRule::WriteAsZeros => 0x0,
  426. };
  427. if let AmlValue::Field { region, flags, offset, length } = self {
  428. let maximum_access_size = {
  429. if let AmlValue::OpRegion { region, .. } = context.namespace.get(*region)? {
  430. match region {
  431. RegionSpace::SystemMemory => 64,
  432. RegionSpace::SystemIo | RegionSpace::PciConfig => 32,
  433. _ => unimplemented!(),
  434. }
  435. } else {
  436. return Err(AmlError::FieldRegionIsNotOpRegion);
  437. }
  438. };
  439. let minimum_access_size = match flags.access_type()? {
  440. FieldAccessType::Any => 8,
  441. FieldAccessType::Byte => 8,
  442. FieldAccessType::Word => 16,
  443. FieldAccessType::DWord => 32,
  444. FieldAccessType::QWord => 64,
  445. FieldAccessType::Buffer => 8, // TODO
  446. };
  447. /*
  448. * Find the access size, as either the minimum access size allowed by the region, or the field length
  449. * rounded up to the next power-of-2, whichever is larger.
  450. */
  451. let access_size = u64::max(minimum_access_size, length.next_power_of_two());
  452. field_value.set_bits(0..(*length as usize), value.as_integer(context)?);
  453. context.write_region(*region, *offset, access_size, field_value)
  454. } else {
  455. Err(AmlError::IncompatibleValueConversion { current: self.type_of(), target: AmlType::FieldUnit })
  456. }
  457. }
  458. pub fn read_buffer_field(&self, context: &AmlContext) -> Result<AmlValue, AmlError> {
  459. use bitvec::view::BitView;
  460. if let AmlValue::BufferField { buffer_data, offset, length } = self {
  461. let offset = *offset as usize;
  462. let length = *length as usize;
  463. let inner_data = buffer_data.lock();
  464. if (offset + length) > (inner_data.len() * 8) {
  465. return Err(AmlError::BufferFieldIndexesOutOfBounds);
  466. }
  467. let bitslice = inner_data.view_bits::<bitvec::order::Lsb0>();
  468. let bits = &bitslice[offset..(offset + length)];
  469. if length > 64 {
  470. Ok(AmlValue::Buffer(Arc::new(spinning_top::Spinlock::new(bits.as_raw_slice().to_vec()))))
  471. } else {
  472. let mut value = 0u64;
  473. value.view_bits_mut::<bitvec::order::Lsb0>()[0..length].clone_from_bitslice(bits);
  474. Ok(AmlValue::Integer(value))
  475. }
  476. } else {
  477. Err(AmlError::IncompatibleValueConversion { current: self.type_of(), target: AmlType::BufferField })
  478. }
  479. }
  480. pub fn write_buffer_field(&mut self, value: AmlValue, context: &mut AmlContext) -> Result<(), AmlError> {
  481. use bitvec::view::BitView;
  482. if let AmlValue::BufferField { buffer_data, offset, length } = self {
  483. let offset = *offset as usize;
  484. let length = *length as usize;
  485. // TODO: check these against the size of the buffer to be written into
  486. let mut inner_data = buffer_data.lock();
  487. let bitslice = inner_data.view_bits_mut::<bitvec::order::Lsb0>();
  488. match value {
  489. AmlValue::Integer(value) => {
  490. /*
  491. * When an `Integer` is written into a `BufferField`, the entire contents are overwritten. If
  492. * it's smaller than the length of the buffer field, it's zero-extended. If it's larger, the
  493. * upper bits are truncated.
  494. */
  495. let bits_to_copy = cmp::min(length, 64);
  496. bitslice[offset..(offset + bits_to_copy)]
  497. .copy_from_bitslice(&value.to_le_bytes().view_bits()[..(bits_to_copy as usize)]);
  498. // Zero extend to the end of the buffer field
  499. bitslice[(offset + bits_to_copy)..(offset + length)].set_all(false);
  500. Ok(())
  501. }
  502. AmlValue::Boolean(value) => {
  503. bitslice.set(offset, value);
  504. Ok(())
  505. }
  506. AmlValue::Buffer(value) => {
  507. /*
  508. * When a `Buffer` is written into a `BufferField`, the entire contents are copied into the
  509. * field. If the buffer is smaller than the size of the buffer field, it is zero extended. If
  510. * the buffer is larger, the upper bits are truncated.
  511. * XXX: this behaviour is only explicitly defined in ACPI 2.0+. While undefined in ACPI 1.0,
  512. * we produce the same behaviour there.
  513. */
  514. let value_data = value.lock();
  515. let bits_to_copy = cmp::min(length, value_data.len() * 8);
  516. bitslice[offset..(offset + bits_to_copy)]
  517. .copy_from_bitslice(&value_data.view_bits()[..(bits_to_copy as usize)]);
  518. // Zero extend to the end of the buffer field
  519. bitslice[(offset + bits_to_copy)..(offset + length)].set_all(false);
  520. Ok(())
  521. }
  522. _ => Err(AmlError::TypeCannotBeWrittenToBufferField(value.type_of())),
  523. }
  524. } else {
  525. Err(AmlError::IncompatibleValueConversion { current: self.type_of(), target: AmlType::BufferField })
  526. }
  527. }
  528. /// Logically compare two `AmlValue`s, according to the rules that govern opcodes like `DefLEqual`, `DefLLess`,
  529. /// etc. The type of `self` dictates the type that `other` will be converted to, and the method by which the
  530. /// values will be compared:
  531. /// - `Integer`s are simply compared by numeric comparison
  532. /// - `String`s and `Buffer`s are compared lexicographically - `other` is compared byte-wise until a byte
  533. /// is discovered that is either less or greater than the corresponding byte of `self`. If the bytes are
  534. /// identical, the lengths are compared. Luckily, the Rust standard library implements lexicographic
  535. /// comparison of strings and `[u8]` for us already.
  536. pub fn cmp(&self, other: AmlValue, context: &mut AmlContext) -> Result<cmp::Ordering, AmlError> {
  537. let self_inner =
  538. if self.type_of() == AmlType::FieldUnit { self.read_field(context)? } else { self.clone() };
  539. match self_inner.type_of() {
  540. AmlType::Integer => Ok(self.as_integer(context)?.cmp(&other.as_integer(context)?)),
  541. AmlType::Buffer => Ok(self.as_buffer(context)?.lock().cmp(&other.as_buffer(context)?.lock())),
  542. AmlType::String => Ok(self.as_string(context)?.cmp(&other.as_string(context)?)),
  543. typ => Err(AmlError::TypeCannotBeCompared(typ)),
  544. }
  545. }
  546. }
  547. /// A control method can take up to 7 arguments, each of which is an `AmlValue`.
  548. #[derive(Clone, Default, Debug)]
  549. pub struct Args(pub [Option<AmlValue>; 7]);
  550. impl Args {
  551. pub const EMPTY: Self = Self([None, None, None, None, None, None, None]);
  552. pub fn from_list(list: Vec<AmlValue>) -> Result<Args, AmlError> {
  553. use core::convert::TryInto;
  554. if list.len() > 7 {
  555. return Err(AmlError::TooManyArgs);
  556. }
  557. let mut args: Vec<Option<AmlValue>> = list.into_iter().map(Option::Some).collect();
  558. args.extend(core::iter::repeat(None).take(7 - args.len()));
  559. Ok(Args(args.try_into().unwrap()))
  560. }
  561. pub fn arg(&self, arg: ArgNum) -> Result<&AmlValue, AmlError> {
  562. if arg > 6 {
  563. return Err(AmlError::InvalidArgAccess(arg));
  564. }
  565. self.0[arg as usize].as_ref().ok_or(AmlError::InvalidArgAccess(arg))
  566. }
  567. pub fn store_arg(&mut self, arg: ArgNum, value: AmlValue) -> Result<(), AmlError> {
  568. if arg > 6 {
  569. return Err(AmlError::InvalidArgAccess(arg));
  570. }
  571. self.0[arg as usize] = Some(value);
  572. Ok(())
  573. }
  574. }
  575. #[cfg(test)]
  576. mod tests {
  577. use super::*;
  578. use crate::test_utils::*;
  579. use core::cmp::Ordering;
  580. #[test]
  581. fn test_object_cmp() {
  582. let mut context = make_test_context();
  583. assert_eq!(AmlValue::Integer(76).cmp(AmlValue::Integer(89), &mut context), Ok(Ordering::Less));
  584. assert_eq!(AmlValue::Integer(11).cmp(AmlValue::Integer(11), &mut context), Ok(Ordering::Equal));
  585. assert_eq!(AmlValue::Integer(8362836690).cmp(AmlValue::Integer(1), &mut context), Ok(Ordering::Greater));
  586. // TODO: test the other combinations too, as well as conversions to the correct types for the second operand
  587. }
  588. }