1 //! ACPI defines a Generic Address Structure (GAS), which provides a versatile way to describe register locations
2 //! in a wide range of address spaces.
3 
4 use crate::AcpiError;
5 use core::convert::TryFrom;
6 
7 /// This is the raw form of a Generic Address Structure, and follows the layout found in the ACPI tables. It does
8 /// not form part of the public API, and should be turned into a `GenericAddress` for most use-cases.
9 #[derive(Clone, Copy, Debug)]
10 #[repr(C, packed)]
11 pub(crate) struct RawGenericAddress {
12     pub address_space: u8,
13     pub bit_width: u8,
14     pub bit_offset: u8,
15     pub access_size: u8,
16     pub address: u64,
17 }
18 
19 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
20 pub enum AddressSpace {
21     SystemMemory,
22     SystemIo,
23     /// Describes a register in the configuration space of a PCI device in segment `0`, on bus `0`. The `address`
24     /// field is of the format:
25     /// ```ignore
26     /// 64              48              32              16               0
27     ///  +---------------+---------------+---------------+---------------+
28     ///  |  reserved (0) |    device     |   function    |    offset     |
29     ///  +---------------+---------------+---------------+---------------+
30     /// ```
31     PciConfigSpace,
32     EmbeddedController,
33     SMBus,
34     SystemCmos,
35     PciBarTarget,
36     Ipmi,
37     GeneralIo,
38     GenericSerialBus,
39     PlatformCommunicationsChannel,
40     FunctionalFixedHardware,
41     OemDefined(u8),
42 }
43 
44 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
45 pub enum AccessSize {
46     Undefined,
47     ByteAccess,
48     WordAccess,
49     DWordAccess,
50     QWordAccess,
51 }
52 
53 impl TryFrom<u8> for AccessSize {
54     type Error = AcpiError;
55 
try_from(size: u8) -> Result<Self, Self::Error>56     fn try_from(size: u8) -> Result<Self, Self::Error> {
57         match size {
58             0 => Ok(AccessSize::Undefined),
59             1 => Ok(AccessSize::ByteAccess),
60             2 => Ok(AccessSize::WordAccess),
61             3 => Ok(AccessSize::DWordAccess),
62             4 => Ok(AccessSize::QWordAccess),
63             _ => Err(AcpiError::InvalidGenericAddress),
64         }
65     }
66 }
67 
68 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
69 pub struct GenericAddress {
70     pub address_space: AddressSpace,
71     pub bit_width: u8,
72     pub bit_offset: u8,
73     pub access_size: AccessSize,
74     pub address: u64,
75 }
76 
77 impl GenericAddress {
from_raw(raw: RawGenericAddress) -> crate::AcpiResult<GenericAddress>78     pub(crate) fn from_raw(raw: RawGenericAddress) -> crate::AcpiResult<GenericAddress> {
79         let address_space = match raw.address_space {
80             0x00 => AddressSpace::SystemMemory,
81             0x01 => AddressSpace::SystemIo,
82             0x02 => AddressSpace::PciConfigSpace,
83             0x03 => AddressSpace::EmbeddedController,
84             0x04 => AddressSpace::SMBus,
85             0x05 => AddressSpace::SystemCmos,
86             0x06 => AddressSpace::PciBarTarget,
87             0x07 => AddressSpace::Ipmi,
88             0x08 => AddressSpace::GeneralIo,
89             0x09 => AddressSpace::GenericSerialBus,
90             0x0a => AddressSpace::PlatformCommunicationsChannel,
91             0x0b..=0x7e => return Err(AcpiError::InvalidGenericAddress),
92             0x7f => AddressSpace::FunctionalFixedHardware,
93             0x80..=0xbf => return Err(AcpiError::InvalidGenericAddress),
94             0xc0..=0xff => AddressSpace::OemDefined(raw.address_space),
95         };
96 
97         Ok(GenericAddress {
98             address_space,
99             bit_width: raw.bit_width,
100             bit_offset: raw.bit_offset,
101             access_size: AccessSize::try_from(raw.access_size)?,
102             address: raw.address,
103         })
104     }
105 }
106