tartan_arch/x86_common/interrupt.rs
1//! Support for managing interrupts.
2
3use crate::model_specific_register_access;
4use core::arch::asm;
5use tartan_bitfield::bitfield;
6use tartan_c_enum::c_enum;
7
8#[cfg(doc)]
9use super::FlagRegister;
10
11
12c_enum! {
13 /// An interrupt/exception number.
14 pub enum InterruptVector(u8) {
15 /// `#DE`: Division by zero or overflow in division.
16 DivideError = 0,
17 /// `#DB`: Breakpoints or other debugging-related traps/faults.
18 DebugException = 1,
19 /// `NMI`: Severe external interrupt that cannot be ignored.
20 NonMaskable = 2,
21 /// `#BP`: Breakpoint via `INT3` instruction.
22 Breakpoint = 3,
23 /// `#OF`: Overflow condition was detected with `INTO` instruction.
24 Overflow = 4,
25 /// `#BR`: Out-of-bounds index detected with `BOUND` instruction.
26 Bound = 5,
27 /// `#UD`: Unrecognized or reserved instruction opcode.
28 InvalidOpcode = 6,
29 /// `#NM`: Tried to execute FPU instruction with no coprocessor present.
30 DeviceNotAvailable = 7,
31 /// `#DF`: A fault was triggered while handling another interrupt.
32 DoubleFault = 8,
33 /// `#TS`: An error was found in the TSS while task switching.
34 InvalidTaskSegment = 10,
35 /// `#NP`: Tried to use a segment without a descriptor defined. Does not apply to
36 /// the stack segment, which has its [own exception](Self::SegmentNotPresent).
37 SegmentNotPresent = 11,
38 /// `#SS`: The stack overflowed its segment or the segment was invalid.
39 StackFault = 12,
40 /// `#GP`: Memory protection or other miscellaneous error.
41 ProtectionFault = 13,
42 /// `#PF`: Tried to load a page that was not present, or used a page in a way that
43 /// was not allowed by its attributes.
44 PageFault = 14,
45 /// `#MF`: Unmasked floating-point error that was *not* part of a SIMD operation.
46 FloatingPointError = 16,
47 /// `#AC`: Improperly aligned memory access in user mode while alignment checks
48 /// were enabled.
49 ///
50 /// See [`FlagRegister::alignment_check_or_access_control`].
51 AlignmentCheck = 17,
52 /// `#MC`: Internal processor/bus error.
53 MachineCheck = 18,
54 /// `#XM`: Unmasked floating-point error during SIMD operation.
55 SIMDFloatingPointError = 19,
56 /// `#VE`: Improper use of virtualization extensions.
57 ///
58 /// See [`ControlRegister4::virtual_machine_extensions`].
59 VirtualizationException = 20,
60 /// `#CP`: Improper branching detected by control-flow guard.
61 ///
62 /// See [`ControlRegister4::control_flow_enforcement`].
63 ControlProtectionException = 21,
64 }
65}
66
67impl InterruptVector {
68 /// Minimum user-defined interrupt vector.
69 const MIN_USER: InterruptVector = InterruptVector(32);
70
71 /// Indicates that this is interrupt vector is reserved by the system.
72 pub fn reserved(self) -> bool {
73 self < Self::MIN_USER
74 }
75}
76
77
78/// `IDTR`: Contains the memory range of the interrupt descriptor table.
79#[repr(C, packed)]
80#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
81#[allow(clippy::module_name_repetitions)]
82pub struct InterruptDescriptorTableRegister {
83 /// The inclusive maximum address offset (i.e., size - 1) of the descriptor table.
84 pub limit: u16,
85 /// Base address of the descriptor table.
86 pub address: usize,
87}
88
89impl InterruptDescriptorTableRegister {
90 /// Retrieve the current value of this register
91 pub fn get() -> Self {
92 let mut value = Self::default();
93 unsafe {
94 asm!(
95 "sidt [{0}]",
96 in(reg) &raw mut value,
97 );
98 }
99 value
100 }
101
102 /// Update the register to the given value.
103 ///
104 /// # Safety
105 /// This register can have fundamental affects on how programs execute.
106 pub unsafe fn set(value: &Self) {
107 asm!(
108 "lidt [{0}]",
109 in(reg) value,
110 );
111 }
112}
113
114
115bitfield! {
116 /// `IA32_APIC_BASE`: A model-specific register that allows relocating an advanced
117 /// programmable interrupt controller (APIC)'s control structure.
118 ///
119 /// See Intel ISA volume 2 §10.4.3–10.4.4.
120 pub struct APICBaseRegister(u64) {
121 /// Can be cleared to disable the APIC. However, it cannot be re-enabled once
122 /// disabled with this mechanism.
123 [11] pub enabled,
124 /// Enable the APIC's
125 [10] pub x2_interface,
126 /// Indicates that this core was designated as the bootstrap processor for
127 /// single-threaded operation on startup.
128 [8] pub bootstrap_processor,
129 }
130}
131
132impl APICBaseRegister {
133 /// The default APIC base address when the processor is reset.
134 pub const DEFAULT_ADDRESS: usize = 0xfee0_0000;
135 const ADDRESS_MASK: u64 = 0xffff_ffff_ffff_f000;
136
137 /// Base address of the APIC's registers.
138 pub fn address(self) -> usize {
139 #![allow(clippy::cast_possible_truncation)]
140 (self.0 & Self::ADDRESS_MASK) as usize
141 }
142
143 /// Update the base address of the APIC's registers.
144 pub fn set_address(&mut self, address: usize) {
145 self.0 &= !Self::ADDRESS_MASK;
146 self.0 |= Self::ADDRESS_MASK & address as u64;
147 }
148}
149
150model_specific_register_access!(APICBaseRegister, 0x1b);