acpica_bindings/interface/
tables.rs

1use crate::{
2    bindings::{
3        functions::{AcpiGetTable, AcpiGetTableByIndex},
4        types::tables::FfiAcpiTableHeader,
5    },
6    status::AcpiError,
7    types::tables::{fadt::Fadt, mcfg::Mcfg, AcpiTableHeader, Madt, Uefi},
8    AcpicaOperation,
9};
10
11impl<const TL: bool, const E: bool, const I: bool> AcpicaOperation<true, TL, E, I> {
12    fn get_tables_of_type(&self, signature: [u8; 4]) -> impl Iterator<Item = AcpiTableHeader> {
13        let mut i = 1;
14
15        core::iter::from_fn(move || {
16            let mut table = core::ptr::null_mut();
17            // Move the signature into an array for borrow checking reasons
18            // And so that if ACPICA mutates this string it's not UB
19            let mut signature = signature;
20
21            // SAFETY: The signature is valid
22            let r = unsafe { AcpiGetTable(signature.as_mut_ptr().cast(), i, &mut table) };
23
24            i += 1;
25
26            match r.as_result() {
27                Ok(()) => {
28                    assert!(!table.is_null());
29                    // SAFETY: The returned pointer is valid
30                    unsafe { Some(AcpiTableHeader::from_ffi(&*table.cast_const())) }
31                }
32                Err(AcpiError::BadParameter) => panic!("ACPICA reported bad parameter"),
33                Err(_) => None,
34            }
35        })
36    }
37
38    /// Gets a table by its signature, if it is present on the system.
39    #[allow(clippy::missing_panics_doc)]
40    #[must_use]
41    pub fn table(&self, signature: [u8; 4]) -> Option<AcpiTableHeader> {
42        let mut table = core::ptr::null_mut();
43        // Move the signature into an array for borrow checking reasons
44        // And so that if ACPICA mutates this string it's not UB
45        let mut signature = signature;
46
47        // SAFETY: The signature is valid
48        let r = unsafe { AcpiGetTable(signature.as_mut_ptr().cast(), 1, &mut table) };
49
50        match r.as_result() {
51            Ok(()) => {
52                assert!(!table.is_null());
53                // SAFETY: The returned pointer is valid
54                unsafe { Some(AcpiTableHeader::from_ffi(&*table)) }
55            }
56            Err(_) => None,
57        }
58    }
59
60    /// Returns an iterator over all the tables detected by ACPICA.
61    /// If you want to find a specific common table, there may be a dedicated method for finding it instead, for instance [`dsdt`], [`madt`], [`fadt`], etc.
62    ///
63    /// [`dsdt`]: AcpicaOperation::dsdt
64    /// [`madt`]: AcpicaOperation::madt
65    /// [`fadt`]: AcpicaOperation::fadt
66    #[allow(clippy::missing_panics_doc)]
67    pub fn tables(&self) -> impl Iterator<Item = AcpiTableHeader> {
68        let mut i = 1;
69
70        core::iter::from_fn(move || {
71            let mut ptr = core::ptr::null_mut();
72
73            // SAFETY:
74            let r = unsafe { AcpiGetTableByIndex(i, &mut ptr) };
75
76            i += 1;
77
78            match r.as_result() {
79                Ok(()) => {
80                    assert!(!ptr.is_null());
81                    // SAFETY: The returned pointer is valid
82                    unsafe { Some(AcpiTableHeader::from_ffi(&*ptr)) }
83                }
84                Err(_) => None,
85            }
86        })
87    }
88
89    /// Gets an iterator over all of the loaded SSDT tables.
90    pub fn ssdt_tables(&self) -> impl Iterator<Item = AcpiTableHeader> {
91        self.get_tables_of_type(*b"SSDT")
92    }
93
94    /// Gets an iterator over all of the loaded UEFI tables.
95    pub fn uefi_tables(&self) -> impl Iterator<Item = Uefi> {
96        self.get_tables_of_type(*b"UEFI").map(|header| {
97            let ptr = header.as_ffi() as *const FfiAcpiTableHeader;
98            let ptr = ptr.cast();
99            // SAFETY: The signature is "UEFI" so the table can be cast to an FfiAcpiTableUefi
100            unsafe { Uefi::from_ffi(&*ptr) }
101        })
102    }
103
104    /// Gets the DSDT
105    #[allow(clippy::missing_panics_doc)]
106    #[must_use]
107    pub fn dsdt(&self) -> AcpiTableHeader {
108        self.table(*b"DSDT")
109            .expect("System should have contained DSDT")
110    }
111
112    /// Gets the MADT
113    #[allow(clippy::missing_panics_doc)]
114    #[must_use]
115    pub fn madt(&self) -> Madt {
116        let ptr = self
117            .table(*b"APIC")
118            .expect("System should have contained MADT")
119            .as_ffi() as *const FfiAcpiTableHeader;
120        let ptr = ptr.cast();
121        // SAFETY: The signature is "APIC" so the table is an MADT
122        unsafe { Madt::from_ffi(&*ptr) }
123    }
124
125    /// Gets the FADT
126    #[allow(clippy::missing_panics_doc)]
127    #[must_use]
128    pub fn fadt(&self) -> Fadt {
129        let ptr = self
130            .table(*b"FACP")
131            .expect("System should have contained FADT")
132            .as_ffi() as *const FfiAcpiTableHeader;
133        let ptr = ptr.cast();
134        // SAFETY: The signature is "APIC" so the table is an MADT
135        unsafe { Fadt::from_ffi(&*ptr) }
136    }
137
138    /// Gets the MCFG
139    #[allow(clippy::missing_panics_doc)]
140    #[must_use]
141    pub fn mcfg(&self) -> Option<Mcfg> {
142        let ptr = self.table(*b"MCFG")?.as_ffi() as *const FfiAcpiTableHeader;
143
144        let ptr = ptr.cast();
145        // SAFETY: The signature is "APIC" so the table is an MADT
146        unsafe { Some(Mcfg::from_ffi(&*ptr)) }
147    }
148}