1use crate::{misc::ArgNum, AmlContext, AmlError, AmlHandle, AmlName};
2use alloc::{
3 string::{String, ToString},
4 sync::Arc,
5 vec::Vec,
6};
7use bit_field::BitField;
8use core::{cmp, fmt, fmt::Debug};
9use spinning_top::Spinlock;
10
11#[derive(Clone, Copy, PartialEq, Eq, Debug)]
12pub enum RegionSpace {
13 SystemMemory,
14 SystemIo,
15 PciConfig,
16 EmbeddedControl,
17 SMBus,
18 SystemCmos,
19 PciBarTarget,
20 IPMI,
21 GeneralPurposeIo,
22 GenericSerialBus,
23 OemDefined(u8),
24}
25
26#[derive(Clone, Copy, PartialEq, Eq, Debug)]
27pub enum FieldAccessType {
28 Any,
29 Byte,
30 Word,
31 DWord,
32 QWord,
33 Buffer,
34}
35
36#[derive(Clone, Copy, PartialEq, Eq, Debug)]
37pub enum FieldUpdateRule {
38 Preserve,
39 WriteAsOnes,
40 WriteAsZeros,
41}
42
43#[derive(Clone, Copy, PartialEq, Eq, Debug)]
45pub struct FieldFlags(u8);
46
47impl FieldFlags {
48 pub fn new(value: u8) -> FieldFlags {
49 FieldFlags(value)
50 }
51
52 pub fn access_type(&self) -> Result<FieldAccessType, AmlError> {
53 match self.0.get_bits(0..4) {
54 0 => Ok(FieldAccessType::Any),
55 1 => Ok(FieldAccessType::Byte),
56 2 => Ok(FieldAccessType::Word),
57 3 => Ok(FieldAccessType::DWord),
58 4 => Ok(FieldAccessType::QWord),
59 5 => Ok(FieldAccessType::Buffer),
60 _ => Err(AmlError::InvalidFieldFlags),
61 }
62 }
63
64 pub fn lock_rule(&self) -> bool {
65 self.0.get_bit(4)
66 }
67
68 pub fn field_update_rule(&self) -> Result<FieldUpdateRule, AmlError> {
69 match self.0.get_bits(5..7) {
70 0 => Ok(FieldUpdateRule::Preserve),
71 1 => Ok(FieldUpdateRule::WriteAsOnes),
72 2 => Ok(FieldUpdateRule::WriteAsZeros),
73 _ => Err(AmlError::InvalidFieldFlags),
74 }
75 }
76}
77
78#[derive(Clone, Copy, PartialEq, Eq, Debug)]
79pub struct MethodFlags(u8);
80
81impl MethodFlags {
82 pub fn new(arg_count: u8, serialize: bool, sync_level: u8) -> MethodFlags {
83 assert!(arg_count <= 7);
84 assert!(sync_level <= 15);
85
86 let mut value = 0;
87 value.set_bits(0..3, arg_count);
88 value.set_bit(3, serialize);
89 value.set_bits(4..8, sync_level);
90 MethodFlags(value)
91 }
92
93 pub fn from(value: u8) -> MethodFlags {
94 MethodFlags(value)
95 }
96
97 pub fn arg_count(&self) -> u8 {
98 self.0.get_bits(0..3)
99 }
100
101 pub fn serialize(&self) -> bool {
102 self.0.get_bit(3)
103 }
104
105 pub fn sync_level(&self) -> u8 {
106 self.0.get_bits(4..8)
107 }
108}
109
110#[derive(Clone, Copy, PartialEq, Eq, Debug)]
116pub struct StatusObject {
117 pub present: bool,
121 pub enabled: bool,
124 pub show_in_ui: bool,
125 pub functional: bool,
126 pub battery_present: bool,
128}
129
130impl Default for StatusObject {
131 fn default() -> Self {
132 StatusObject {
133 present: true,
134 enabled: true,
135 show_in_ui: true,
136 functional: true,
137 battery_present: true,
138 }
139 }
140}
141
142#[derive(Clone, Copy, PartialEq, Eq, Debug)]
143pub enum AmlType {
144 Uninitialized,
145 Buffer,
146 BufferField,
147 DdbHandle,
149 DebugObject,
150 Event,
151 FieldUnit,
152 Device,
153 Integer,
154 Method,
155 Mutex,
156 ObjReference,
157 OpRegion,
158 Package,
159 PowerResource,
160 Processor,
161 RawDataBuffer,
162 String,
163 ThermalZone,
164}
165
166#[derive(Clone)]
167pub enum MethodCode {
168 Aml(Vec<u8>),
169 Native(Arc<dyn Fn(&mut AmlContext) -> Result<AmlValue, AmlError> + Send + Sync>),
170}
171
172impl fmt::Debug for MethodCode {
173 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
174 match self {
175 MethodCode::Aml(ref code) => write!(f, "AML({:x?})", code),
176 MethodCode::Native(_) => write!(f, "(native method)"),
177 }
178 }
179}
180
181#[derive(Clone, Debug)]
182pub enum AmlValue {
183 Boolean(bool),
184 Integer(u64),
185 String(String),
186 OpRegion {
190 region: RegionSpace,
191 offset: u64,
192 length: u64,
193 parent_device: Option<AmlName>,
194 },
195 Field {
197 region: AmlHandle,
198 flags: FieldFlags,
199 offset: u64,
200 length: u64,
201 },
202 Device,
203 Method {
204 flags: MethodFlags,
205 code: MethodCode,
206 },
207 Buffer(Arc<Spinlock<Vec<u8>>>),
208 BufferField {
209 buffer_data: Arc<Spinlock<Vec<u8>>>,
210 offset: u64,
212 length: u64,
214 },
215 Processor {
216 id: u8,
217 pblk_address: u32,
218 pblk_len: u8,
219 },
220 Mutex {
221 sync_level: u8,
222 },
223 Package(Vec<AmlValue>),
225 PowerResource {
226 system_level: u8,
227 resource_order: u16,
228 },
229 ThermalZone,
230}
231
232impl AmlValue {
233 pub fn zero() -> AmlValue {
234 AmlValue::Integer(0)
235 }
236
237 pub fn one() -> AmlValue {
238 AmlValue::Integer(1)
239 }
240
241 pub fn ones() -> AmlValue {
242 AmlValue::Integer(u64::max_value())
243 }
244
245 pub fn native_method<F>(arg_count: u8, serialize: bool, sync_level: u8, f: F) -> AmlValue
246 where
247 F: (Fn(&mut AmlContext) -> Result<AmlValue, AmlError>) + 'static + Send + Sync,
248 {
249 let flags = MethodFlags::new(arg_count, serialize, sync_level);
250 AmlValue::Method {
251 flags,
252 code: MethodCode::Native(Arc::new(f)),
253 }
254 }
255
256 pub fn type_of(&self) -> AmlType {
257 match self {
258 AmlValue::Boolean(_) => AmlType::Integer,
259 AmlValue::Integer(_) => AmlType::Integer,
260 AmlValue::String(_) => AmlType::String,
261 AmlValue::OpRegion { .. } => AmlType::OpRegion,
262 AmlValue::Field { .. } => AmlType::FieldUnit,
263 AmlValue::Device => AmlType::Device,
264 AmlValue::Method { .. } => AmlType::Method,
265 AmlValue::Buffer(_) => AmlType::Buffer,
266 AmlValue::BufferField { .. } => AmlType::BufferField,
267 AmlValue::Processor { .. } => AmlType::Processor,
268 AmlValue::Mutex { .. } => AmlType::Mutex,
269 AmlValue::Package(_) => AmlType::Package,
270 AmlValue::PowerResource { .. } => AmlType::PowerResource,
271 AmlValue::ThermalZone => AmlType::ThermalZone,
272 }
273 }
274
275 pub fn as_bool(&self) -> Result<bool, AmlError> {
276 match self {
277 AmlValue::Boolean(value) => Ok(*value),
278 AmlValue::Integer(value) => Ok(*value != 0),
279 _ => Err(AmlError::IncompatibleValueConversion {
280 current: self.type_of(),
281 target: AmlType::Integer,
282 }),
283 }
284 }
285
286 pub fn as_integer(&self, context: &AmlContext) -> Result<u64, AmlError> {
287 match self {
288 AmlValue::Integer(value) => Ok(*value),
289 AmlValue::Boolean(value) => Ok(if *value { u64::max_value() } else { 0 }),
290 AmlValue::Buffer(ref bytes) => {
291 let bytes = bytes.lock();
299 let bytes = if bytes.len() > 8 {
300 &bytes[0..8]
301 } else {
302 &bytes[..]
303 };
304
305 Ok(bytes.iter().rev().fold(0u64, |mut i, &popped| {
306 i <<= 8;
307 i += popped as u64;
308 i
309 }))
310 }
311 AmlValue::Field { .. } => self.read_field(context)?.as_integer(context),
316 AmlValue::BufferField { .. } => self.read_buffer_field(context)?.as_integer(context),
317
318 _ => Err(AmlError::IncompatibleValueConversion {
319 current: self.type_of(),
320 target: AmlType::Integer,
321 }),
322 }
323 }
324
325 pub fn as_buffer(&self, context: &AmlContext) -> Result<Arc<Spinlock<Vec<u8>>>, AmlError> {
326 match self {
327 AmlValue::Buffer(ref bytes) => Ok(bytes.clone()),
328 AmlValue::Field { .. } => self.read_field(context)?.as_buffer(context),
330 AmlValue::BufferField { .. } => self.read_buffer_field(context)?.as_buffer(context),
331 _ => Err(AmlError::IncompatibleValueConversion {
332 current: self.type_of(),
333 target: AmlType::Buffer,
334 }),
335 }
336 }
337
338 pub fn as_string(&self, context: &AmlContext) -> Result<String, AmlError> {
339 match self {
340 AmlValue::String(ref string) => Ok(string.clone()),
341 AmlValue::Field { .. } => self.read_field(context)?.as_string(context),
343 _ => Err(AmlError::IncompatibleValueConversion {
344 current: self.type_of(),
345 target: AmlType::String,
346 }),
347 }
348 }
349
350 pub fn as_concat_type(&self) -> AmlValue {
354 match self.type_of() {
355 AmlType::Integer => self.clone(),
356 AmlType::String => self.clone(),
357 AmlType::Buffer => self.clone(),
358
359 AmlType::Uninitialized => AmlValue::String("[Uninitialized]".to_string()),
360 AmlType::BufferField => AmlValue::String("[Buffer Field]".to_string()),
361 AmlType::DdbHandle => AmlValue::String("[Ddb Handle]".to_string()),
362 AmlType::DebugObject => AmlValue::String("[Debug Object]".to_string()),
363 AmlType::Event => AmlValue::String("[Event]".to_string()),
364 AmlType::FieldUnit => AmlValue::String("[Field]".to_string()),
365 AmlType::Device => AmlValue::String("[Device]".to_string()),
366 AmlType::Method => AmlValue::String("[Control Method]".to_string()),
367 AmlType::Mutex => AmlValue::String("[Mutex]".to_string()),
368 AmlType::ObjReference => AmlValue::String("[Obj Reference]".to_string()),
369 AmlType::OpRegion => AmlValue::String("[Operation Region]".to_string()),
370 AmlType::Package => AmlValue::String("[Package]".to_string()),
371 AmlType::Processor => AmlValue::String("[Processor]".to_string()),
372 AmlType::PowerResource => AmlValue::String("[Power Resource]".to_string()),
373 AmlType::RawDataBuffer => AmlValue::String("[Raw Data Buffer]".to_string()),
374 AmlType::ThermalZone => AmlValue::String("[Thermal Zone]".to_string()),
375 }
376 }
377
378 pub fn as_status(&self) -> Result<StatusObject, AmlError> {
382 match self {
383 AmlValue::Integer(value) => {
384 if value.get_bits(5..64) != 0 {
388 return Err(AmlError::InvalidStatusObject);
389 }
390
391 Ok(StatusObject {
392 present: value.get_bit(0),
393 enabled: value.get_bit(1),
394 show_in_ui: value.get_bit(2),
395 functional: value.get_bit(3),
396 battery_present: value.get_bit(4),
397 })
398 }
399
400 _ => Err(AmlError::InvalidStatusObject),
401 }
402 }
403
404 pub fn as_type(
416 &self,
417 desired_type: AmlType,
418 context: &AmlContext,
419 ) -> Result<AmlValue, AmlError> {
420 if self.type_of() == desired_type {
422 return Ok(self.clone());
423 }
424
425 match desired_type {
427 AmlType::Integer => self.as_integer(context).map(|value| AmlValue::Integer(value)),
428 AmlType::Buffer => self.as_buffer(context).map(|value| AmlValue::Buffer(value)),
429 AmlType::FieldUnit => panic!(
430 "Can't implicitly convert to FieldUnit. This must be special-cased by the caller for now :("
431 ),
432 _ => Err(AmlError::IncompatibleValueConversion { current: self.type_of(), target: desired_type }),
433 }
434 }
435
436 pub fn read_field(&self, context: &AmlContext) -> Result<AmlValue, AmlError> {
439 if let AmlValue::Field {
440 region,
441 flags,
442 offset,
443 length,
444 } = self
445 {
446 let _maximum_access_size = {
447 if let AmlValue::OpRegion { region, .. } = context.namespace.get(*region)? {
448 match region {
449 RegionSpace::SystemMemory => 64,
450 RegionSpace::SystemIo | RegionSpace::PciConfig => 32,
451 _ => unimplemented!(),
452 }
453 } else {
454 return Err(AmlError::FieldRegionIsNotOpRegion);
455 }
456 };
457 let minimum_access_size = match flags.access_type()? {
458 FieldAccessType::Any => 8,
459 FieldAccessType::Byte => 8,
460 FieldAccessType::Word => 16,
461 FieldAccessType::DWord => 32,
462 FieldAccessType::QWord => 64,
463 FieldAccessType::Buffer => 8, };
465
466 let access_size = u64::max(minimum_access_size, length.next_power_of_two());
471
472 Ok(AmlValue::Integer(
479 context
480 .read_region(*region, *offset, access_size)?
481 .get_bits(0..(*length as usize)),
482 ))
483 } else {
484 Err(AmlError::IncompatibleValueConversion {
485 current: self.type_of(),
486 target: AmlType::FieldUnit,
487 })
488 }
489 }
490
491 pub fn write_field(
492 &mut self,
493 value: AmlValue,
494 context: &mut AmlContext,
495 ) -> Result<(), AmlError> {
496 let field_update_rule = if let AmlValue::Field { flags, .. } = self {
502 flags.field_update_rule()?
503 } else {
504 return Err(AmlError::IncompatibleValueConversion {
505 current: self.type_of(),
506 target: AmlType::FieldUnit,
507 });
508 };
509 let mut field_value = match field_update_rule {
510 FieldUpdateRule::Preserve => self.read_field(context)?.as_integer(context)?,
511 FieldUpdateRule::WriteAsOnes => 0xffffffff_ffffffff,
512 FieldUpdateRule::WriteAsZeros => 0x0,
513 };
514
515 if let AmlValue::Field {
516 region,
517 flags,
518 offset,
519 length,
520 } = self
521 {
522 let _maximum_access_size = {
523 if let AmlValue::OpRegion { region, .. } = context.namespace.get(*region)? {
524 match region {
525 RegionSpace::SystemMemory => 64,
526 RegionSpace::SystemIo | RegionSpace::PciConfig => 32,
527 _ => unimplemented!(),
528 }
529 } else {
530 return Err(AmlError::FieldRegionIsNotOpRegion);
531 }
532 };
533 let minimum_access_size = match flags.access_type()? {
534 FieldAccessType::Any => 8,
535 FieldAccessType::Byte => 8,
536 FieldAccessType::Word => 16,
537 FieldAccessType::DWord => 32,
538 FieldAccessType::QWord => 64,
539 FieldAccessType::Buffer => 8, };
541
542 let access_size = u64::max(minimum_access_size, length.next_power_of_two());
547
548 field_value.set_bits(0..(*length as usize), value.as_integer(context)?);
549 context.write_region(*region, *offset, access_size, field_value)
550 } else {
551 Err(AmlError::IncompatibleValueConversion {
552 current: self.type_of(),
553 target: AmlType::FieldUnit,
554 })
555 }
556 }
557
558 pub fn read_buffer_field(&self, _context: &AmlContext) -> Result<AmlValue, AmlError> {
559 use bitvec::view::BitView;
560
561 if let AmlValue::BufferField {
562 buffer_data,
563 offset,
564 length,
565 } = self
566 {
567 let offset = *offset as usize;
568 let length = *length as usize;
569 let inner_data = buffer_data.lock();
570
571 if (offset + length) > (inner_data.len() * 8) {
572 return Err(AmlError::BufferFieldIndexesOutOfBounds);
573 }
574
575 let bitslice = inner_data.view_bits::<bitvec::order::Lsb0>();
576 let bits = &bitslice[offset..(offset + length)];
577
578 if length > 64 {
579 let mut bitvec = bits.to_bitvec();
580 bitvec.set_uninitialized(false);
581 Ok(AmlValue::Buffer(Arc::new(spinning_top::Spinlock::new(
582 bitvec.into_vec(),
583 ))))
584 } else if length > 32 {
585 let mut upper = 0u32;
594 let mut lower = 0u32;
595 lower.view_bits_mut::<bitvec::order::Lsb0>()[0..32].clone_from_bitslice(bits);
596 upper.view_bits_mut::<bitvec::order::Lsb0>()[0..(length - 32)]
597 .clone_from_bitslice(&bits[32..]);
598 Ok(AmlValue::Integer((upper as u64) << 32 + (lower as u64)))
599 } else {
600 let mut value = 0u32;
601 value.view_bits_mut::<bitvec::order::Lsb0>()[0..length].clone_from_bitslice(bits);
602 Ok(AmlValue::Integer(value as u64))
603 }
604 } else {
605 Err(AmlError::IncompatibleValueConversion {
606 current: self.type_of(),
607 target: AmlType::BufferField,
608 })
609 }
610 }
611
612 pub fn write_buffer_field(
613 &mut self,
614 value: AmlValue,
615 _context: &mut AmlContext,
616 ) -> Result<(), AmlError> {
617 use bitvec::view::BitView;
618
619 if let AmlValue::BufferField {
620 buffer_data,
621 offset,
622 length,
623 } = self
624 {
625 let offset = *offset as usize;
626 let length = *length as usize;
627 let mut inner_data = buffer_data.lock();
629 let bitslice = inner_data.view_bits_mut::<bitvec::order::Lsb0>();
630
631 match value {
632 AmlValue::Integer(value) => {
633 let bits_to_copy = cmp::min(length, 64);
639 bitslice[offset..(offset + bits_to_copy)].copy_from_bitslice(
640 &value.to_le_bytes().view_bits()[..(bits_to_copy as usize)],
641 );
642 bitslice[(offset + bits_to_copy)..(offset + length)].fill(false);
644 Ok(())
645 }
646 AmlValue::Boolean(value) => {
647 bitslice.set(offset, value);
648 Ok(())
649 }
650 AmlValue::Buffer(value) => {
651 let value_data = value.lock();
659 let bits_to_copy = cmp::min(length, value_data.len() * 8);
660 bitslice[offset..(offset + bits_to_copy)]
661 .copy_from_bitslice(&value_data.view_bits()[..(bits_to_copy as usize)]);
662 bitslice[(offset + bits_to_copy)..(offset + length)].fill(false);
664 Ok(())
665 }
666 _ => Err(AmlError::TypeCannotBeWrittenToBufferField(value.type_of())),
667 }
668 } else {
669 Err(AmlError::IncompatibleValueConversion {
670 current: self.type_of(),
671 target: AmlType::BufferField,
672 })
673 }
674 }
675
676 pub fn cmp(
685 &self,
686 other: AmlValue,
687 context: &mut AmlContext,
688 ) -> Result<cmp::Ordering, AmlError> {
689 let self_inner = if self.type_of() == AmlType::FieldUnit {
690 self.read_field(context)?
691 } else {
692 self.clone()
693 };
694
695 match self_inner.type_of() {
696 AmlType::Integer => Ok(self.as_integer(context)?.cmp(&other.as_integer(context)?)),
697 AmlType::Buffer => Ok(self
698 .as_buffer(context)?
699 .lock()
700 .cmp(&other.as_buffer(context)?.lock())),
701 AmlType::String => Ok(self.as_string(context)?.cmp(&other.as_string(context)?)),
702 typ => Err(AmlError::TypeCannotBeCompared(typ)),
703 }
704 }
705}
706
707#[derive(Clone, Default, Debug)]
709pub struct Args(pub [Option<AmlValue>; 7]);
710
711impl Args {
712 pub const EMPTY: Self = Self([None, None, None, None, None, None, None]);
713
714 pub fn from_list(list: Vec<AmlValue>) -> Result<Args, AmlError> {
715 use core::convert::TryInto;
716
717 if list.len() > 7 {
718 return Err(AmlError::TooManyArgs);
719 }
720
721 let mut args: Vec<Option<AmlValue>> = list.into_iter().map(Option::Some).collect();
722 args.extend(core::iter::repeat(None).take(7 - args.len()));
723 Ok(Args(args.try_into().unwrap()))
724 }
725
726 pub fn arg(&self, arg: ArgNum) -> Result<&AmlValue, AmlError> {
727 if arg > 6 {
728 return Err(AmlError::InvalidArgAccess(arg));
729 }
730
731 self.0[arg as usize]
732 .as_ref()
733 .ok_or(AmlError::InvalidArgAccess(arg))
734 }
735
736 pub fn store_arg(&mut self, arg: ArgNum, value: AmlValue) -> Result<(), AmlError> {
737 if arg > 6 {
738 return Err(AmlError::InvalidArgAccess(arg));
739 }
740
741 self.0[arg as usize] = Some(value);
742 Ok(())
743 }
744}