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