acpica_bindings/interface/
tables.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
use crate::{
    bindings::{
        functions::{AcpiGetTable, AcpiGetTableByIndex},
        types::tables::FfiAcpiTableHeader,
    },
    status::AcpiError,
    types::tables::{fadt::Fadt, mcfg::Mcfg, AcpiTableHeader, Madt, Uefi},
    AcpicaOperation,
};

impl<const TL: bool, const E: bool, const I: bool> AcpicaOperation<true, TL, E, I> {
    fn get_tables_of_type(&self, signature: [u8; 4]) -> impl Iterator<Item = AcpiTableHeader> {
        let mut i = 1;

        core::iter::from_fn(move || {
            let mut table = core::ptr::null_mut();
            // Move the signature into an array for borrow checking reasons
            // And so that if ACPICA mutates this string it's not UB
            let mut signature = signature;

            // SAFETY: The signature is valid
            let r = unsafe { AcpiGetTable(signature.as_mut_ptr().cast(), i, &mut table) };

            i += 1;

            match r.as_result() {
                Ok(()) => {
                    assert!(!table.is_null());
                    // SAFETY: The returned pointer is valid
                    unsafe { Some(AcpiTableHeader::from_ffi(&*table.cast_const())) }
                }
                Err(AcpiError::BadParameter) => panic!("ACPICA reported bad parameter"),
                Err(_) => None,
            }
        })
    }

    /// Gets a table by its signature, if it is present on the system.
    #[allow(clippy::missing_panics_doc)]
    #[must_use]
    pub fn table(&self, signature: [u8; 4]) -> Option<AcpiTableHeader> {
        let mut table = core::ptr::null_mut();
        // Move the signature into an array for borrow checking reasons
        // And so that if ACPICA mutates this string it's not UB
        let mut signature = signature;

        // SAFETY: The signature is valid
        let r = unsafe { AcpiGetTable(signature.as_mut_ptr().cast(), 1, &mut table) };

        match r.as_result() {
            Ok(()) => {
                assert!(!table.is_null());
                // SAFETY: The returned pointer is valid
                unsafe { Some(AcpiTableHeader::from_ffi(&*table)) }
            }
            Err(_) => None,
        }
    }

    /// Returns an iterator over all the tables detected by ACPICA.
    /// 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.
    ///
    /// [`dsdt`]: AcpicaOperation::dsdt
    /// [`madt`]: AcpicaOperation::madt
    /// [`fadt`]: AcpicaOperation::fadt
    #[allow(clippy::missing_panics_doc)]
    pub fn tables(&self) -> impl Iterator<Item = AcpiTableHeader> {
        let mut i = 1;

        core::iter::from_fn(move || {
            let mut ptr = core::ptr::null_mut();

            // SAFETY:
            let r = unsafe { AcpiGetTableByIndex(i, &mut ptr) };

            i += 1;

            match r.as_result() {
                Ok(()) => {
                    assert!(!ptr.is_null());
                    // SAFETY: The returned pointer is valid
                    unsafe { Some(AcpiTableHeader::from_ffi(&*ptr)) }
                }
                Err(_) => None,
            }
        })
    }

    /// Gets an iterator over all of the loaded SSDT tables.
    pub fn ssdt_tables(&self) -> impl Iterator<Item = AcpiTableHeader> {
        self.get_tables_of_type(*b"SSDT")
    }

    /// Gets an iterator over all of the loaded UEFI tables.
    pub fn uefi_tables(&self) -> impl Iterator<Item = Uefi> {
        self.get_tables_of_type(*b"UEFI").map(|header| {
            let ptr = header.as_ffi() as *const FfiAcpiTableHeader;
            let ptr = ptr.cast();
            // SAFETY: The signature is "UEFI" so the table can be cast to an FfiAcpiTableUefi
            unsafe { Uefi::from_ffi(&*ptr) }
        })
    }

    /// Gets the DSDT
    #[allow(clippy::missing_panics_doc)]
    #[must_use]
    pub fn dsdt(&self) -> AcpiTableHeader {
        self.table(*b"DSDT")
            .expect("System should have contained DSDT")
    }

    /// Gets the MADT
    #[allow(clippy::missing_panics_doc)]
    #[must_use]
    pub fn madt(&self) -> Madt {
        let ptr = self
            .table(*b"APIC")
            .expect("System should have contained MADT")
            .as_ffi() as *const FfiAcpiTableHeader;
        let ptr = ptr.cast();
        // SAFETY: The signature is "APIC" so the table is an MADT
        unsafe { Madt::from_ffi(&*ptr) }
    }

    /// Gets the FADT
    #[allow(clippy::missing_panics_doc)]
    #[must_use]
    pub fn fadt(&self) -> Fadt {
        let ptr = self
            .table(*b"FACP")
            .expect("System should have contained FADT")
            .as_ffi() as *const FfiAcpiTableHeader;
        let ptr = ptr.cast();
        // SAFETY: The signature is "APIC" so the table is an MADT
        unsafe { Fadt::from_ffi(&*ptr) }
    }

    /// Gets the MCFG
    #[allow(clippy::missing_panics_doc)]
    #[must_use]
    pub fn mcfg(&self) -> Option<Mcfg> {
        let ptr = self.table(*b"MCFG")?.as_ffi() as *const FfiAcpiTableHeader;

        let ptr = ptr.cast();
        // SAFETY: The signature is "APIC" so the table is an MADT
        unsafe { Some(Mcfg::from_ffi(&*ptr)) }
    }
}