value.rs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. use crate::{misc::ArgNum, AmlContext, AmlError, AmlHandle, AmlName};
  2. use alloc::{string::String, vec::Vec};
  3. use bit_field::BitField;
  4. use core::convert::TryInto;
  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. Reserved,
  28. }
  29. #[derive(Clone, Copy, PartialEq, Eq, Debug)]
  30. pub enum FieldUpdateRule {
  31. Preserve,
  32. WriteAsOnes,
  33. WriteAsZeros,
  34. }
  35. // TODO: custom debug impl
  36. #[derive(Clone, Copy, PartialEq, Eq, Debug)]
  37. pub struct FieldFlags(u8);
  38. impl FieldFlags {
  39. pub fn new(value: u8) -> FieldFlags {
  40. FieldFlags(value)
  41. }
  42. pub fn access_type(&self) -> Result<FieldAccessType, AmlError> {
  43. match self.0.get_bits(0..4) {
  44. 0 => Ok(FieldAccessType::Any),
  45. 1 => Ok(FieldAccessType::Byte),
  46. 2 => Ok(FieldAccessType::Word),
  47. 3 => Ok(FieldAccessType::DWord),
  48. 4 => Ok(FieldAccessType::QWord),
  49. 5 => Ok(FieldAccessType::Buffer),
  50. _ => Err(AmlError::InvalidFieldFlags),
  51. }
  52. }
  53. pub fn lock_rule(&self) -> bool {
  54. self.0.get_bit(4)
  55. }
  56. pub fn field_update_rule(&self) -> Result<FieldUpdateRule, AmlError> {
  57. match self.0.get_bits(5..7) {
  58. 0 => Ok(FieldUpdateRule::Preserve),
  59. 1 => Ok(FieldUpdateRule::WriteAsOnes),
  60. 2 => Ok(FieldUpdateRule::WriteAsZeros),
  61. _ => Err(AmlError::InvalidFieldFlags),
  62. }
  63. }
  64. }
  65. #[derive(Clone, Copy, PartialEq, Eq, Debug)]
  66. pub struct MethodFlags(u8);
  67. impl MethodFlags {
  68. pub fn new(value: u8) -> MethodFlags {
  69. MethodFlags(value)
  70. }
  71. pub fn arg_count(&self) -> u8 {
  72. self.0.get_bits(0..3)
  73. }
  74. pub fn serialize(&self) -> bool {
  75. self.0.get_bit(3)
  76. }
  77. pub fn sync_level(&self) -> u8 {
  78. self.0.get_bits(4..8)
  79. }
  80. }
  81. /// Representation of the return value of a `_STA` method, which represents the status of an object. It must be
  82. /// evaluated, if present, before evaluating the `_INI` method for an device.
  83. ///
  84. /// The `Default` implementation of this type is the correct value to use if a device doesn't have a `_STA` object
  85. /// to evaluate.
  86. #[derive(Clone, Copy, PartialEq, Eq, Debug)]
  87. pub struct StatusObject {
  88. /// Whether the device is physically present. If this is `false`, `enabled` should also be `false` (i.e. a
  89. /// device that is not present can't be enabled). However, this is not enforced here if the firmware is doing
  90. /// something wrong.
  91. present: bool,
  92. /// Whether the device is enabled. Both `present` and `enabled` must be `true` for the device to decode its
  93. /// hardware resources.
  94. enabled: bool,
  95. show_in_ui: bool,
  96. functioning: bool,
  97. /// Only applicable for Control Method Battery Devices (`PNP0C0A`). For all other devices, ignore this value.
  98. battery_present: bool,
  99. }
  100. impl Default for StatusObject {
  101. fn default() -> Self {
  102. StatusObject { present: true, enabled: true, show_in_ui: true, functioning: true, battery_present: true }
  103. }
  104. }
  105. #[derive(Clone, Copy, PartialEq, Eq, Debug)]
  106. pub enum AmlType {
  107. Uninitialized,
  108. Buffer,
  109. BufferField,
  110. /// Handle to a definition block handle. Returned by the `Load` operator.
  111. DdbHandle,
  112. DebugObject,
  113. Event,
  114. FieldUnit,
  115. Integer,
  116. Method,
  117. Mutex,
  118. ObjReference,
  119. OpRegion,
  120. Package,
  121. PowerResource,
  122. Processor,
  123. RawDataBuffer,
  124. String,
  125. ThermalZone,
  126. }
  127. #[derive(Clone, PartialEq, Eq, Debug)]
  128. pub enum AmlValue {
  129. Boolean(bool),
  130. Integer(u64),
  131. String(String),
  132. /// Describes an operation region. Some regions require other objects to be declared under their parent device
  133. /// (e.g. an `_ADR` object for a `PciConfig` region), in which case an absolute path to the object is stored in
  134. /// `parent_device`.
  135. OpRegion {
  136. region: RegionSpace,
  137. offset: u64,
  138. length: u64,
  139. parent_device: Option<AmlName>,
  140. },
  141. /// Describes a field unit within an operation region.
  142. Field {
  143. region: AmlHandle,
  144. flags: FieldFlags,
  145. offset: u64,
  146. length: u64,
  147. },
  148. Method {
  149. flags: MethodFlags,
  150. code: Vec<u8>,
  151. },
  152. Buffer {
  153. bytes: Vec<u8>,
  154. size: u64,
  155. },
  156. Processor {
  157. id: u8,
  158. pblk_address: u32,
  159. pblk_len: u8,
  160. },
  161. Mutex {
  162. sync_level: u8,
  163. },
  164. Package(Vec<AmlValue>),
  165. }
  166. impl AmlValue {
  167. /// Returns the AML type of this value. For `Name`, this returns the type of the inner value.
  168. pub fn type_of(&self) -> AmlType {
  169. match self {
  170. AmlValue::Boolean(_) => AmlType::Integer,
  171. AmlValue::Integer(_) => AmlType::Integer,
  172. AmlValue::String(_) => AmlType::String,
  173. AmlValue::OpRegion { .. } => AmlType::OpRegion,
  174. AmlValue::Field { .. } => AmlType::FieldUnit,
  175. AmlValue::Method { .. } => AmlType::Method,
  176. AmlValue::Buffer { .. } => AmlType::Buffer,
  177. AmlValue::Processor { .. } => AmlType::Processor,
  178. AmlValue::Mutex { .. } => AmlType::Mutex,
  179. AmlValue::Package(_) => AmlType::Package,
  180. }
  181. }
  182. pub fn as_bool(&self) -> Result<bool, AmlError> {
  183. match self {
  184. AmlValue::Boolean(value) => Ok(*value),
  185. AmlValue::Integer(value) => Ok(*value != 0),
  186. _ => Err(AmlError::IncompatibleValueConversion),
  187. }
  188. }
  189. pub fn as_integer(&self, context: &AmlContext) -> Result<u64, AmlError> {
  190. match self {
  191. AmlValue::Integer(value) => Ok(*value),
  192. AmlValue::Buffer { ref bytes, .. } => {
  193. /*
  194. * "The first 8 bytes of the buffer are converted to an integer, taking the first
  195. * byte as the least significant byte of the integer. A zero-length buffer is
  196. * illegal." - §19.6.140
  197. *
  198. * XXX: We return `0` for zero-length buffers because they literally occur in
  199. * the reference implementation.
  200. */
  201. let bytes = if bytes.len() > 8 { &bytes[0..8] } else { bytes };
  202. Ok(bytes.iter().rev().fold(0: u64, |mut i, &popped| {
  203. i <<= 8;
  204. i += popped as u64;
  205. i
  206. }))
  207. }
  208. /*
  209. * Read from a field. This can return either a `Buffer` or an `Integer`, so we make sure to call
  210. * `as_integer` on the result.
  211. */
  212. AmlValue::Field { .. } => self.read_field(context)?.as_integer(context),
  213. _ => Err(AmlError::IncompatibleValueConversion),
  214. }
  215. }
  216. /// Turns an `AmlValue` returned from a `_STA` method into a `StatusObject`. Should only be called for values
  217. /// returned from `_STA`. If you need a `StatusObject`, but the device does not have a `_STA` method, use
  218. /// `StatusObject::default()`.
  219. pub fn as_status(&self) -> Result<StatusObject, AmlError> {
  220. match self {
  221. AmlValue::Integer(value) => {
  222. /*
  223. * Bits 5+ are reserved and are expected to be cleared.
  224. */
  225. if value.get_bits(5..64) != 0 {
  226. return Err(AmlError::InvalidStatusObject);
  227. }
  228. Ok(StatusObject {
  229. present: value.get_bit(0),
  230. enabled: value.get_bit(1),
  231. show_in_ui: value.get_bit(2),
  232. functioning: value.get_bit(3),
  233. battery_present: value.get_bit(4),
  234. })
  235. }
  236. _ => Err(AmlError::InvalidStatusObject),
  237. }
  238. }
  239. /// Convert this value to a value of the same data, but with the given AML type, if possible,
  240. /// by converting the implicit conversions described in §19.3.5 of the spec.
  241. ///
  242. /// The implicit conversions applied are:
  243. /// `Buffer` from: `Integer`, `String`, `Debug`
  244. /// `BufferField` from: `Integer`, `Buffer`, `String`, `Debug`
  245. /// `DdbHandle` from: `Integer`, `Debug`
  246. /// `FieldUnit` from: `Integer`,`Buffer`, `String`, `Debug`
  247. /// `Integer` from: `Buffer`, `BufferField`, `DdbHandle`, `FieldUnit`, `String`, `Debug`
  248. /// `Package` from: `Debug`
  249. /// `String` from: `Integer`, `Buffer`, `Debug`
  250. pub fn as_type(&self, desired_type: AmlType, context: &AmlContext) -> Result<AmlValue, AmlError> {
  251. // Cache the type of this object
  252. let our_type = self.type_of();
  253. // If the value is already of the correct type, just return it as is
  254. if our_type == desired_type {
  255. return Ok(self.clone());
  256. }
  257. // TODO: implement all of the rules
  258. match desired_type {
  259. AmlType::Integer => self.as_integer(context).map(|value| AmlValue::Integer(value)),
  260. _ => Err(AmlError::IncompatibleValueConversion),
  261. }
  262. }
  263. /// Reads from a field of an opregion, returning either a `AmlValue::Integer` or an `AmlValue::Buffer`,
  264. /// depending on the size of the field.
  265. pub fn read_field(&self, context: &AmlContext) -> Result<AmlValue, AmlError> {
  266. if let AmlValue::Field { region, flags, offset, length } = self {
  267. let (region_space, region_base, region_length, parent_device) = {
  268. if let AmlValue::OpRegion { region, offset, length, parent_device } =
  269. context.namespace.get(*region)?
  270. {
  271. (region, offset, length, parent_device)
  272. } else {
  273. return Err(AmlError::FieldRegionIsNotOpRegion);
  274. }
  275. };
  276. match region_space {
  277. RegionSpace::SystemMemory => {
  278. let address = (region_base + offset).try_into().map_err(|_| AmlError::FieldInvalidAddress)?;
  279. match length {
  280. 8 => Ok(AmlValue::Integer(context.handler.read_u8(address) as u64)),
  281. 16 => Ok(AmlValue::Integer(context.handler.read_u16(address) as u64)),
  282. 32 => Ok(AmlValue::Integer(context.handler.read_u32(address) as u64)),
  283. 64 => Ok(AmlValue::Integer(context.handler.read_u64(address))),
  284. _ => Err(AmlError::FieldInvalidAccessSize),
  285. }
  286. }
  287. RegionSpace::SystemIo => {
  288. let port = (region_base + offset).try_into().map_err(|_| AmlError::FieldInvalidAddress)?;
  289. match length {
  290. 8 => Ok(AmlValue::Integer(context.handler.read_io_u8(port) as u64)),
  291. 16 => Ok(AmlValue::Integer(context.handler.read_io_u16(port) as u64)),
  292. 32 => Ok(AmlValue::Integer(context.handler.read_io_u32(port) as u64)),
  293. _ => Err(AmlError::FieldInvalidAccessSize),
  294. }
  295. }
  296. // TODO
  297. _ => unimplemented!(),
  298. }
  299. } else {
  300. Err(AmlError::IncompatibleValueConversion)
  301. }
  302. }
  303. }
  304. /// A control method can take up to 7 arguments, each of which can be an `AmlValue`.
  305. #[derive(Clone, Debug, Default)]
  306. pub struct Args {
  307. pub arg_0: Option<AmlValue>,
  308. pub arg_1: Option<AmlValue>,
  309. pub arg_2: Option<AmlValue>,
  310. pub arg_3: Option<AmlValue>,
  311. pub arg_4: Option<AmlValue>,
  312. pub arg_5: Option<AmlValue>,
  313. pub arg_6: Option<AmlValue>,
  314. }
  315. impl Args {
  316. pub fn from_list(mut list: Vec<AmlValue>) -> Args {
  317. assert!(list.len() <= 7);
  318. list.reverse();
  319. Args {
  320. arg_0: list.pop(),
  321. arg_1: list.pop(),
  322. arg_2: list.pop(),
  323. arg_3: list.pop(),
  324. arg_4: list.pop(),
  325. arg_5: list.pop(),
  326. arg_6: list.pop(),
  327. }
  328. }
  329. /// Get an argument by its `ArgNum`.
  330. ///
  331. /// ### Panics
  332. /// Panics if passed an invalid argument number (valid argument numbers are `0..=6`)
  333. pub fn arg(&self, num: ArgNum) -> Result<&AmlValue, AmlError> {
  334. match num {
  335. 0 => self.arg_0.as_ref().ok_or(AmlError::InvalidArgAccess(num)),
  336. 1 => self.arg_1.as_ref().ok_or(AmlError::InvalidArgAccess(num)),
  337. 2 => self.arg_2.as_ref().ok_or(AmlError::InvalidArgAccess(num)),
  338. 3 => self.arg_3.as_ref().ok_or(AmlError::InvalidArgAccess(num)),
  339. 4 => self.arg_4.as_ref().ok_or(AmlError::InvalidArgAccess(num)),
  340. 5 => self.arg_5.as_ref().ok_or(AmlError::InvalidArgAccess(num)),
  341. 6 => self.arg_6.as_ref().ok_or(AmlError::InvalidArgAccess(num)),
  342. _ => Err(AmlError::InvalidArgAccess(num)),
  343. }
  344. }
  345. }