1use super::sdt::Sdt;
6use zerocopy::FromBytes;
7
8pub const MADT_SIGNATURE: &[u8; 4] = b"APIC";
9
10#[derive(Clone, Copy, Debug, FromBytes)]
12#[repr(C, packed)]
13pub struct MadtAcpiTable {
14 pub header: Sdt,
15 pub local_apic_phys_addr: u32,
16 pub flags: u32,
17}
18
19impl MadtAcpiTable {
20 pub fn get() -> Option<&'static MadtAcpiTable> {
22 unsafe { super::find_table(MADT_SIGNATURE).map(|ptr| &*(ptr as *const MadtAcpiTable)) }
23 }
24}
25
26#[derive(Clone, Copy, Debug, FromBytes)]
28#[repr(C, packed)]
29struct EntryRecord {
30 typ: u8,
31 size: u8,
32}
33
34#[derive(Copy, Clone, Debug, FromBytes)]
36#[repr(C, packed)]
37pub struct MadtLocalApic {
38 _header: EntryRecord,
39 pub processor: u8,
40 pub apic_id: u8,
41 pub flags: u32,
42}
43
44#[derive(Copy, Clone, Debug, FromBytes)]
46#[repr(C, packed)]
47pub struct MadtIoApic {
48 _header: EntryRecord,
49 pub id: u8,
50 _reserved: u8,
51 pub address: u32,
52 pub gsi_base: u32,
53}
54
55#[derive(Copy, Clone, Debug, FromBytes)]
57#[repr(C, packed)]
58pub struct MadtIntSrcOverride {
59 _header: EntryRecord,
60 pub bus_source: u8,
61 pub irq_source: u8,
62 pub gsi: u32,
63 pub flags: u16,
64}
65
66pub struct MadtInfo {
67 pub local_apic_address: u32,
68 pub flags: u32,
69 pub local_apics: [Option<LocalApicEntry>; 32],
70 pub local_apic_count: usize,
71 pub io_apics: [Option<IoApicEntry>; 4],
72 pub io_apic_count: usize,
73 pub overrides: [Option<InterruptSourceOverride>; 16],
74 pub override_count: usize,
75}
76
77#[derive(Clone, Copy, Debug)]
78pub struct LocalApicEntry {
79 pub processor: u8,
80 pub apic_id: u8,
81 pub flags: u32,
82}
83
84#[derive(Clone, Copy, Debug)]
85pub struct IoApicEntry {
86 pub id: u8,
87 pub address: u32,
88 pub gsi_base: u32,
89}
90
91#[derive(Clone, Copy, Debug)]
92pub struct InterruptSourceOverride {
93 pub bus_source: u8,
94 pub irq_source: u8,
95 pub gsi: u32,
96 pub flags: u16,
97}
98
99impl InterruptSourceOverride {
100 pub fn polarity(&self) -> u8 {
103 (self.flags & 0x03) as u8
104 }
105
106 pub fn trigger_mode(&self) -> u8 {
109 ((self.flags >> 2) & 0x03) as u8
110 }
111}
112
113impl MadtInfo {
114 pub fn irq_to_gsi(&self, irq: u8) -> (u32, u8, u8) {
119 for i in 0..self.override_count {
120 if let Some(ref ovr) = self.overrides[i] {
121 if ovr.irq_source == irq {
122 return (ovr.gsi, ovr.polarity(), ovr.trigger_mode());
123 }
124 }
125 }
126 (irq as u32, 0, 0)
128 }
129}
130
131pub fn parse_madt() -> Option<MadtInfo> {
133 let madt_ptr = super::find_table(MADT_SIGNATURE)? as *const MadtAcpiTable;
134 let madt = unsafe { &*madt_ptr };
135 if madt.header.length < core::mem::size_of::<MadtAcpiTable>() as u32 {
136 log::error!("ACPI: MADT length smaller than header");
137 return None;
138 }
139 let madt_len = madt.header.length as usize;
140 let mut sum: u8 = 0;
141 for i in 0..madt_len {
142 sum = sum.wrapping_add(unsafe { *((madt_ptr as *const u8).add(i)) });
143 }
144 if sum != 0 {
145 log::error!("ACPI: MADT checksum failed");
146 return None;
147 }
148
149 let mut info = MadtInfo {
150 local_apic_address: madt.local_apic_phys_addr,
151 flags: madt.flags,
152 local_apics: [None; 32],
153 local_apic_count: 0,
154 io_apics: [None; 4],
155 io_apic_count: 0,
156 overrides: [None; 16],
157 override_count: 0,
158 };
159
160 let total_length = madt_len;
161 let entries_start = madt_ptr as usize + core::mem::size_of::<MadtAcpiTable>();
162 let entries_end = madt_ptr as usize + total_length;
163 let mut offset = entries_start;
164
165 while offset + 2 <= entries_end {
166 let record = unsafe { &*(offset as *const EntryRecord) };
167 let entry_type = record.typ;
168 let entry_size = record.size as usize;
169
170 if entry_size < 2 || offset + entry_size > entries_end {
171 break;
172 }
173
174 match entry_type {
175 0 => {
176 if info.local_apic_count < info.local_apics.len() {
177 let entry = unsafe { &*(offset as *const MadtLocalApic) };
178 info.local_apics[info.local_apic_count] = Some(LocalApicEntry {
179 processor: entry.processor,
180 apic_id: entry.apic_id,
181 flags: entry.flags,
182 });
183 info.local_apic_count += 1;
184 }
185 }
186 1 => {
187 if info.io_apic_count < info.io_apics.len() {
188 let entry = unsafe { &*(offset as *const MadtIoApic) };
189 info.io_apics[info.io_apic_count] = Some(IoApicEntry {
190 id: entry.id,
191 address: entry.address,
192 gsi_base: entry.gsi_base,
193 });
194 info.io_apic_count += 1;
195 }
196 }
197 2 => {
198 if info.override_count < info.overrides.len() {
199 let entry = unsafe { &*(offset as *const MadtIntSrcOverride) };
200 info.overrides[info.override_count] = Some(InterruptSourceOverride {
201 bus_source: entry.bus_source,
202 irq_source: entry.irq_source,
203 gsi: entry.gsi,
204 flags: entry.flags,
205 });
206 info.override_count += 1;
207 }
208 }
209 _ => {}
210 }
211 offset += entry_size;
212 }
213
214 Some(info)
215}