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 impl RawGenericAddress { is_empty(&self) -> bool20 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)] 30 pub 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)] 55 pub enum AccessSize { 56 Undefined, 57 ByteAccess, 58 WordAccess, 59 DWordAccess, 60 QWordAccess, 61 } 62 63 impl TryFrom<u8> for AccessSize { 64 type Error = AcpiError; 65 try_from(size: u8) -> Result<Self, Self::Error>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)] 79 pub 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 87 impl GenericAddress { from_raw(raw: RawGenericAddress) -> crate::AcpiResult<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 } 116