acpica_bindings/interface/
types.rs

1//! Contains rust equivalents of types used by ACPICA
2
3mod generic_address;
4pub mod object;
5pub mod tables;
6
7use core::{
8    ffi::{c_void, CStr},
9    fmt::{Debug, Display},
10};
11
12use crate::bindings::types::{
13    functions::{FfiAcpiOsdExecCallback, FfiAcpiOsdHandler},
14    FfiAcpiCpuFlags, FfiAcpiPciId, FfiAcpiPredefinedNames,
15};
16
17pub use generic_address::*;
18
19use self::object::AcpiObject;
20
21/// A physical address into main memory
22#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
23pub struct AcpiPhysicalAddress(pub usize);
24
25impl AcpiPhysicalAddress {
26    /// A null pointer, i.e. a pointer of value 0
27    pub const NULL: Self = Self(0);
28}
29
30impl Debug for AcpiPhysicalAddress {
31    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
32        f.debug_tuple("AcpiPhysicalAddress")
33            .field(&format_args!("{:#x}", self.0))
34            .finish()
35    }
36}
37
38#[cfg(feature = "x86_64")]
39impl From<AcpiPhysicalAddress> for x86_64::PhysAddr {
40    fn from(val: AcpiPhysicalAddress) -> Self {
41        x86_64::PhysAddr::new(val.0.try_into().unwrap())
42    }
43}
44
45/// A default value in an ACPI namespace.
46///
47/// This struct is passed to the [`predefined_override`] method to allow the OS to change the values of default objects.
48///
49/// [`predefined_override`]: crate::interface::handler::AcpiHandler::predefined_override
50#[derive(Debug)]
51pub struct AcpiPredefinedNames<'a>(&'a FfiAcpiPredefinedNames);
52
53impl<'a> AcpiPredefinedNames<'a> {
54    pub(crate) fn from_ffi(ffi_predefined_names: &'a FfiAcpiPredefinedNames) -> Self {
55        Self(ffi_predefined_names)
56    }
57
58    pub(crate) fn as_ffi(&self) -> &'a FfiAcpiPredefinedNames {
59        self.0
60    }
61
62    /// Gets the name of the object in the namespace
63    #[must_use]
64    #[allow(clippy::missing_panics_doc)] // ACPI names are ASCII, so this should never panic
65    pub fn name(&self) -> &str {
66        // SAFETY: The `name` pointer in an FfiAcpiPredefinedNames struct is a null terminated string
67        unsafe {
68            CStr::from_ptr(self.0.name)
69                .to_str()
70                .expect("Object name should have been valid utf-8")
71        }
72    }
73
74    /// Gets the object which will be added to the namespace
75    #[must_use]
76    pub fn object(&self) -> AcpiObject {
77        // SAFETY: The values were passed by ACPICA, so they are valid.
78        unsafe { AcpiObject::from_type_and_val(self.0.object_type, self.0.val) }
79    }
80}
81
82/// The address of an I/O port
83#[derive(Debug, Clone, Copy)]
84pub struct AcpiIoAddress(pub usize);
85
86/// A tag identifying an interrupt callback so that it can be removed.
87/// The OS will receive the tag from [`install_interrupt_handler`] and it must be compared against each handler using [`is_tag`]
88///
89/// [`install_interrupt_handler`]: super::handler::AcpiHandler::install_interrupt_handler
90/// [`is_tag`]: AcpiInterruptCallback::is_tag
91#[derive(Debug)]
92pub struct AcpiInterruptCallbackTag(pub(crate) FfiAcpiOsdHandler);
93
94/// A callback to notify ACPICA about an interrupt.
95///
96/// The [`call`] method should be used to run the callback from the associated interrupt handler.
97///
98/// [`call`]: AcpiInterruptCallback::call
99#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
100pub struct AcpiInterruptCallback {
101    pub(crate) function: FfiAcpiOsdHandler,
102    pub(crate) context: *mut c_void,
103}
104
105// SAFETY: The `context` pointer in an `AcpiInterruptCallback` points into ACPICA's memory - either
106// in a static or on the kernel heap. Both of these need to be available to all kernel threads for
107// ACPICA to function at all, so the OS needs to make this sound for the library to function.
108unsafe impl Send for AcpiInterruptCallback {}
109
110/// Whether an interrupt is handled or not.
111///
112/// TODO: What should the OS use this for?
113#[derive(Debug, Clone, Copy, PartialEq, Eq)]
114pub enum AcpiInterruptHandledStatus {
115    /// The interrupt has been handled
116    Handled,
117    /// The interrupt has not been handled
118    NotHandled,
119}
120
121impl AcpiInterruptCallback {
122    /// Calls the callback
123    ///
124    /// # Safety
125    /// This method may only be called from the interrupt handler this callback is for.
126    /// An interrupt vector will have been provided along with this object, and this method should only be called from the
127    /// interrupt handler for that interrupt vector.
128    pub unsafe fn call(&mut self) -> AcpiInterruptHandledStatus {
129        // SAFETY:
130        let call_result = unsafe { (self.function)(self.context) };
131        match call_result {
132            0 => AcpiInterruptHandledStatus::Handled,
133            1 => AcpiInterruptHandledStatus::NotHandled,
134            _ => unreachable!("Acpi callback returned an invalid value"),
135        }
136    }
137
138    /// Checks whether this callback matches the given `tag`
139    #[must_use]
140    pub fn is_tag(&self, tag: &AcpiInterruptCallbackTag) -> bool {
141        self.function == tag.0
142    }
143}
144
145/// A callback to run in a new thread.
146///
147/// The [`call`] method should be used to run the callback from the created thread.
148///
149/// [`call`]: AcpiThreadCallback::call
150#[derive(Debug)]
151pub struct AcpiThreadCallback {
152    pub(crate) function: FfiAcpiOsdExecCallback,
153    pub(crate) context: *mut c_void,
154}
155
156impl AcpiThreadCallback {
157    /// Calls the callback
158    ///
159    /// # Safety
160    /// This method must be called from a new kernel thread.
161    pub unsafe fn call(&mut self) {
162        // SAFETY: This is
163        unsafe { (self.function)(self.context) };
164    }
165}
166
167/// A PCI device, identified by its `segment:bus:device:function` address.
168#[derive(Debug, Copy, Clone, PartialEq, Eq)]
169pub struct AcpiPciId {
170    /// The PCI segment which the device is accessible through
171    pub segment: u16,
172    /// The PCI bus number
173    pub bus: u16,
174    /// The device number on the PCI bus
175    pub device: u16,
176    /// The function number of the device
177    pub function: u16,
178}
179
180impl AcpiPciId {
181    pub(crate) fn from_ffi(v: FfiAcpiPciId) -> Self {
182        Self {
183            segment: v.segment,
184            bus: v.bus,
185            device: v.device,
186            function: v.function,
187        }
188    }
189}
190
191/// An error which can occur during allocation
192#[derive(Debug, Clone, Copy, PartialEq, Eq)]
193pub enum AcpiAllocationError {
194    /// The system has run out of dynamic memory
195    OutOfMemory,
196}
197
198impl Display for AcpiAllocationError {
199    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
200        match self {
201            Self::OutOfMemory => f.write_str("Out of memory"),
202        }
203    }
204}
205
206/// An error which can occur when mapping physical memory
207#[derive(Debug, Clone, Copy, PartialEq, Eq)]
208pub enum AcpiMappingError {
209    /// The system has run out of frames of memory to map
210    OutOfMemory,
211}
212
213impl Display for AcpiMappingError {
214    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
215        match self {
216            Self::OutOfMemory => f.write_str("Out of memory"),
217        }
218    }
219}
220
221/// CPU flags to be preserved after releasing a lock.
222///
223/// The OS passes this type to ACPICA when acquiring a lock, and they are returned when releasing the lock.
224#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
225pub struct AcpiCpuFlags(pub FfiAcpiCpuFlags);