acpica_bindings/interface/types/
object.rs

1//! The [`AcpiObject`] type
2
3use core::ffi::CStr;
4
5use log::{debug, warn};
6
7use crate::bindings::{
8    consts::{
9        ACPI_TYPE_ANY, ACPI_TYPE_BUFFER, ACPI_TYPE_INTEGER, ACPI_TYPE_LOCAL_REFERENCE,
10        ACPI_TYPE_PACKAGE, ACPI_TYPE_POWER, ACPI_TYPE_PROCESSOR, ACPI_TYPE_STRING,
11    },
12    types::{
13        object::{FfiAcpiObject, FfiAcpiObjectType},
14        FfiAcpiHandle, FfiAcpiIoAddress,
15    },
16};
17
18/// A package [`AcpiObject`]
19#[derive(Debug)]
20pub struct AcpiObjectPackage {
21    count: u32,
22    elements: *mut FfiAcpiObject,
23}
24
25/// A string [`AcpiObject`]
26#[derive(Debug)]
27pub struct AcpiObjectString {
28    length: u32,
29    pointer: *mut u8,
30}
31
32/// A buffer [`AcpiObject`]
33#[derive(Debug)]
34pub struct AcpiObjectBuffer {
35    length: u32,
36    pointer: *mut u8,
37}
38
39/// A reference to another [`AcpiObject`]
40#[derive(Debug)]
41pub struct AcpiObjectReference {
42    actual_type: FfiAcpiObjectType,
43    handle: FfiAcpiHandle,
44}
45
46/// An [`AcpiObject`] describing the features of a processor
47#[derive(Debug)]
48pub struct AcpiObjectProcessor {
49    proc_id: u32,
50    pblk_address: FfiAcpiIoAddress,
51    pblk_length: u32,
52}
53
54/// An [`AcpiObject`] describing a power resource
55#[derive(Debug)]
56pub struct AcpiObjectPowerResource {
57    system_level: u32,
58    resource_order: u32,
59}
60
61/// An object used in the processing of ACPI data, mostly AML execution.
62#[derive(Debug)]
63pub enum AcpiObject<'a> {
64    /// The object can be any type, or the type is not known.
65    /// From ACPICA comments: "\[Any\] is used to indicate a NULL package element or an unresolved named reference."
66    Any,
67    /// The object is an integer
68    Integer(u64),
69    /// The object is a string
70    String(&'a str),
71    /// The object is a buffer of bytes
72    Buffer(&'a [u8]),
73    /// The object is a package containing other AML data
74    Package(AcpiObjectPackage),
75    /// The object is a reference to another [`AcpiObject`]
76    Reference(AcpiObjectReference),
77    /// The object describes the features of a processor
78    Processor(AcpiObjectProcessor),
79    /// The object describes a power resource
80    PowerResource(AcpiObjectPowerResource),
81}
82
83impl<'a> AcpiObject<'a> {
84    /// Copies the data from an APCICA object into a safe representation.
85    ///
86    /// # Safety
87    /// `pointer` must point to a valid `ACPI_OBJECT` struct.
88    pub(crate) unsafe fn from_ffi(pointer: *const FfiAcpiObject) -> Self {
89        // SAFETY: `pointer` is a valid acpi object
90        let ffi_acpi_object = unsafe { *pointer };
91        // SAFETY: Every variant of FfiAcpiObject has this field in this location,
92        // so it can be accessed no matter what the real variant is.
93        let object_type = unsafe { ffi_acpi_object.object_type };
94
95        match object_type {
96            _t @ ACPI_TYPE_ANY => Self::Any,
97            // SAFETY: If the object is an integer then the `integer` field can be read
98            _t @ ACPI_TYPE_INTEGER => unsafe { Self::Integer(ffi_acpi_object.integer.value) },
99            _t @ ACPI_TYPE_STRING => {
100                // SAFETY: If the object is a string then the `string` field can be read
101                let string = unsafe { ffi_acpi_object.string };
102
103                // SAFETY: The object is valid so the pointer and length are correct
104                let bytes = unsafe {
105                    core::slice::from_raw_parts(string.pointer.cast(), string.length as _)
106                };
107
108                let str = core::str::from_utf8(bytes).unwrap();
109
110                Self::String(str)
111            }
112            _t @ ACPI_TYPE_BUFFER => {
113                // SAFETY: If the object is a buffer then the `buffer` field can be read
114                let buffer = unsafe { ffi_acpi_object.buffer };
115
116                let bytes =
117                // SAFETY: The object is valid so the pointer and length are correct
118                    unsafe { core::slice::from_raw_parts(buffer.pointer, buffer.length as _) };
119
120                Self::Buffer(bytes)
121            }
122            _t @ ACPI_TYPE_PACKAGE => {
123                // SAFETY: If the object is a package then the `package` field can be read
124                let package = unsafe { ffi_acpi_object.package };
125
126                Self::Package(AcpiObjectPackage {
127                    count: package.count,
128                    elements: package.elements,
129                })
130            }
131            _t @ ACPI_TYPE_LOCAL_REFERENCE => {
132                // SAFETY: If the object is a reference then the `reference` field can be read
133                let reference = unsafe { ffi_acpi_object.reference };
134
135                Self::Reference(AcpiObjectReference {
136                    actual_type: reference.actual_type,
137                    handle: reference.handle,
138                })
139            }
140            _t @ ACPI_TYPE_PROCESSOR => {
141                // SAFETY: If the object is a processor then the `processor` field can be read
142                let processor = unsafe { ffi_acpi_object.processor };
143
144                Self::Processor(AcpiObjectProcessor {
145                    proc_id: processor.proc_id,
146                    pblk_address: processor.pblk_address,
147                    pblk_length: processor.pblk_length,
148                })
149            }
150            _t @ ACPI_TYPE_POWER => {
151                // SAFETY: If the object is a power resource then the `power_resource` field can be read
152                let power_resource = unsafe { ffi_acpi_object.power_resource };
153
154                Self::PowerResource(AcpiObjectPowerResource {
155                    system_level: power_resource.system_level,
156                    resource_order: power_resource.resource_order,
157                })
158            }
159
160            _ => Self::Any,
161        }
162    }
163
164    /// Copies the data from an ACPI object, indicated by its type number and a pointer to the object (for integer objects, the pointer itself stores the value)
165    ///
166    /// # Safety
167    /// `val` must be valid data of the type indicated by `object_type`
168    pub(crate) unsafe fn from_type_and_val(object_type: u8, val: *mut i8) -> Self {
169        match object_type.into() {
170            _t @ ACPI_TYPE_ANY => Self::Any,
171            _t @ ACPI_TYPE_INTEGER => Self::Integer(val as _),
172            _t @ ACPI_TYPE_STRING => {
173                // SAFETY: If the object is a string then the pointer points to a null terminated string
174                let s = unsafe {
175                    CStr::from_ptr(val)
176                        .to_str()
177                        .expect("String object should have been valid utf-8")
178                };
179                Self::String(s)
180            }
181
182            _ => {
183                warn!(target: "acpi_object_from_type_and_val", "Check object type meaning. Type is {}, val is {:p}", object_type, val);
184                Self::Any
185            }
186        }
187    }
188
189    /// Gets the type of the object
190    #[must_use]
191    pub fn get_type(&self) -> AcpiObjectType {
192        match self {
193            AcpiObject::Any => AcpiObjectType::Any,
194            AcpiObject::Integer(_) => AcpiObjectType::Integer,
195            AcpiObject::String(_) => AcpiObjectType::String,
196            AcpiObject::Buffer(_) => AcpiObjectType::Buffer,
197            AcpiObject::Package(_) => AcpiObjectType::Package,
198            AcpiObject::Reference(_) => AcpiObjectType::Reference,
199            AcpiObject::Processor(_) => AcpiObjectType::Processor,
200            AcpiObject::PowerResource(_) => AcpiObjectType::PowerResource,
201        }
202    }
203}
204
205/// A type of an [`AcpiObject`]. This is used when the type of data is known but the value is not.
206#[derive(Debug, Clone, Copy, PartialEq, Eq)]
207pub enum AcpiObjectType {
208    /// The object can be any type, or the type is not known.
209    /// From ACPICA comments: "\[Any\] is used to indicate a NULL package element or an unresolved named reference."
210    Any,
211    /// The object is an integer
212    Integer,
213    /// The object is a string
214    String,
215    /// The object is a buffer of bytes
216    Buffer,
217    /// The object is a package containing other AML data
218    Package,
219    /// The object is a reference to another [`AcpiObject`]
220    Reference,
221    /// The object describes the features of a processor
222    Processor,
223    /// The object describes a power resource
224    PowerResource,
225}
226
227impl AcpiObjectType {
228    pub(crate) fn from_type_id(id: FfiAcpiObjectType) -> Self {
229        match id {
230            _t @ ACPI_TYPE_ANY => Self::Any,
231            _t @ ACPI_TYPE_INTEGER => Self::Integer,
232            _t @ ACPI_TYPE_STRING => Self::String,
233            _t @ ACPI_TYPE_BUFFER => Self::Buffer,
234            _t @ ACPI_TYPE_PACKAGE => Self::Package,
235            _t @ ACPI_TYPE_LOCAL_REFERENCE => Self::Reference,
236            _t @ ACPI_TYPE_PROCESSOR => Self::Processor,
237            _t @ ACPI_TYPE_POWER => Self::PowerResource,
238
239            _ => Self::Any,
240        }
241    }
242}