1 use crate::ManagedSlice;
2 use core::alloc::Allocator;
3 
4 #[derive(Debug)]
5 pub struct IoApic {
6     pub id: u8,
7     /// The physical address at which to access this I/O APIC.
8     pub address: u32,
9     /// The global system interrupt number where this I/O APIC's inputs start.
10     pub global_system_interrupt_base: u32,
11 }
12 
13 #[derive(Debug)]
14 pub struct NmiLine {
15     pub processor: NmiProcessor,
16     pub line: LocalInterruptLine,
17 }
18 
19 /// Indicates which local interrupt line will be utilized by an external interrupt. Specifically,
20 /// these lines directly correspond to their requisite LVT entries in a processor's APIC.
21 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
22 pub enum LocalInterruptLine {
23     Lint0,
24     Lint1,
25 }
26 
27 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
28 pub enum NmiProcessor {
29     All,
30     ProcessorUid(u32),
31 }
32 
33 /// Polarity indicates what signal mode the interrupt line needs to be in to be considered 'active'.
34 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
35 pub enum Polarity {
36     SameAsBus,
37     ActiveHigh,
38     ActiveLow,
39 }
40 
41 /// Trigger mode of an interrupt, describing how the interrupt is triggered.
42 ///
43 /// When an interrupt is `Edge` triggered, it is triggered exactly once, when the interrupt
44 /// signal goes from its opposite polarity to its active polarity.
45 ///
46 /// For `Level` triggered interrupts, a continuous signal is emitted so long as the interrupt
47 /// is in its active polarity.
48 ///
49 /// `SameAsBus`-triggered interrupts will utilize the same interrupt triggering as the system bus
50 /// they communicate across.
51 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
52 pub enum TriggerMode {
53     SameAsBus,
54     Edge,
55     Level,
56 }
57 
58 /// Describes a difference in the mapping of an ISA interrupt to how it's mapped in other interrupt
59 /// models. For example, if a device is connected to ISA IRQ 0 and IOAPIC input 2, an override will
60 /// appear mapping source 0 to GSI 2. Currently these will only be created for ISA interrupt
61 /// sources.
62 #[derive(Debug)]
63 pub struct InterruptSourceOverride {
64     pub isa_source: u8,
65     pub global_system_interrupt: u32,
66     pub polarity: Polarity,
67     pub trigger_mode: TriggerMode,
68 }
69 
70 /// Describes a Global System Interrupt that should be enabled as non-maskable. Any source that is
71 /// non-maskable can not be used by devices.
72 #[derive(Debug)]
73 pub struct NmiSource {
74     pub global_system_interrupt: u32,
75     pub polarity: Polarity,
76     pub trigger_mode: TriggerMode,
77 }
78 
79 #[derive(Debug)]
80 pub struct Apic<'a, A>
81 where
82     A: Allocator,
83 {
84     pub local_apic_address: u64,
85     pub io_apics: ManagedSlice<'a, IoApic, A>,
86     pub local_apic_nmi_lines: ManagedSlice<'a, NmiLine, A>,
87     pub interrupt_source_overrides: ManagedSlice<'a, InterruptSourceOverride, A>,
88     pub nmi_sources: ManagedSlice<'a, NmiSource, A>,
89 
90     /// If this field is set, you must remap and mask all the lines of the legacy PIC, even if
91     /// you choose to use the APIC. It's recommended that you do this even if ACPI does not
92     /// require you to.
93     pub also_has_legacy_pics: bool,
94 }
95 
96 impl<'a, A> Apic<'a, A>
97 where
98     A: Allocator,
99 {
new( local_apic_address: u64, io_apics: ManagedSlice<'a, IoApic, A>, local_apic_nmi_lines: ManagedSlice<'a, NmiLine, A>, interrupt_source_overrides: ManagedSlice<'a, InterruptSourceOverride, A>, nmi_sources: ManagedSlice<'a, NmiSource, A>, also_has_legacy_pics: bool, ) -> Self100     pub(crate) fn new(
101         local_apic_address: u64,
102         io_apics: ManagedSlice<'a, IoApic, A>,
103         local_apic_nmi_lines: ManagedSlice<'a, NmiLine, A>,
104         interrupt_source_overrides: ManagedSlice<'a, InterruptSourceOverride, A>,
105         nmi_sources: ManagedSlice<'a, NmiSource, A>,
106         also_has_legacy_pics: bool,
107     ) -> Self {
108         Self {
109             local_apic_address,
110             io_apics,
111             local_apic_nmi_lines,
112             interrupt_source_overrides,
113             nmi_sources,
114             also_has_legacy_pics,
115         }
116     }
117 }
118 
119 #[derive(Debug)]
120 #[non_exhaustive]
121 pub enum InterruptModel<'a, A>
122 where
123     A: Allocator,
124 {
125     /// This model is only chosen when the MADT does not describe another interrupt model. On `x86_64` platforms,
126     /// this probably means only the legacy i8259 PIC is present.
127     Unknown,
128 
129     /// Describes an interrupt controller based around the Advanced Programmable Interrupt Controller (any of APIC,
130     /// XAPIC, or X2APIC). These are likely to be found on x86 and x86_64 systems and are made up of a Local APIC
131     /// for each core and one or more I/O APICs to handle external interrupts.
132     Apic(Apic<'a, A>),
133 }
134