1 use crate::{
2 sdt::{ExtendedField, SdtHeader, Signature},
3 AcpiTable,
4 };
5 use bit_field::BitField;
6 use core::{marker::PhantomData, mem};
7
8 #[cfg(feature = "allocator_api")]
9 use crate::{
10 platform::{
11 interrupt::{InterruptModel, Polarity, TriggerMode},
12 ProcessorInfo,
13 },
14 AcpiResult,
15 };
16
17 #[derive(Debug)]
18 pub enum MadtError {
19 UnexpectedEntry,
20 InterruptOverrideEntryHasInvalidBus,
21 InvalidLocalNmiLine,
22 MpsIntiInvalidPolarity,
23 MpsIntiInvalidTriggerMode,
24 }
25
26 /// Represents the MADT - this contains the MADT header fields. You can then iterate over a `Madt`
27 /// to read each entry from it.
28 ///
29 /// In modern versions of ACPI, the MADT can detail one of four interrupt models:
30 /// * The ancient dual-i8259 legacy PIC model
31 /// * The Advanced Programmable Interrupt Controller (APIC) model
32 /// * The Streamlined Advanced Programmable Interrupt Controller (SAPIC) model (for Itanium systems)
33 /// * The Generic Interrupt Controller (GIC) model (for ARM systems)
34 #[repr(C, packed)]
35 #[derive(Debug, Clone, Copy)]
36 pub struct Madt {
37 pub header: SdtHeader,
38 pub local_apic_address: u32,
39 pub flags: u32,
40 }
41
42 /// ### Safety: Implementation properly represents a valid MADT.
43 unsafe impl AcpiTable for Madt {
44 const SIGNATURE: Signature = Signature::MADT;
45
header(&self) -> &SdtHeader46 fn header(&self) -> &SdtHeader {
47 &self.header
48 }
49 }
50
51 impl Madt {
52 #[cfg(feature = "allocator_api")]
parse_interrupt_model_in<'a, A>( &self, allocator: A, ) -> AcpiResult<(InterruptModel<'a, A>, Option<ProcessorInfo<'a, A>>)> where A: core::alloc::Allocator + Clone,53 pub fn parse_interrupt_model_in<'a, A>(
54 &self,
55 allocator: A,
56 ) -> AcpiResult<(InterruptModel<'a, A>, Option<ProcessorInfo<'a, A>>)>
57 where
58 A: core::alloc::Allocator + Clone,
59 {
60 /*
61 * We first do a pass through the MADT to determine which interrupt model is being used.
62 */
63 for entry in self.entries() {
64 match entry {
65 MadtEntry::LocalApic(_) |
66 MadtEntry::LocalX2Apic(_) |
67 MadtEntry::IoApic(_) |
68 MadtEntry::InterruptSourceOverride(_) |
69 MadtEntry::NmiSource(_) | // TODO: is this one used by more than one model?
70 MadtEntry::LocalApicNmi(_) |
71 MadtEntry::X2ApicNmi(_) |
72 MadtEntry::LocalApicAddressOverride(_) => {
73 return self.parse_apic_model_in(allocator);
74 }
75
76 MadtEntry::IoSapic(_) |
77 MadtEntry::LocalSapic(_) |
78 MadtEntry::PlatformInterruptSource(_) => {
79 unimplemented!();
80 }
81
82 MadtEntry::Gicc(_) |
83 MadtEntry::Gicd(_) |
84 MadtEntry::GicMsiFrame(_) |
85 MadtEntry::GicRedistributor(_) |
86 MadtEntry::GicInterruptTranslationService(_) => {
87 unimplemented!();
88 }
89
90 MadtEntry::MultiprocessorWakeup(_) => ()
91 }
92 }
93
94 Ok((InterruptModel::Unknown, None))
95 }
96
97 #[cfg(feature = "allocator_api")]
parse_apic_model_in<'a, A>( &self, allocator: A, ) -> AcpiResult<(InterruptModel<'a, A>, Option<ProcessorInfo<'a, A>>)> where A: core::alloc::Allocator + Clone,98 fn parse_apic_model_in<'a, A>(
99 &self,
100 allocator: A,
101 ) -> AcpiResult<(InterruptModel<'a, A>, Option<ProcessorInfo<'a, A>>)>
102 where
103 A: core::alloc::Allocator + Clone,
104 {
105 use crate::{
106 platform::{
107 interrupt::{
108 Apic,
109 InterruptSourceOverride,
110 IoApic,
111 LocalInterruptLine,
112 NmiLine,
113 NmiProcessor,
114 NmiSource,
115 },
116 Processor,
117 ProcessorState,
118 },
119 AcpiError,
120 };
121
122 let mut local_apic_address = self.local_apic_address as u64;
123 let mut io_apic_count = 0;
124 let mut iso_count = 0;
125 let mut nmi_source_count = 0;
126 let mut local_nmi_line_count = 0;
127 let mut processor_count = 0usize;
128
129 // Do a pass over the entries so we know how much space we should reserve in the vectors
130 for entry in self.entries() {
131 match entry {
132 MadtEntry::IoApic(_) => io_apic_count += 1,
133 MadtEntry::InterruptSourceOverride(_) => iso_count += 1,
134 MadtEntry::NmiSource(_) => nmi_source_count += 1,
135 MadtEntry::LocalApicNmi(_) => local_nmi_line_count += 1,
136 MadtEntry::LocalApic(_) => processor_count += 1,
137 _ => (),
138 }
139 }
140
141 let mut io_apics = crate::ManagedSlice::new_in(io_apic_count, allocator.clone())?;
142 let mut interrupt_source_overrides = crate::ManagedSlice::new_in(iso_count, allocator.clone())?;
143 let mut nmi_sources = crate::ManagedSlice::new_in(nmi_source_count, allocator.clone())?;
144 let mut local_apic_nmi_lines = crate::ManagedSlice::new_in(local_nmi_line_count, allocator.clone())?;
145 let mut application_processors =
146 crate::ManagedSlice::new_in(processor_count.saturating_sub(1), allocator)?; // Subtract one for the BSP
147 let mut boot_processor = None;
148
149 io_apic_count = 0;
150 iso_count = 0;
151 nmi_source_count = 0;
152 local_nmi_line_count = 0;
153 processor_count = 0;
154
155 for entry in self.entries() {
156 match entry {
157 MadtEntry::LocalApic(entry) => {
158 /*
159 * The first processor is the BSP. Subsequent ones are APs. If we haven't found
160 * the BSP yet, this must be it.
161 */
162 let is_ap = boot_processor.is_some();
163 let is_disabled = !{ entry.flags }.get_bit(0);
164
165 let state = match (is_ap, is_disabled) {
166 (_, true) => ProcessorState::Disabled,
167 (true, false) => ProcessorState::WaitingForSipi,
168 (false, false) => ProcessorState::Running,
169 };
170
171 let processor = Processor {
172 processor_uid: entry.processor_id as u32,
173 local_apic_id: entry.apic_id as u32,
174 state,
175 is_ap,
176 };
177
178 if is_ap {
179 application_processors[processor_count] = processor;
180 processor_count += 1;
181 } else {
182 boot_processor = Some(processor);
183 }
184 }
185
186 MadtEntry::LocalX2Apic(entry) => {
187 let is_ap = boot_processor.is_some();
188 let is_disabled = !{ entry.flags }.get_bit(0);
189
190 let state = match (is_ap, is_disabled) {
191 (_, true) => ProcessorState::Disabled,
192 (true, false) => ProcessorState::WaitingForSipi,
193 (false, false) => ProcessorState::Running,
194 };
195
196 let processor = Processor {
197 processor_uid: entry.processor_uid,
198 local_apic_id: entry.x2apic_id,
199 state,
200 is_ap,
201 };
202
203 if is_ap {
204 application_processors[processor_count] = processor;
205 processor_count += 1;
206 } else {
207 boot_processor = Some(processor);
208 }
209 }
210
211 MadtEntry::IoApic(entry) => {
212 io_apics[io_apic_count] = IoApic {
213 id: entry.io_apic_id,
214 address: entry.io_apic_address,
215 global_system_interrupt_base: entry.global_system_interrupt_base,
216 };
217 io_apic_count += 1;
218 }
219
220 MadtEntry::InterruptSourceOverride(entry) => {
221 if entry.bus != 0 {
222 return Err(AcpiError::InvalidMadt(MadtError::InterruptOverrideEntryHasInvalidBus));
223 }
224
225 let (polarity, trigger_mode) = parse_mps_inti_flags(entry.flags)?;
226
227 interrupt_source_overrides[iso_count] = InterruptSourceOverride {
228 isa_source: entry.irq,
229 global_system_interrupt: entry.global_system_interrupt,
230 polarity,
231 trigger_mode,
232 };
233 iso_count += 1;
234 }
235
236 MadtEntry::NmiSource(entry) => {
237 let (polarity, trigger_mode) = parse_mps_inti_flags(entry.flags)?;
238
239 nmi_sources[nmi_source_count] = NmiSource {
240 global_system_interrupt: entry.global_system_interrupt,
241 polarity,
242 trigger_mode,
243 };
244 nmi_source_count += 1;
245 }
246
247 MadtEntry::LocalApicNmi(entry) => {
248 local_apic_nmi_lines[local_nmi_line_count] = NmiLine {
249 processor: if entry.processor_id == 0xff {
250 NmiProcessor::All
251 } else {
252 NmiProcessor::ProcessorUid(entry.processor_id as u32)
253 },
254 line: match entry.nmi_line {
255 0 => LocalInterruptLine::Lint0,
256 1 => LocalInterruptLine::Lint1,
257 _ => return Err(AcpiError::InvalidMadt(MadtError::InvalidLocalNmiLine)),
258 },
259 };
260 local_nmi_line_count += 1;
261 }
262
263 MadtEntry::X2ApicNmi(entry) => {
264 local_apic_nmi_lines[local_nmi_line_count] = NmiLine {
265 processor: if entry.processor_uid == 0xffffffff {
266 NmiProcessor::All
267 } else {
268 NmiProcessor::ProcessorUid(entry.processor_uid)
269 },
270 line: match entry.nmi_line {
271 0 => LocalInterruptLine::Lint0,
272 1 => LocalInterruptLine::Lint1,
273 _ => return Err(AcpiError::InvalidMadt(MadtError::InvalidLocalNmiLine)),
274 },
275 };
276 local_nmi_line_count += 1;
277 }
278
279 MadtEntry::LocalApicAddressOverride(entry) => {
280 local_apic_address = entry.local_apic_address;
281 }
282
283 _ => {
284 return Err(AcpiError::InvalidMadt(MadtError::UnexpectedEntry));
285 }
286 }
287 }
288
289 Ok((
290 InterruptModel::Apic(Apic::new(
291 local_apic_address,
292 io_apics,
293 local_apic_nmi_lines,
294 interrupt_source_overrides,
295 nmi_sources,
296 self.supports_8259(),
297 )),
298 Some(ProcessorInfo::new(boot_processor.unwrap(), application_processors)),
299 ))
300 }
301
entries(&self) -> MadtEntryIter302 pub fn entries(&self) -> MadtEntryIter {
303 MadtEntryIter {
304 pointer: unsafe { (self as *const Madt as *const u8).add(mem::size_of::<Madt>()) },
305 remaining_length: self.header.length - mem::size_of::<Madt>() as u32,
306 _phantom: PhantomData,
307 }
308 }
309
supports_8259(&self) -> bool310 pub fn supports_8259(&self) -> bool {
311 { self.flags }.get_bit(0)
312 }
313 }
314
315 #[derive(Debug)]
316 pub struct MadtEntryIter<'a> {
317 pointer: *const u8,
318 /*
319 * The iterator can only have at most `u32::MAX` remaining bytes, because the length of the
320 * whole SDT can only be at most `u32::MAX`.
321 */
322 remaining_length: u32,
323 _phantom: PhantomData<&'a ()>,
324 }
325
326 #[derive(Debug)]
327 pub enum MadtEntry<'a> {
328 LocalApic(&'a LocalApicEntry),
329 IoApic(&'a IoApicEntry),
330 InterruptSourceOverride(&'a InterruptSourceOverrideEntry),
331 NmiSource(&'a NmiSourceEntry),
332 LocalApicNmi(&'a LocalApicNmiEntry),
333 LocalApicAddressOverride(&'a LocalApicAddressOverrideEntry),
334 IoSapic(&'a IoSapicEntry),
335 LocalSapic(&'a LocalSapicEntry),
336 PlatformInterruptSource(&'a PlatformInterruptSourceEntry),
337 LocalX2Apic(&'a LocalX2ApicEntry),
338 X2ApicNmi(&'a X2ApicNmiEntry),
339 Gicc(&'a GiccEntry),
340 Gicd(&'a GicdEntry),
341 GicMsiFrame(&'a GicMsiFrameEntry),
342 GicRedistributor(&'a GicRedistributorEntry),
343 GicInterruptTranslationService(&'a GicInterruptTranslationServiceEntry),
344 MultiprocessorWakeup(&'a MultiprocessorWakeupEntry),
345 }
346
347 impl<'a> Iterator for MadtEntryIter<'a> {
348 type Item = MadtEntry<'a>;
349
next(&mut self) -> Option<Self::Item>350 fn next(&mut self) -> Option<Self::Item> {
351 while self.remaining_length > 0 {
352 let entry_pointer = self.pointer;
353 let header = unsafe { *(self.pointer as *const EntryHeader) };
354
355 self.pointer = unsafe { self.pointer.offset(header.length as isize) };
356 self.remaining_length -= header.length as u32;
357
358 macro_rules! construct_entry {
359 ($entry_type:expr,
360 $entry_pointer:expr,
361 $(($value:expr => $variant:path as $type:ty)),*
362 ) => {
363 match $entry_type {
364 $(
365 $value => {
366 return Some($variant(unsafe {
367 &*($entry_pointer as *const $type)
368 }))
369 }
370 )*
371
372 /*
373 * These entry types are reserved by the ACPI standard. We should skip them
374 * if they appear in a real MADT.
375 */
376 0x11..=0x7f => {}
377
378 /*
379 * These entry types are reserved for OEM use. Atm, we just skip them too.
380 * TODO: work out if we should ever do anything else here
381 */
382 0x80..=0xff => {}
383 }
384 }
385 }
386
387 #[rustfmt::skip]
388 construct_entry!(
389 header.entry_type,
390 entry_pointer,
391 (0x0 => MadtEntry::LocalApic as LocalApicEntry),
392 (0x1 => MadtEntry::IoApic as IoApicEntry),
393 (0x2 => MadtEntry::InterruptSourceOverride as InterruptSourceOverrideEntry),
394 (0x3 => MadtEntry::NmiSource as NmiSourceEntry),
395 (0x4 => MadtEntry::LocalApicNmi as LocalApicNmiEntry),
396 (0x5 => MadtEntry::LocalApicAddressOverride as LocalApicAddressOverrideEntry),
397 (0x6 => MadtEntry::IoSapic as IoSapicEntry),
398 (0x7 => MadtEntry::LocalSapic as LocalSapicEntry),
399 (0x8 => MadtEntry::PlatformInterruptSource as PlatformInterruptSourceEntry),
400 (0x9 => MadtEntry::LocalX2Apic as LocalX2ApicEntry),
401 (0xa => MadtEntry::X2ApicNmi as X2ApicNmiEntry),
402 (0xb => MadtEntry::Gicc as GiccEntry),
403 (0xc => MadtEntry::Gicd as GicdEntry),
404 (0xd => MadtEntry::GicMsiFrame as GicMsiFrameEntry),
405 (0xe => MadtEntry::GicRedistributor as GicRedistributorEntry),
406 (0xf => MadtEntry::GicInterruptTranslationService as GicInterruptTranslationServiceEntry),
407 (0x10 => MadtEntry::MultiprocessorWakeup as MultiprocessorWakeupEntry)
408 );
409 }
410
411 None
412 }
413 }
414
415 #[derive(Clone, Copy, Debug)]
416 #[repr(C, packed)]
417 pub struct EntryHeader {
418 pub entry_type: u8,
419 pub length: u8,
420 }
421
422 #[derive(Clone, Copy, Debug)]
423 #[repr(C, packed)]
424 pub struct LocalApicEntry {
425 pub header: EntryHeader,
426 pub processor_id: u8,
427 pub apic_id: u8,
428 pub flags: u32,
429 }
430
431 #[derive(Clone, Copy, Debug)]
432 #[repr(C, packed)]
433 pub struct IoApicEntry {
434 pub header: EntryHeader,
435 pub io_apic_id: u8,
436 _reserved: u8,
437 pub io_apic_address: u32,
438 pub global_system_interrupt_base: u32,
439 }
440
441 #[derive(Clone, Copy, Debug)]
442 #[repr(C, packed)]
443 pub struct InterruptSourceOverrideEntry {
444 pub header: EntryHeader,
445 pub bus: u8, // 0 - ISA bus
446 pub irq: u8, // This is bus-relative
447 pub global_system_interrupt: u32,
448 pub flags: u16,
449 }
450
451 #[derive(Clone, Copy, Debug)]
452 #[repr(C, packed)]
453 pub struct NmiSourceEntry {
454 pub header: EntryHeader,
455 pub flags: u16,
456 pub global_system_interrupt: u32,
457 }
458
459 #[derive(Clone, Copy, Debug)]
460 #[repr(C, packed)]
461 pub struct LocalApicNmiEntry {
462 pub header: EntryHeader,
463 pub processor_id: u8,
464 pub flags: u16,
465 pub nmi_line: u8, // Describes which LINTn is the NMI connected to
466 }
467
468 #[derive(Clone, Copy, Debug)]
469 #[repr(C, packed)]
470 pub struct LocalApicAddressOverrideEntry {
471 pub header: EntryHeader,
472 _reserved: u16,
473 pub local_apic_address: u64,
474 }
475
476 /// If this entry is present, the system has an I/O SAPIC, which must be used instead of the I/O
477 /// APIC.
478 #[derive(Clone, Copy, Debug)]
479 #[repr(C, packed)]
480 pub struct IoSapicEntry {
481 pub header: EntryHeader,
482 pub io_apic_id: u8,
483 _reserved: u8,
484 pub global_system_interrupt_base: u32,
485 pub io_sapic_address: u64,
486 }
487
488 #[derive(Clone, Copy, Debug)]
489 #[repr(C, packed)]
490 pub struct LocalSapicEntry {
491 pub header: EntryHeader,
492 pub processor_id: u8,
493 pub local_sapic_id: u8,
494 pub local_sapic_eid: u8,
495 _reserved: [u8; 3],
496 pub flags: u32,
497 pub processor_uid: u32,
498
499 /// This string can be used to associate this local SAPIC to a processor defined in the
500 /// namespace when the `_UID` object is a string. It is a null-terminated ASCII string, and so
501 /// this field will be `'\0'` if the string is not present, otherwise it extends from the
502 /// address of this field.
503 processor_uid_string: u8,
504 }
505
506 #[derive(Clone, Copy, Debug)]
507 #[repr(C, packed)]
508 pub struct PlatformInterruptSourceEntry {
509 pub header: EntryHeader,
510 pub flags: u16,
511 pub interrupt_type: u8,
512 pub processor_id: u8,
513 pub processor_eid: u8,
514 pub io_sapic_vector: u8,
515 pub global_system_interrupt: u32,
516 pub platform_interrupt_source_flags: u32,
517 }
518
519 #[derive(Clone, Copy, Debug)]
520 #[repr(C, packed)]
521 pub struct LocalX2ApicEntry {
522 pub header: EntryHeader,
523 _reserved: u16,
524 pub x2apic_id: u32,
525 pub flags: u32,
526 pub processor_uid: u32,
527 }
528
529 #[derive(Clone, Copy, Debug)]
530 #[repr(C, packed)]
531 pub struct X2ApicNmiEntry {
532 pub header: EntryHeader,
533 pub flags: u16,
534 pub processor_uid: u32,
535 pub nmi_line: u8,
536 _reserved: [u8; 3],
537 }
538
539 /// This field will appear for ARM processors that support ACPI and use the Generic Interrupt
540 /// Controller. In the GICC interrupt model, each logical process has a Processor Device object in
541 /// the namespace, and uses this structure to convey its GIC information.
542 #[derive(Clone, Copy, Debug)]
543 #[repr(C, packed)]
544 pub struct GiccEntry {
545 pub header: EntryHeader,
546 _reserved1: u16,
547 pub cpu_interface_number: u32,
548 pub processor_uid: u32,
549 pub flags: u32,
550 pub parking_protocol_version: u32,
551 pub performance_interrupt_gsiv: u32,
552 pub parked_address: u64,
553 pub gic_registers_address: u64,
554 pub gic_virtual_registers_address: u64,
555 pub gic_hypervisor_registers_address: u64,
556 pub vgic_maintenance_interrupt: u32,
557 pub gicr_base_address: u64,
558 pub mpidr: u64,
559 pub processor_power_efficiency_class: u8,
560 _reserved2: u8,
561 /// SPE overflow Interrupt.
562 ///
563 /// ACPI 6.3 defined this field. It is zero in prior versions or
564 /// if this processor does not support SPE.
565 pub spe_overflow_interrupt: u16,
566 pub trbe_interrupt: ExtendedField<u16, 6>,
567 }
568
569 #[derive(Clone, Copy, Debug)]
570 #[repr(C, packed)]
571 pub struct GicdEntry {
572 pub header: EntryHeader,
573 _reserved1: u16,
574 pub gic_id: u32,
575 pub physical_base_address: u64,
576 pub system_vector_base: u32,
577
578 /// The GIC version
579 /// 0x00: Fall back to hardware discovery
580 /// 0x01: GICv1
581 /// 0x02: GICv2
582 /// 0x03: GICv3
583 /// 0x04: GICv4
584 /// 0x05-0xff: Reserved for future use
585 pub gic_version: u8,
586 _reserved2: [u8; 3],
587 }
588
589 #[derive(Clone, Copy, Debug)]
590 #[repr(C, packed)]
591 pub struct GicMsiFrameEntry {
592 pub header: EntryHeader,
593 _reserved: u16,
594 pub frame_id: u32,
595 pub physical_base_address: u64,
596 pub flags: u32,
597 pub spi_count: u16,
598 pub spi_base: u16,
599 }
600
601 #[derive(Clone, Copy, Debug)]
602 #[repr(C, packed)]
603 pub struct GicRedistributorEntry {
604 pub header: EntryHeader,
605 _reserved: u16,
606 pub discovery_range_base_address: u64,
607 pub discovery_range_length: u32,
608 }
609
610 #[derive(Clone, Copy, Debug)]
611 #[repr(C, packed)]
612 pub struct GicInterruptTranslationServiceEntry {
613 pub header: EntryHeader,
614 _reserved1: u16,
615 pub id: u32,
616 pub physical_base_address: u64,
617 _reserved2: u32,
618 }
619
620 #[derive(Clone, Copy, Debug)]
621 #[repr(C, packed)]
622 pub struct MultiprocessorWakeupEntry {
623 pub header: EntryHeader,
624 pub mailbox_version: u16,
625 _reserved: u32,
626 pub mailbox_address: u64,
627 }
628
629 #[cfg(feature = "allocator_api")]
parse_mps_inti_flags(flags: u16) -> crate::AcpiResult<(Polarity, TriggerMode)>630 fn parse_mps_inti_flags(flags: u16) -> crate::AcpiResult<(Polarity, TriggerMode)> {
631 let polarity = match flags.get_bits(0..2) {
632 0b00 => Polarity::SameAsBus,
633 0b01 => Polarity::ActiveHigh,
634 0b11 => Polarity::ActiveLow,
635 _ => return Err(crate::AcpiError::InvalidMadt(MadtError::MpsIntiInvalidPolarity)),
636 };
637
638 let trigger_mode = match flags.get_bits(2..4) {
639 0b00 => TriggerMode::SameAsBus,
640 0b01 => TriggerMode::Edge,
641 0b11 => TriggerMode::Level,
642 _ => return Err(crate::AcpiError::InvalidMadt(MadtError::MpsIntiInvalidTriggerMode)),
643 };
644
645 Ok((polarity, trigger_mode))
646 }
647