acpi/
address.rs

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
4use crate::AcpiError;
5use 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)]
11pub(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
19impl RawGenericAddress {
20    pub(crate) const fn is_empty(&self) -> bool {
21        self.address_space == 0
22            && self.bit_width == 0
23            && self.bit_offset == 0
24            && self.access_size == 0
25            && self.address == 0
26    }
27}
28
29#[derive(PartialEq, Eq, Clone, Copy, Debug)]
30pub enum AddressSpace {
31    SystemMemory,
32    SystemIo,
33    /// Describes a register in the configuration space of a PCI device in segment `0`, on bus `0`. The `address`
34    /// field is of the format:
35    /// ```ignore
36    /// 64              48              32              16               0
37    ///  +---------------+---------------+---------------+---------------+
38    ///  |  reserved (0) |    device     |   function    |    offset     |
39    ///  +---------------+---------------+---------------+---------------+
40    /// ```
41    PciConfigSpace,
42    EmbeddedController,
43    SMBus,
44    SystemCmos,
45    PciBarTarget,
46    Ipmi,
47    GeneralIo,
48    GenericSerialBus,
49    PlatformCommunicationsChannel,
50    FunctionalFixedHardware,
51    OemDefined(u8),
52}
53
54#[derive(PartialEq, Eq, Clone, Copy, Debug)]
55pub enum AccessSize {
56    Undefined,
57    ByteAccess,
58    WordAccess,
59    DWordAccess,
60    QWordAccess,
61}
62
63impl TryFrom<u8> for AccessSize {
64    type Error = AcpiError;
65
66    fn try_from(size: u8) -> Result<Self, Self::Error> {
67        match size {
68            0 => Ok(AccessSize::Undefined),
69            1 => Ok(AccessSize::ByteAccess),
70            2 => Ok(AccessSize::WordAccess),
71            3 => Ok(AccessSize::DWordAccess),
72            4 => Ok(AccessSize::QWordAccess),
73            _ => Err(AcpiError::InvalidGenericAddress),
74        }
75    }
76}
77
78#[derive(PartialEq, Eq, Clone, Copy, Debug)]
79pub struct GenericAddress {
80    pub address_space: AddressSpace,
81    pub bit_width: u8,
82    pub bit_offset: u8,
83    pub access_size: AccessSize,
84    pub address: u64,
85}
86
87impl GenericAddress {
88    pub(crate) fn from_raw(raw: RawGenericAddress) -> crate::AcpiResult<GenericAddress> {
89        let address_space = match raw.address_space {
90            0x00 => AddressSpace::SystemMemory,
91            0x01 => AddressSpace::SystemIo,
92            0x02 => AddressSpace::PciConfigSpace,
93            0x03 => AddressSpace::EmbeddedController,
94            0x04 => AddressSpace::SMBus,
95            0x05 => AddressSpace::SystemCmos,
96            0x06 => AddressSpace::PciBarTarget,
97            0x07 => AddressSpace::Ipmi,
98            0x08 => AddressSpace::GeneralIo,
99            0x09 => AddressSpace::GenericSerialBus,
100            0x0a => AddressSpace::PlatformCommunicationsChannel,
101            0x0b..=0x7e => return Err(AcpiError::InvalidGenericAddress),
102            0x7f => AddressSpace::FunctionalFixedHardware,
103            0x80..=0xbf => return Err(AcpiError::InvalidGenericAddress),
104            0xc0..=0xff => AddressSpace::OemDefined(raw.address_space),
105        };
106
107        Ok(GenericAddress {
108            address_space,
109            bit_width: raw.bit_width,
110            bit_offset: raw.bit_offset,
111            access_size: AccessSize::try_from(raw.access_size)?,
112            address: raw.address,
113        })
114    }
115}