value.rs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  1. use crate::{misc::ArgNum, AmlContext, AmlError, AmlHandle, AmlName};
  2. use alloc::{rc::Rc, string::String, vec::Vec};
  3. use bit_field::BitField;
  4. use core::{cmp, fmt, fmt::Debug};
  5. #[derive(Clone, Copy, PartialEq, Eq, Debug)]
  6. pub enum RegionSpace {
  7. SystemMemory,
  8. SystemIo,
  9. PciConfig,
  10. EmbeddedControl,
  11. SMBus,
  12. SystemCmos,
  13. PciBarTarget,
  14. IPMI,
  15. GeneralPurposeIo,
  16. GenericSerialBus,
  17. OemDefined(u8),
  18. }
  19. #[derive(Clone, Copy, PartialEq, Eq, Debug)]
  20. pub enum FieldAccessType {
  21. Any,
  22. Byte,
  23. Word,
  24. DWord,
  25. QWord,
  26. Buffer,
  27. }
  28. #[derive(Clone, Copy, PartialEq, Eq, Debug)]
  29. pub enum FieldUpdateRule {
  30. Preserve,
  31. WriteAsOnes,
  32. WriteAsZeros,
  33. }
  34. // TODO: custom debug impl
  35. #[derive(Clone, Copy, PartialEq, Eq, Debug)]
  36. pub struct FieldFlags(u8);
  37. impl FieldFlags {
  38. pub fn new(value: u8) -> FieldFlags {
  39. FieldFlags(value)
  40. }
  41. pub fn access_type(&self) -> Result<FieldAccessType, AmlError> {
  42. match self.0.get_bits(0..4) {
  43. 0 => Ok(FieldAccessType::Any),
  44. 1 => Ok(FieldAccessType::Byte),
  45. 2 => Ok(FieldAccessType::Word),
  46. 3 => Ok(FieldAccessType::DWord),
  47. 4 => Ok(FieldAccessType::QWord),
  48. 5 => Ok(FieldAccessType::Buffer),
  49. _ => Err(AmlError::InvalidFieldFlags),
  50. }
  51. }
  52. pub fn lock_rule(&self) -> bool {
  53. self.0.get_bit(4)
  54. }
  55. pub fn field_update_rule(&self) -> Result<FieldUpdateRule, AmlError> {
  56. match self.0.get_bits(5..7) {
  57. 0 => Ok(FieldUpdateRule::Preserve),
  58. 1 => Ok(FieldUpdateRule::WriteAsOnes),
  59. 2 => Ok(FieldUpdateRule::WriteAsZeros),
  60. _ => Err(AmlError::InvalidFieldFlags),
  61. }
  62. }
  63. }
  64. #[derive(Clone, Copy, PartialEq, Eq, Debug)]
  65. pub struct MethodFlags(u8);
  66. impl MethodFlags {
  67. pub fn new(value: u8) -> MethodFlags {
  68. MethodFlags(value)
  69. }
  70. pub fn arg_count(&self) -> u8 {
  71. self.0.get_bits(0..3)
  72. }
  73. pub fn serialize(&self) -> bool {
  74. self.0.get_bit(3)
  75. }
  76. pub fn sync_level(&self) -> u8 {
  77. self.0.get_bits(4..8)
  78. }
  79. }
  80. /// Representation of the return value of a `_STA` method, which represents the status of an object. It must be
  81. /// evaluated, if present, before evaluating the `_INI` method for an device.
  82. ///
  83. /// The `Default` implementation of this type is the correct value to use if a device doesn't have a `_STA` object
  84. /// to evaluate.
  85. #[derive(Clone, Copy, PartialEq, Eq, Debug)]
  86. pub struct StatusObject {
  87. /// Whether the device is physically present. If this is `false`, `enabled` should also be `false` (i.e. a
  88. /// device that is not present can't be enabled). However, this is not enforced here if the firmware is doing
  89. /// something wrong.
  90. pub present: bool,
  91. /// Whether the device is enabled. Both `present` and `enabled` must be `true` for the device to decode its
  92. /// hardware resources.
  93. pub enabled: bool,
  94. pub show_in_ui: bool,
  95. pub functional: bool,
  96. /// Only applicable for Control Method Battery Devices (`PNP0C0A`). For all other devices, ignore this value.
  97. pub battery_present: bool,
  98. }
  99. impl Default for StatusObject {
  100. fn default() -> Self {
  101. StatusObject { present: true, enabled: true, show_in_ui: true, functional: true, battery_present: true }
  102. }
  103. }
  104. #[derive(Clone, Copy, PartialEq, Eq, Debug)]
  105. pub enum AmlType {
  106. Uninitialized,
  107. Buffer,
  108. BufferField,
  109. /// Handle to a definition block handle. Returned by the `Load` operator.
  110. DdbHandle,
  111. DebugObject,
  112. Event,
  113. FieldUnit,
  114. Integer,
  115. Method,
  116. Mutex,
  117. ObjReference,
  118. OpRegion,
  119. Package,
  120. PowerResource,
  121. Processor,
  122. RawDataBuffer,
  123. String,
  124. ThermalZone,
  125. }
  126. #[derive(Clone)]
  127. pub enum MethodCode {
  128. Aml(Vec<u8>),
  129. Native(Rc<dyn Fn(&mut AmlContext) -> Result<AmlValue, AmlError>>),
  130. }
  131. impl fmt::Debug for MethodCode {
  132. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  133. match self {
  134. MethodCode::Aml(ref code) => f.debug_struct("AML method").field("code", code).finish(),
  135. MethodCode::Native(_) => f.debug_struct("Native method").finish(),
  136. }
  137. }
  138. }
  139. #[derive(Clone, Debug)]
  140. pub enum AmlValue {
  141. Boolean(bool),
  142. Integer(u64),
  143. String(String),
  144. /// Describes an operation region. Some regions require other objects to be declared under their parent device
  145. /// (e.g. an `_ADR` object for a `PciConfig` region), in which case an absolute path to the object is stored in
  146. /// `parent_device`.
  147. OpRegion {
  148. region: RegionSpace,
  149. offset: u64,
  150. length: u64,
  151. parent_device: Option<AmlName>,
  152. },
  153. /// Describes a field unit within an operation region.
  154. Field {
  155. region: AmlHandle,
  156. flags: FieldFlags,
  157. offset: u64,
  158. length: u64,
  159. },
  160. Method {
  161. flags: MethodFlags,
  162. code: MethodCode,
  163. },
  164. Buffer(Vec<u8>),
  165. Processor {
  166. id: u8,
  167. pblk_address: u32,
  168. pblk_len: u8,
  169. },
  170. Mutex {
  171. sync_level: u8,
  172. },
  173. Package(Vec<AmlValue>),
  174. }
  175. impl AmlValue {
  176. pub fn type_of(&self) -> AmlType {
  177. match self {
  178. AmlValue::Boolean(_) => AmlType::Integer,
  179. AmlValue::Integer(_) => AmlType::Integer,
  180. AmlValue::String(_) => AmlType::String,
  181. AmlValue::OpRegion { .. } => AmlType::OpRegion,
  182. AmlValue::Field { .. } => AmlType::FieldUnit,
  183. AmlValue::Method { .. } => AmlType::Method,
  184. AmlValue::Buffer(_) => AmlType::Buffer,
  185. AmlValue::Processor { .. } => AmlType::Processor,
  186. AmlValue::Mutex { .. } => AmlType::Mutex,
  187. AmlValue::Package(_) => AmlType::Package,
  188. }
  189. }
  190. pub fn as_bool(&self) -> Result<bool, AmlError> {
  191. match self {
  192. AmlValue::Boolean(value) => Ok(*value),
  193. AmlValue::Integer(value) => Ok(*value != 0),
  194. _ => Err(AmlError::IncompatibleValueConversion),
  195. }
  196. }
  197. pub fn as_integer(&self, context: &AmlContext) -> Result<u64, AmlError> {
  198. match self {
  199. AmlValue::Integer(value) => Ok(*value),
  200. AmlValue::Buffer(ref bytes) => {
  201. /*
  202. * "The first 8 bytes of the buffer are converted to an integer, taking the first
  203. * byte as the least significant byte of the integer. A zero-length buffer is
  204. * illegal." - §19.6.140
  205. *
  206. * XXX: Buffers with length `0` appear in real tables, so we return `0` for them.
  207. */
  208. let bytes = if bytes.len() > 8 { &bytes[0..8] } else { bytes };
  209. Ok(bytes.iter().rev().fold(0: u64, |mut i, &popped| {
  210. i <<= 8;
  211. i += popped as u64;
  212. i
  213. }))
  214. }
  215. /*
  216. * Read from a field. This can return either a `Buffer` or an `Integer`, so we make sure to call
  217. * `as_integer` on the result.
  218. */
  219. AmlValue::Field { .. } => self.read_field(context)?.as_integer(context),
  220. _ => Err(AmlError::IncompatibleValueConversion),
  221. }
  222. }
  223. pub fn as_buffer(&self, context: &AmlContext) -> Result<Vec<u8>, AmlError> {
  224. match self {
  225. AmlValue::Buffer(ref bytes) => Ok(bytes.clone()),
  226. // TODO: implement conversion of String and Integer to Buffer
  227. AmlValue::Field { .. } => self.read_field(context)?.as_buffer(context),
  228. _ => Err(AmlError::IncompatibleValueConversion),
  229. }
  230. }
  231. pub fn as_string(&self, context: &AmlContext) -> Result<String, AmlError> {
  232. match self {
  233. AmlValue::String(ref string) => Ok(string.clone()),
  234. // TODO: implement conversion of Buffer to String
  235. AmlValue::Field { .. } => self.read_field(context)?.as_string(context),
  236. _ => Err(AmlError::IncompatibleValueConversion),
  237. }
  238. }
  239. /// Turns an `AmlValue` returned from a `_STA` method into a `StatusObject`. Should only be called for values
  240. /// returned from `_STA`. If you need a `StatusObject`, but the device does not have a `_STA` method, use
  241. /// `StatusObject::default()`.
  242. pub fn as_status(&self) -> Result<StatusObject, AmlError> {
  243. match self {
  244. AmlValue::Integer(value) => {
  245. /*
  246. * Bits 5+ are reserved and are expected to be cleared.
  247. */
  248. if value.get_bits(5..64) != 0 {
  249. return Err(AmlError::InvalidStatusObject);
  250. }
  251. Ok(StatusObject {
  252. present: value.get_bit(0),
  253. enabled: value.get_bit(1),
  254. show_in_ui: value.get_bit(2),
  255. functional: value.get_bit(3),
  256. battery_present: value.get_bit(4),
  257. })
  258. }
  259. _ => Err(AmlError::InvalidStatusObject),
  260. }
  261. }
  262. /// Convert this value to a value of the same data, but with the given AML type, if possible,
  263. /// by converting the implicit conversions described in §19.3.5 of the spec.
  264. ///
  265. /// The implicit conversions applied are:
  266. /// `Buffer` from: `Integer`, `String`, `Debug`
  267. /// `BufferField` from: `Integer`, `Buffer`, `String`, `Debug`
  268. /// `DdbHandle` from: `Integer`, `Debug`
  269. /// `FieldUnit` from: `Integer`,`Buffer`, `String`, `Debug`
  270. /// `Integer` from: `Buffer`, `BufferField`, `DdbHandle`, `FieldUnit`, `String`, `Debug`
  271. /// `Package` from: `Debug`
  272. /// `String` from: `Integer`, `Buffer`, `Debug`
  273. pub fn as_type(&self, desired_type: AmlType, context: &AmlContext) -> Result<AmlValue, AmlError> {
  274. // If the value is already of the correct type, just return it as is
  275. if self.type_of() == desired_type {
  276. return Ok(self.clone());
  277. }
  278. // TODO: implement all of the rules
  279. match desired_type {
  280. AmlType::Integer => self.as_integer(context).map(|value| AmlValue::Integer(value)),
  281. AmlType::FieldUnit => panic!(
  282. "Can't implicitly convert to FieldUnit. This must be special-cased by the caller for now :("
  283. ),
  284. _ => Err(AmlError::IncompatibleValueConversion),
  285. }
  286. }
  287. /// Reads from a field of an opregion, returning either a `AmlValue::Integer` or an `AmlValue::Buffer`,
  288. /// depending on the size of the field.
  289. pub fn read_field(&self, context: &AmlContext) -> Result<AmlValue, AmlError> {
  290. if let AmlValue::Field { region, flags, offset, length } = self {
  291. let maximum_access_size = {
  292. if let AmlValue::OpRegion { region, .. } = context.namespace.get(*region)? {
  293. match region {
  294. RegionSpace::SystemMemory => 64,
  295. RegionSpace::SystemIo | RegionSpace::PciConfig => 32,
  296. _ => unimplemented!(),
  297. }
  298. } else {
  299. return Err(AmlError::FieldRegionIsNotOpRegion);
  300. }
  301. };
  302. let minimum_access_size = match flags.access_type()? {
  303. FieldAccessType::Any => 8,
  304. FieldAccessType::Byte => 8,
  305. FieldAccessType::Word => 16,
  306. FieldAccessType::DWord => 32,
  307. FieldAccessType::QWord => 64,
  308. FieldAccessType::Buffer => 8, // TODO
  309. };
  310. /*
  311. * Find the access size, as either the minimum access size allowed by the region, or the field length
  312. * rounded up to the next power-of-2, whichever is larger.
  313. */
  314. let access_size = u64::max(minimum_access_size, length.next_power_of_two());
  315. /*
  316. * TODO: we need to decide properly how to read from the region itself. Complications:
  317. * - if the region has a minimum access size greater than the desired length, we need to read the
  318. * minimum and mask it (reading a byte from a WordAcc region)
  319. * - if the desired length is larger than we can read, we need to do multiple reads
  320. */
  321. Ok(AmlValue::Integer(
  322. context.read_region(*region, *offset, access_size)?.get_bits(0..(*length as usize)),
  323. ))
  324. } else {
  325. Err(AmlError::IncompatibleValueConversion)
  326. }
  327. }
  328. pub fn write_field(&mut self, value: AmlValue, context: &mut AmlContext) -> Result<(), AmlError> {
  329. /*
  330. * If the field's update rule is `Preserve`, we need to read the initial value of the field, so we can
  331. * overwrite the correct bits. We destructure the field to do the actual write, so we read from it if
  332. * needed here, otherwise the borrow-checker doesn't understand.
  333. */
  334. let field_update_rule = if let AmlValue::Field { region, flags, offset, length } = self {
  335. flags.field_update_rule()?
  336. } else {
  337. return Err(AmlError::IncompatibleValueConversion);
  338. };
  339. let mut field_value = match field_update_rule {
  340. FieldUpdateRule::Preserve => self.read_field(context)?.as_integer(context)?,
  341. FieldUpdateRule::WriteAsOnes => 0xffffffff_ffffffff,
  342. FieldUpdateRule::WriteAsZeros => 0x0,
  343. };
  344. if let AmlValue::Field { region, flags, offset, length } = self {
  345. let maximum_access_size = {
  346. if let AmlValue::OpRegion { region, .. } = context.namespace.get(*region)? {
  347. match region {
  348. RegionSpace::SystemMemory => 64,
  349. RegionSpace::SystemIo | RegionSpace::PciConfig => 32,
  350. _ => unimplemented!(),
  351. }
  352. } else {
  353. return Err(AmlError::FieldRegionIsNotOpRegion);
  354. }
  355. };
  356. let minimum_access_size = match flags.access_type()? {
  357. FieldAccessType::Any => 8,
  358. FieldAccessType::Byte => 8,
  359. FieldAccessType::Word => 16,
  360. FieldAccessType::DWord => 32,
  361. FieldAccessType::QWord => 64,
  362. FieldAccessType::Buffer => 8, // TODO
  363. };
  364. /*
  365. * Find the access size, as either the minimum access size allowed by the region, or the field length
  366. * rounded up to the next power-of-2, whichever is larger.
  367. */
  368. let access_size = u64::max(minimum_access_size, length.next_power_of_two());
  369. field_value.set_bits(0..(*length as usize), value.as_integer(context)?);
  370. context.write_region(*region, *offset, access_size, field_value)
  371. } else {
  372. Err(AmlError::IncompatibleValueConversion)
  373. }
  374. }
  375. /// Logically compare two `AmlValue`s, according to the rules that govern opcodes like `DefLEqual`, `DefLLess`,
  376. /// etc. The type of `self` dictates the type that `other` will be converted to, and the method by which the
  377. /// values will be compared:
  378. /// - `Integer`s are simply compared by numeric comparison
  379. /// - `String`s and `Buffer`s are compared lexicographically - `other` is compared byte-wise until a byte
  380. /// is discovered that is either less or greater than the corresponding byte of `self`. If the bytes are
  381. /// identical, the lengths are compared. Luckily, the Rust standard library implements lexicographic
  382. /// comparison of strings and `[u8]` for us already.
  383. pub fn cmp(&self, other: AmlValue, context: &mut AmlContext) -> Result<cmp::Ordering, AmlError> {
  384. let self_inner =
  385. if self.type_of() == AmlType::FieldUnit { self.read_field(context)? } else { self.clone() };
  386. match self_inner.type_of() {
  387. AmlType::Integer => Ok(self.as_integer(context)?.cmp(&other.as_integer(context)?)),
  388. AmlType::Buffer => Ok(self.as_buffer(context)?.cmp(&other.as_buffer(context)?)),
  389. AmlType::String => Ok(self.as_string(context)?.cmp(&other.as_string(context)?)),
  390. typ => Err(AmlError::TypeCannotBeCompared(typ)),
  391. }
  392. }
  393. }
  394. /// A control method can take up to 7 arguments, each of which can be an `AmlValue`.
  395. #[derive(Clone, Debug, Default)]
  396. pub struct Args {
  397. pub arg_0: Option<AmlValue>,
  398. pub arg_1: Option<AmlValue>,
  399. pub arg_2: Option<AmlValue>,
  400. pub arg_3: Option<AmlValue>,
  401. pub arg_4: Option<AmlValue>,
  402. pub arg_5: Option<AmlValue>,
  403. pub arg_6: Option<AmlValue>,
  404. }
  405. impl Args {
  406. pub fn from_list(mut list: Vec<AmlValue>) -> Args {
  407. assert!(list.len() <= 7);
  408. list.reverse();
  409. Args {
  410. arg_0: list.pop(),
  411. arg_1: list.pop(),
  412. arg_2: list.pop(),
  413. arg_3: list.pop(),
  414. arg_4: list.pop(),
  415. arg_5: list.pop(),
  416. arg_6: list.pop(),
  417. }
  418. }
  419. /// Get an argument by its `ArgNum`.
  420. ///
  421. /// ### Panics
  422. /// Panics if passed an invalid argument number (valid argument numbers are `0..=6`)
  423. pub fn arg(&self, num: ArgNum) -> Result<&AmlValue, AmlError> {
  424. match num {
  425. 0 => self.arg_0.as_ref().ok_or(AmlError::InvalidArgAccess(num)),
  426. 1 => self.arg_1.as_ref().ok_or(AmlError::InvalidArgAccess(num)),
  427. 2 => self.arg_2.as_ref().ok_or(AmlError::InvalidArgAccess(num)),
  428. 3 => self.arg_3.as_ref().ok_or(AmlError::InvalidArgAccess(num)),
  429. 4 => self.arg_4.as_ref().ok_or(AmlError::InvalidArgAccess(num)),
  430. 5 => self.arg_5.as_ref().ok_or(AmlError::InvalidArgAccess(num)),
  431. 6 => self.arg_6.as_ref().ok_or(AmlError::InvalidArgAccess(num)),
  432. _ => Err(AmlError::InvalidArgAccess(num)),
  433. }
  434. }
  435. }
  436. #[cfg(test)]
  437. mod tests {
  438. use super::*;
  439. use crate::{test_utils::*, AmlError};
  440. use core::cmp::Ordering;
  441. #[test]
  442. fn test_object_cmp() {
  443. let mut context = make_test_context();
  444. assert_eq!(AmlValue::Integer(76).cmp(AmlValue::Integer(89), &mut context), Ok(Ordering::Less));
  445. assert_eq!(AmlValue::Integer(11).cmp(AmlValue::Integer(11), &mut context), Ok(Ordering::Equal));
  446. assert_eq!(AmlValue::Integer(8362836690).cmp(AmlValue::Integer(1), &mut context), Ok(Ordering::Greater));
  447. assert_eq!(
  448. AmlValue::Integer(4).cmp(AmlValue::Boolean(true), &mut context),
  449. Err(AmlError::IncompatibleValueConversion)
  450. );
  451. // TODO: test the other combinations too, as well as conversions to the correct types for the second operand
  452. }
  453. }