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