value.rs 20 KB

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