value.rs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  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. Uninitialized,
  157. Boolean(bool),
  158. Integer(u64),
  159. String(String),
  160. /// Describes an operation region. Some regions require other objects to be declared under their parent device
  161. /// (e.g. an `_ADR` object for a `PciConfig` region), in which case an absolute path to the object is stored in
  162. /// `parent_device`.
  163. OpRegion {
  164. region: RegionSpace,
  165. offset: u64,
  166. length: u64,
  167. parent_device: Option<AmlName>,
  168. },
  169. /// Describes a field unit within an operation region.
  170. Field {
  171. region: AmlHandle,
  172. flags: FieldFlags,
  173. offset: u64,
  174. length: u64,
  175. },
  176. Device,
  177. Method {
  178. flags: MethodFlags,
  179. code: MethodCode,
  180. },
  181. Buffer(Arc<Spinlock<Vec<u8>>>),
  182. BufferField {
  183. buffer_data: Arc<Spinlock<Vec<u8>>>,
  184. /// In bits.
  185. offset: u64,
  186. /// In bits.
  187. length: u64,
  188. },
  189. Processor {
  190. id: u8,
  191. pblk_address: u32,
  192. pblk_len: u8,
  193. },
  194. Mutex {
  195. sync_level: u8,
  196. },
  197. // TODO: I think this will need to be `Arc`ed as well, as `Index` can be used on both Buffers and Packages
  198. Package(Vec<AmlValue>),
  199. PowerResource {
  200. system_level: u8,
  201. resource_order: u16,
  202. },
  203. ThermalZone,
  204. }
  205. impl AmlValue {
  206. pub fn zero() -> AmlValue {
  207. AmlValue::Integer(0)
  208. }
  209. pub fn one() -> AmlValue {
  210. AmlValue::Integer(1)
  211. }
  212. pub fn ones() -> AmlValue {
  213. AmlValue::Integer(u64::max_value())
  214. }
  215. pub fn native_method<F>(arg_count: u8, serialize: bool, sync_level: u8, f: F) -> AmlValue
  216. where
  217. F: (Fn(&mut AmlContext) -> Result<AmlValue, AmlError>) + 'static + Send + Sync,
  218. {
  219. let flags = MethodFlags::new(arg_count, serialize, sync_level);
  220. AmlValue::Method { flags, code: MethodCode::Native(Arc::new(f)) }
  221. }
  222. pub fn type_of(&self) -> AmlType {
  223. match self {
  224. AmlValue::Uninitialized => AmlType::Uninitialized,
  225. AmlValue::Boolean(_) => AmlType::Integer,
  226. AmlValue::Integer(_) => AmlType::Integer,
  227. AmlValue::String(_) => AmlType::String,
  228. AmlValue::OpRegion { .. } => AmlType::OpRegion,
  229. AmlValue::Field { .. } => AmlType::FieldUnit,
  230. AmlValue::Device => AmlType::Device,
  231. AmlValue::Method { .. } => AmlType::Method,
  232. AmlValue::Buffer(_) => AmlType::Buffer,
  233. AmlValue::BufferField { .. } => AmlType::BufferField,
  234. AmlValue::Processor { .. } => AmlType::Processor,
  235. AmlValue::Mutex { .. } => AmlType::Mutex,
  236. AmlValue::Package(_) => AmlType::Package,
  237. AmlValue::PowerResource { .. } => AmlType::PowerResource,
  238. AmlValue::ThermalZone => AmlType::ThermalZone,
  239. }
  240. }
  241. /// Returns the `SizeOf (x)` application result as specified in ACPI 6.2 §19.6.125
  242. pub fn size_of(&self) -> Result<u64, AmlError> {
  243. match self {
  244. // For a buffer, returns the size in bytes of the data
  245. AmlValue::Buffer(value) => Ok(value.lock().len() as u64),
  246. // For a string, returns the size in bytes (without NULL)
  247. AmlValue::String(value) => Ok(value.len() as u64),
  248. // For a package, returns the number of elements
  249. AmlValue::Package(value) => Ok(value.len() as u64),
  250. // TODO: For an Object Reference, the size of the object is returned
  251. // Other data types cause a fatal run-time error
  252. _ => Err(AmlError::InvalidSizeOfApplication(self.type_of())),
  253. }
  254. }
  255. pub fn as_bool(&self) -> Result<bool, AmlError> {
  256. match self {
  257. AmlValue::Boolean(value) => Ok(*value),
  258. AmlValue::Integer(value) => Ok(*value != 0),
  259. _ => Err(AmlError::IncompatibleValueConversion { current: self.type_of(), target: AmlType::Integer }),
  260. }
  261. }
  262. pub fn as_integer(&self, context: &mut AmlContext) -> Result<u64, AmlError> {
  263. match self {
  264. AmlValue::Integer(value) => Ok(*value),
  265. AmlValue::Boolean(value) => Ok(if *value { u64::max_value() } else { 0 }),
  266. AmlValue::Buffer(ref bytes) => {
  267. /*
  268. * "The first 8 bytes of the buffer are converted to an integer, taking the first
  269. * byte as the least significant byte of the integer. A zero-length buffer is
  270. * illegal." - §19.6.140
  271. *
  272. * XXX: Buffers with length `0` appear in real tables, so we return `0` for them.
  273. */
  274. let bytes = bytes.lock();
  275. let bytes = if bytes.len() > 8 { &bytes[0..8] } else { &bytes[..] };
  276. Ok(bytes.iter().rev().fold(0u64, |mut i, &popped| {
  277. i <<= 8;
  278. i += popped as u64;
  279. i
  280. }))
  281. }
  282. /*
  283. * Read from a field or buffer field. These can return either a `Buffer` or an `Integer`, so we make sure to call
  284. * `as_integer` on the result.
  285. */
  286. AmlValue::Field { .. } => self.read_field(context)?.as_integer(context),
  287. AmlValue::BufferField { .. } => self.read_buffer_field(context)?.as_integer(context),
  288. _ => Err(AmlError::IncompatibleValueConversion { current: self.type_of(), target: AmlType::Integer }),
  289. }
  290. }
  291. pub fn as_buffer(&self, context: &mut AmlContext) -> Result<Arc<Spinlock<Vec<u8>>>, AmlError> {
  292. match self {
  293. AmlValue::Buffer(ref bytes) => Ok(bytes.clone()),
  294. // TODO: implement conversion of String and Integer to Buffer
  295. AmlValue::Field { .. } => self.read_field(context)?.as_buffer(context),
  296. AmlValue::BufferField { .. } => self.read_buffer_field(context)?.as_buffer(context),
  297. _ => Err(AmlError::IncompatibleValueConversion { current: self.type_of(), target: AmlType::Buffer }),
  298. }
  299. }
  300. pub fn as_string(&self, context: &mut AmlContext) -> Result<String, AmlError> {
  301. match self {
  302. AmlValue::String(ref string) => Ok(string.clone()),
  303. // TODO: implement conversion of Buffer to String
  304. AmlValue::Field { .. } => self.read_field(context)?.as_string(context),
  305. _ => Err(AmlError::IncompatibleValueConversion { current: self.type_of(), target: AmlType::String }),
  306. }
  307. }
  308. /// Converts an `AmlValue` to the representation that should be used when concatenating it with other values,
  309. /// primarily by the `DefConcat` opcode. This will always produce a `AmlValue::Integer`, `AmlValue::String`, or
  310. /// `AmlValue::Buffer`, with other types being converted to strings containing the name of their type.
  311. pub fn as_concat_type(&self) -> AmlValue {
  312. match self.type_of() {
  313. AmlType::Integer => self.clone(),
  314. AmlType::String => self.clone(),
  315. AmlType::Buffer => self.clone(),
  316. AmlType::Uninitialized => AmlValue::String("[Uninitialized]".to_string()),
  317. AmlType::BufferField => AmlValue::String("[Buffer Field]".to_string()),
  318. AmlType::DdbHandle => AmlValue::String("[Ddb Handle]".to_string()),
  319. AmlType::DebugObject => AmlValue::String("[Debug Object]".to_string()),
  320. AmlType::Event => AmlValue::String("[Event]".to_string()),
  321. AmlType::FieldUnit => AmlValue::String("[Field]".to_string()),
  322. AmlType::Device => AmlValue::String("[Device]".to_string()),
  323. AmlType::Method => AmlValue::String("[Control Method]".to_string()),
  324. AmlType::Mutex => AmlValue::String("[Mutex]".to_string()),
  325. AmlType::ObjReference => AmlValue::String("[Obj Reference]".to_string()),
  326. AmlType::OpRegion => AmlValue::String("[Operation Region]".to_string()),
  327. AmlType::Package => AmlValue::String("[Package]".to_string()),
  328. AmlType::Processor => AmlValue::String("[Processor]".to_string()),
  329. AmlType::PowerResource => AmlValue::String("[Power Resource]".to_string()),
  330. AmlType::RawDataBuffer => AmlValue::String("[Raw Data Buffer]".to_string()),
  331. AmlType::ThermalZone => AmlValue::String("[Thermal Zone]".to_string()),
  332. }
  333. }
  334. /// Turns an `AmlValue` returned from a `_STA` method into a `StatusObject`. Should only be called for values
  335. /// returned from `_STA`. If you need a `StatusObject`, but the device does not have a `_STA` method, use
  336. /// `StatusObject::default()`.
  337. pub fn as_status(&self) -> Result<StatusObject, AmlError> {
  338. match self {
  339. AmlValue::Integer(value) => {
  340. /*
  341. * Bits 5+ are reserved and are expected to be cleared.
  342. */
  343. if value.get_bits(5..64) != 0 {
  344. return Err(AmlError::InvalidStatusObject);
  345. }
  346. Ok(StatusObject {
  347. present: value.get_bit(0),
  348. enabled: value.get_bit(1),
  349. show_in_ui: value.get_bit(2),
  350. functional: value.get_bit(3),
  351. battery_present: value.get_bit(4),
  352. })
  353. }
  354. _ => Err(AmlError::InvalidStatusObject),
  355. }
  356. }
  357. /// Convert this value to a value of the same data, but with the given AML type, if possible,
  358. /// by converting the implicit conversions described in §19.3.5 of the spec.
  359. ///
  360. /// The implicit conversions applied are:
  361. /// `Buffer` from: `Integer`, `String`, `Debug`
  362. /// `BufferField` from: `Integer`, `Buffer`, `String`, `Debug`
  363. /// `DdbHandle` from: `Integer`, `Debug`
  364. /// `FieldUnit` from: `Integer`,`Buffer`, `String`, `Debug`
  365. /// `Integer` from: `Buffer`, `BufferField`, `DdbHandle`, `FieldUnit`, `String`, `Debug`
  366. /// `Package` from: `Debug`
  367. /// `String` from: `Integer`, `Buffer`, `Debug`
  368. pub fn as_type(&self, desired_type: AmlType, context: &mut AmlContext) -> Result<AmlValue, AmlError> {
  369. // If the value is already of the correct type, just return it as is
  370. if self.type_of() == desired_type {
  371. return Ok(self.clone());
  372. }
  373. // TODO: implement all of the rules
  374. match desired_type {
  375. AmlType::Integer => self.as_integer(context).map(|value| AmlValue::Integer(value)),
  376. AmlType::Buffer => self.as_buffer(context).map(|value| AmlValue::Buffer(value)),
  377. AmlType::FieldUnit => panic!(
  378. "Can't implicitly convert to FieldUnit. This must be special-cased by the caller for now :("
  379. ),
  380. _ => Err(AmlError::IncompatibleValueConversion { current: self.type_of(), target: desired_type }),
  381. }
  382. }
  383. /// Reads from a field of an opregion, returning either a `AmlValue::Integer` or an `AmlValue::Buffer`,
  384. /// depending on the size of the field.
  385. pub fn read_field(&self, context: &mut AmlContext) -> Result<AmlValue, AmlError> {
  386. if let AmlValue::Field { region, flags, offset, length } = self {
  387. let _maximum_access_size = {
  388. if let AmlValue::OpRegion { region, .. } = context.namespace.get(*region)? {
  389. match region {
  390. RegionSpace::SystemMemory => 64,
  391. RegionSpace::SystemIo | RegionSpace::PciConfig => 32,
  392. _ => unimplemented!(),
  393. }
  394. } else {
  395. return Err(AmlError::FieldRegionIsNotOpRegion);
  396. }
  397. };
  398. let minimum_access_size = match flags.access_type()? {
  399. FieldAccessType::Any => 8,
  400. FieldAccessType::Byte => 8,
  401. FieldAccessType::Word => 16,
  402. FieldAccessType::DWord => 32,
  403. FieldAccessType::QWord => 64,
  404. FieldAccessType::Buffer => 8, // TODO
  405. };
  406. /*
  407. * Find the access size, as either the minimum access size allowed by the region, or the field length
  408. * rounded up to the next power-of-2, whichever is larger.
  409. */
  410. let access_size = u64::max(minimum_access_size, length.next_power_of_two());
  411. /*
  412. * TODO: we need to decide properly how to read from the region itself. Complications:
  413. * - if the region has a minimum access size greater than the desired length, we need to read the
  414. * minimum and mask it (reading a byte from a WordAcc region)
  415. * - if the desired length is larger than we can read, we need to do multiple reads
  416. */
  417. Ok(AmlValue::Integer(
  418. context.read_region(*region, *offset, access_size)?.get_bits(0..(*length as usize)),
  419. ))
  420. } else {
  421. Err(AmlError::IncompatibleValueConversion { current: self.type_of(), target: AmlType::FieldUnit })
  422. }
  423. }
  424. pub fn write_field(&mut self, value: AmlValue, context: &mut AmlContext) -> Result<(), AmlError> {
  425. /*
  426. * If the field's update rule is `Preserve`, we need to read the initial value of the field, so we can
  427. * overwrite the correct bits. We destructure the field to do the actual write, so we read from it if
  428. * needed here, otherwise the borrow-checker doesn't understand.
  429. */
  430. let field_update_rule = if let AmlValue::Field { flags, .. } = self {
  431. flags.field_update_rule()?
  432. } else {
  433. return Err(AmlError::IncompatibleValueConversion {
  434. current: self.type_of(),
  435. target: AmlType::FieldUnit,
  436. });
  437. };
  438. let mut field_value = match field_update_rule {
  439. FieldUpdateRule::Preserve => self.read_field(context)?.as_integer(context)?,
  440. FieldUpdateRule::WriteAsOnes => 0xffffffff_ffffffff,
  441. FieldUpdateRule::WriteAsZeros => 0x0,
  442. };
  443. if let AmlValue::Field { region, flags, offset, length } = self {
  444. let _maximum_access_size = {
  445. if let AmlValue::OpRegion { region, .. } = context.namespace.get(*region)? {
  446. match region {
  447. RegionSpace::SystemMemory => 64,
  448. RegionSpace::SystemIo | RegionSpace::PciConfig => 32,
  449. _ => unimplemented!(),
  450. }
  451. } else {
  452. return Err(AmlError::FieldRegionIsNotOpRegion);
  453. }
  454. };
  455. let minimum_access_size = match flags.access_type()? {
  456. FieldAccessType::Any => 8,
  457. FieldAccessType::Byte => 8,
  458. FieldAccessType::Word => 16,
  459. FieldAccessType::DWord => 32,
  460. FieldAccessType::QWord => 64,
  461. FieldAccessType::Buffer => 8, // TODO
  462. };
  463. /*
  464. * Find the access size, as either the minimum access size allowed by the region, or the field length
  465. * rounded up to the next power-of-2, whichever is larger.
  466. */
  467. let access_size = u64::max(minimum_access_size, length.next_power_of_two());
  468. field_value.set_bits(0..(*length as usize), value.as_integer(context)?);
  469. context.write_region(*region, *offset, access_size, field_value)
  470. } else {
  471. Err(AmlError::IncompatibleValueConversion { current: self.type_of(), target: AmlType::FieldUnit })
  472. }
  473. }
  474. pub fn read_buffer_field(&self, _context: &AmlContext) -> Result<AmlValue, AmlError> {
  475. use bitvec::view::BitView;
  476. if let AmlValue::BufferField { buffer_data, offset, length } = self {
  477. let offset = *offset as usize;
  478. let length = *length as usize;
  479. let inner_data = buffer_data.lock();
  480. if (offset + length) > (inner_data.len() * 8) {
  481. return Err(AmlError::BufferFieldIndexesOutOfBounds);
  482. }
  483. let bitslice = inner_data.view_bits::<bitvec::order::Lsb0>();
  484. let bits = &bitslice[offset..(offset + length)];
  485. if length > 64 {
  486. let mut bitvec = bits.to_bitvec();
  487. bitvec.set_uninitialized(false);
  488. Ok(AmlValue::Buffer(Arc::new(spinning_top::Spinlock::new(bitvec.into_vec()))))
  489. } else if length > 32 {
  490. /*
  491. * TODO: this is a pretty gross hack to work around a weird limitation with the `bitvec` crate on
  492. * 32-bit platforms. For reasons beyond me right now, it can't operate on a `u64` on a 32-bit
  493. * platform, so we manually extract two `u32`s and stick them together. In the future, we should
  494. * definitely have a closer look at what `bitvec` is doing and see if we can fix this code, or
  495. * replace it with a different crate. This should hold everything vaguely together until we have
  496. * time to do that.
  497. */
  498. let mut upper = 0u32;
  499. let mut lower = 0u32;
  500. lower.view_bits_mut::<bitvec::order::Lsb0>()[0..32].clone_from_bitslice(bits);
  501. upper.view_bits_mut::<bitvec::order::Lsb0>()[0..(length - 32)].clone_from_bitslice(&bits[32..]);
  502. Ok(AmlValue::Integer((upper as u64) << 32 + (lower as u64)))
  503. } else {
  504. let mut value = 0u32;
  505. value.view_bits_mut::<bitvec::order::Lsb0>()[0..length].clone_from_bitslice(bits);
  506. Ok(AmlValue::Integer(value as u64))
  507. }
  508. } else {
  509. Err(AmlError::IncompatibleValueConversion { current: self.type_of(), target: AmlType::BufferField })
  510. }
  511. }
  512. pub fn write_buffer_field(&mut self, value: AmlValue, _context: &mut AmlContext) -> Result<(), AmlError> {
  513. use bitvec::view::BitView;
  514. if let AmlValue::BufferField { buffer_data, offset, length } = self {
  515. let offset = *offset as usize;
  516. let length = *length as usize;
  517. // TODO: check these against the size of the buffer to be written into
  518. let mut inner_data = buffer_data.lock();
  519. let bitslice = inner_data.view_bits_mut::<bitvec::order::Lsb0>();
  520. match value {
  521. AmlValue::Integer(value) => {
  522. /*
  523. * When an `Integer` is written into a `BufferField`, the entire contents are overwritten. If
  524. * it's smaller than the length of the buffer field, it's zero-extended. If it's larger, the
  525. * upper bits are truncated.
  526. */
  527. let bits_to_copy = cmp::min(length, 64);
  528. bitslice[offset..(offset + bits_to_copy)]
  529. .copy_from_bitslice(&value.to_le_bytes().view_bits()[..(bits_to_copy as usize)]);
  530. // Zero extend to the end of the buffer field
  531. bitslice[(offset + bits_to_copy)..(offset + length)].fill(false);
  532. Ok(())
  533. }
  534. AmlValue::Boolean(value) => {
  535. bitslice.set(offset, value);
  536. Ok(())
  537. }
  538. AmlValue::Buffer(value) => {
  539. /*
  540. * When a `Buffer` is written into a `BufferField`, the entire contents are copied into the
  541. * field. If the buffer is smaller than the size of the buffer field, it is zero extended. If
  542. * the buffer is larger, the upper bits are truncated.
  543. * XXX: this behaviour is only explicitly defined in ACPI 2.0+. While undefined in ACPI 1.0,
  544. * we produce the same behaviour there.
  545. */
  546. let value_data = value.lock();
  547. let bits_to_copy = cmp::min(length, value_data.len() * 8);
  548. bitslice[offset..(offset + bits_to_copy)]
  549. .copy_from_bitslice(&value_data.view_bits()[..(bits_to_copy as usize)]);
  550. // Zero extend to the end of the buffer field
  551. bitslice[(offset + bits_to_copy)..(offset + length)].fill(false);
  552. Ok(())
  553. }
  554. _ => Err(AmlError::TypeCannotBeWrittenToBufferField(value.type_of())),
  555. }
  556. } else {
  557. Err(AmlError::IncompatibleValueConversion { current: self.type_of(), target: AmlType::BufferField })
  558. }
  559. }
  560. /// Logically compare two `AmlValue`s, according to the rules that govern opcodes like `DefLEqual`, `DefLLess`,
  561. /// etc. The type of `self` dictates the type that `other` will be converted to, and the method by which the
  562. /// values will be compared:
  563. /// - `Integer`s are simply compared by numeric comparison
  564. /// - `String`s and `Buffer`s are compared lexicographically - `other` is compared byte-wise until a byte
  565. /// is discovered that is either less or greater than the corresponding byte of `self`. If the bytes are
  566. /// identical, the lengths are compared. Luckily, the Rust standard library implements lexicographic
  567. /// comparison of strings and `[u8]` for us already.
  568. pub fn cmp(&self, other: AmlValue, context: &mut AmlContext) -> Result<cmp::Ordering, AmlError> {
  569. let self_inner =
  570. if self.type_of() == AmlType::FieldUnit { self.read_field(context)? } else { self.clone() };
  571. match self_inner.type_of() {
  572. AmlType::Integer => Ok(self.as_integer(context)?.cmp(&other.as_integer(context)?)),
  573. AmlType::Buffer => Ok(self.as_buffer(context)?.lock().cmp(&other.as_buffer(context)?.lock())),
  574. AmlType::String => Ok(self.as_string(context)?.cmp(&other.as_string(context)?)),
  575. typ => Err(AmlError::TypeCannotBeCompared(typ)),
  576. }
  577. }
  578. }
  579. /// A control method can take up to 7 arguments, each of which is an `AmlValue`.
  580. #[derive(Clone, Default, Debug)]
  581. pub struct Args(pub [Option<AmlValue>; 7]);
  582. impl Args {
  583. pub const EMPTY: Self = Self([None, None, None, None, None, None, None]);
  584. pub fn from_list(list: Vec<AmlValue>) -> Result<Args, AmlError> {
  585. use core::convert::TryInto;
  586. if list.len() > 7 {
  587. return Err(AmlError::TooManyArgs);
  588. }
  589. let mut args: Vec<Option<AmlValue>> = list.into_iter().map(Option::Some).collect();
  590. args.extend(core::iter::repeat(None).take(7 - args.len()));
  591. Ok(Args(args.try_into().unwrap()))
  592. }
  593. pub fn arg(&self, arg: ArgNum) -> Result<&AmlValue, AmlError> {
  594. if arg > 6 {
  595. return Err(AmlError::InvalidArgAccess(arg));
  596. }
  597. self.0[arg as usize].as_ref().ok_or(AmlError::InvalidArgAccess(arg))
  598. }
  599. pub fn store_arg(&mut self, arg: ArgNum, value: AmlValue) -> Result<(), AmlError> {
  600. if arg > 6 {
  601. return Err(AmlError::InvalidArgAccess(arg));
  602. }
  603. self.0[arg as usize] = Some(value);
  604. Ok(())
  605. }
  606. }
  607. #[cfg(test)]
  608. mod tests {
  609. use super::*;
  610. use crate::test_utils::*;
  611. use core::cmp::Ordering;
  612. #[test]
  613. fn test_object_cmp() {
  614. let mut context = make_test_context();
  615. assert_eq!(AmlValue::Integer(76).cmp(AmlValue::Integer(89), &mut context), Ok(Ordering::Less));
  616. assert_eq!(AmlValue::Integer(11).cmp(AmlValue::Integer(11), &mut context), Ok(Ordering::Equal));
  617. assert_eq!(AmlValue::Integer(8362836690).cmp(AmlValue::Integer(1), &mut context), Ok(Ordering::Greater));
  618. // TODO: test the other combinations too, as well as conversions to the correct types for the second operand
  619. }
  620. }