Skip to main content

strat9_kernel/acpi/
rsdt.rs

1//! Definitions for the ACPI RSDT and XSDT system tables.
2//! Inspired by Theseus OS.
3
4use super::sdt::Sdt;
5
6pub const RSDT_SIGNATURE: &[u8; 4] = b"RSDT";
7pub const XSDT_SIGNATURE: &[u8; 4] = b"XSDT";
8
9pub enum RsdtXsdt {
10    Regular(*const Sdt),
11    Extended(*const Sdt),
12}
13
14impl RsdtXsdt {
15    /// Build the root SDT view directly from RSDP contents.
16    pub fn from_rsdp(rsdp_vaddr: u64, revision: u8) -> Option<Self> {
17        // ACPI 2.0+: XSDT address at byte offset 24 in RSDP v2 struct.
18        if revision >= 2 {
19            let xsdt_phys = unsafe {
20                core::ptr::read_unaligned((rsdp_vaddr as *const u8).add(24) as *const u64)
21            };
22            if xsdt_phys != 0 {
23                crate::memory::paging::ensure_identity_map_range(
24                    xsdt_phys,
25                    core::mem::size_of::<Sdt>() as u64,
26                );
27                let xsdt_ptr = crate::memory::phys_to_virt(xsdt_phys) as *const Sdt;
28                return Some(RsdtXsdt::Extended(xsdt_ptr));
29            }
30        }
31
32        // ACPI 1.0 fallback: RSDT address at byte offset 16.
33        let rsdt_phys =
34            unsafe { core::ptr::read_unaligned((rsdp_vaddr as *const u8).add(16) as *const u32) }
35                as u64;
36        if rsdt_phys == 0 {
37            return None;
38        }
39        crate::memory::paging::ensure_identity_map_range(
40            rsdt_phys,
41            core::mem::size_of::<Sdt>() as u64,
42        );
43        let rsdt_ptr = crate::memory::phys_to_virt(rsdt_phys) as *const Sdt;
44        Some(RsdtXsdt::Regular(rsdt_ptr))
45    }
46
47    /// Performs the sdt operation.
48    pub fn sdt(&self) -> &'static Sdt {
49        match self {
50            RsdtXsdt::Regular(ptr) => unsafe { &**ptr },
51            RsdtXsdt::Extended(ptr) => unsafe { &**ptr },
52        }
53    }
54
55    /// Returns an iterator over the physical addresses of the SDT entries
56    pub fn addresses(&self) -> RsdtXsdtIter {
57        let sdt = self.sdt();
58        let header_size = core::mem::size_of::<Sdt>();
59        if (sdt.length as usize) < header_size {
60            return RsdtXsdtIter::Empty;
61        }
62        let data_ptr = (sdt as *const Sdt as u64 + header_size as u64) as *const u8;
63        let data_len = sdt.length as usize - header_size;
64
65        match self {
66            RsdtXsdt::Regular(_) => RsdtXsdtIter::Regular {
67                ptr: data_ptr as *const u32,
68                count: data_len / 4,
69                index: 0,
70            },
71            RsdtXsdt::Extended(_) => RsdtXsdtIter::Extended {
72                ptr: data_ptr as *const u64,
73                count: data_len / 8,
74                index: 0,
75            },
76        }
77    }
78}
79
80pub enum RsdtXsdtIter {
81    Empty,
82    Regular {
83        ptr: *const u32,
84        count: usize,
85        index: usize,
86    },
87    Extended {
88        ptr: *const u64,
89        count: usize,
90        index: usize,
91    },
92}
93
94impl Iterator for RsdtXsdtIter {
95    type Item = u64;
96
97    /// Performs the next operation.
98    fn next(&mut self) -> Option<Self::Item> {
99        match self {
100            RsdtXsdtIter::Empty => None,
101            RsdtXsdtIter::Regular { ptr, count, index } => {
102                if index < count {
103                    let addr = unsafe { core::ptr::read_unaligned(ptr.add(*index)) };
104                    *index += 1;
105                    Some(addr as u64)
106                } else {
107                    None
108                }
109            }
110            RsdtXsdtIter::Extended { ptr, count, index } => {
111                if index < count {
112                    let addr = unsafe { core::ptr::read_unaligned(ptr.add(*index)) };
113                    *index += 1;
114                    Some(addr)
115                } else {
116                    None
117                }
118            }
119        }
120    }
121}