x86/
irq.rs

1//! Shared interrupt description and set-up code.
2//! See the `bits*::irq` modules for arch-specific portions.
3
4use bitflags::*;
5
6use core::arch::asm;
7use core::fmt;
8
9/// x86 Exception description (see also Intel Vol. 3a Chapter 6).
10#[derive(Debug)]
11pub struct InterruptDescription {
12    pub vector: u8,
13    pub mnemonic: &'static str,
14    pub description: &'static str,
15    pub irqtype: &'static str,
16    pub source: &'static str,
17}
18
19impl fmt::Display for InterruptDescription {
20    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
21        write!(
22            f,
23            "{} ({}, vec={}) {}",
24            self.mnemonic, self.irqtype, self.vector, self.description
25        )
26    }
27}
28
29pub const DIVIDE_ERROR_VECTOR: u8 = 0;
30pub const DEBUG_VECTOR: u8 = 1;
31pub const NONMASKABLE_INTERRUPT_VECTOR: u8 = 2;
32pub const BREAKPOINT_VECTOR: u8 = 3;
33pub const OVERFLOW_VECTOR: u8 = 4;
34pub const BOUND_RANGE_EXCEEDED_VECTOR: u8 = 5;
35pub const INVALID_OPCODE_VECTOR: u8 = 6;
36pub const DEVICE_NOT_AVAILABLE_VECTOR: u8 = 7;
37pub const DOUBLE_FAULT_VECTOR: u8 = 8;
38pub const COPROCESSOR_SEGMENT_OVERRUN_VECTOR: u8 = 9;
39pub const INVALID_TSS_VECTOR: u8 = 10;
40pub const SEGMENT_NOT_PRESENT_VECTOR: u8 = 11;
41pub const STACK_SEGEMENT_FAULT_VECTOR: u8 = 12;
42pub const GENERAL_PROTECTION_FAULT_VECTOR: u8 = 13;
43pub const PAGE_FAULT_VECTOR: u8 = 14;
44pub const X87_FPU_VECTOR: u8 = 16;
45pub const ALIGNMENT_CHECK_VECTOR: u8 = 17;
46pub const MACHINE_CHECK_VECTOR: u8 = 18;
47pub const SIMD_FLOATING_POINT_VECTOR: u8 = 19;
48pub const VIRTUALIZATION_VECTOR: u8 = 20;
49
50/// x86 External Interrupts (1-32).
51pub static EXCEPTIONS: [InterruptDescription; 32] = [
52    InterruptDescription {
53        vector: DIVIDE_ERROR_VECTOR,
54        mnemonic: "#DE",
55        description: "Divide Error",
56        irqtype: "Fault",
57        source: "DIV and IDIV instructions.",
58    },
59    InterruptDescription {
60        vector: DEBUG_VECTOR,
61        mnemonic: "#DB",
62        description: "Debug",
63        irqtype: "Fault / Trap",
64        source: "Debug condition",
65    },
66    InterruptDescription {
67        vector: NONMASKABLE_INTERRUPT_VECTOR,
68        mnemonic: "NMI",
69        description: "Nonmaskable Interrupt",
70        irqtype: "Interrupt",
71        source: "Nonmaskable external interrupt.",
72    },
73    InterruptDescription {
74        vector: BREAKPOINT_VECTOR,
75        mnemonic: "#BP",
76        description: "Breakpoint",
77        irqtype: "Trap",
78        source: "INT 3 instruction.",
79    },
80    InterruptDescription {
81        vector: OVERFLOW_VECTOR,
82        mnemonic: "#OF",
83        description: "Overflow",
84        irqtype: "Trap",
85        source: "INTO instruction.",
86    },
87    InterruptDescription {
88        vector: BOUND_RANGE_EXCEEDED_VECTOR,
89        mnemonic: "#BR",
90        description: "BOUND Range Exceeded",
91        irqtype: "Fault",
92        source: "BOUND instruction.",
93    },
94    InterruptDescription {
95        vector: INVALID_OPCODE_VECTOR,
96        mnemonic: "#UD",
97        description: "Invalid Opcode (Undefined \
98                      Opcode)",
99        irqtype: "Fault",
100        source: "UD2 instruction or reserved \
101                 opcode.",
102    },
103    InterruptDescription {
104        vector: DEVICE_NOT_AVAILABLE_VECTOR,
105        mnemonic: "#NM",
106        description: "Device Not Available (No \
107                      Math Coprocessor)",
108        irqtype: "Fault",
109        source: "Floating-point or WAIT/FWAIT \
110                 instruction.",
111    },
112    InterruptDescription {
113        vector: DOUBLE_FAULT_VECTOR,
114        mnemonic: "#DF",
115        description: "Double Fault",
116        irqtype: "Abort",
117        source: "Any instruction that can \
118                 generate an exception, an NMI, \
119                 or an INTR.",
120    },
121    InterruptDescription {
122        vector: COPROCESSOR_SEGMENT_OVERRUN_VECTOR,
123        mnemonic: "",
124        description: "Coprocessor Segment Overrun",
125        irqtype: "Fault",
126        source: "Floating-point instruction.",
127    },
128    InterruptDescription {
129        vector: INVALID_TSS_VECTOR,
130        mnemonic: "#TS",
131        description: "Invalid TSS",
132        irqtype: "Fault",
133        source: "Task switch or TSS access.",
134    },
135    InterruptDescription {
136        vector: SEGMENT_NOT_PRESENT_VECTOR,
137        mnemonic: "#NP",
138        description: "Segment Not Present",
139        irqtype: "Fault",
140        source: "Loading segment registers or \
141                 accessing system segments.",
142    },
143    InterruptDescription {
144        vector: STACK_SEGEMENT_FAULT_VECTOR,
145        mnemonic: "#SS",
146        description: "Stack-Segment Fault",
147        irqtype: "Fault",
148        source: "Stack operations and SS register \
149                 loads.",
150    },
151    InterruptDescription {
152        vector: GENERAL_PROTECTION_FAULT_VECTOR,
153        mnemonic: "#GP",
154        description: "General Protection",
155        irqtype: "Fault",
156        source: "Any memory reference and other \
157                 protection checks.",
158    },
159    InterruptDescription {
160        vector: PAGE_FAULT_VECTOR,
161        mnemonic: "#PF",
162        description: "Page Fault",
163        irqtype: "Fault",
164        source: "Any memory reference.",
165    },
166    InterruptDescription {
167        vector: 15,
168        mnemonic: "",
169        description: "RESERVED",
170        irqtype: "",
171        source: "None.",
172    },
173    InterruptDescription {
174        vector: X87_FPU_VECTOR,
175        mnemonic: "#MF",
176        description: "x87 FPU Floating-Point",
177        irqtype: "Fault",
178        source: "x87 FPU instructions.",
179    },
180    InterruptDescription {
181        vector: ALIGNMENT_CHECK_VECTOR,
182        mnemonic: "#AC",
183        description: "Alignment Check",
184        irqtype: "Fault",
185        source: "Unaligned memory access.",
186    },
187    InterruptDescription {
188        vector: MACHINE_CHECK_VECTOR,
189        mnemonic: "#MC",
190        description: "Machine Check",
191        irqtype: "Abort",
192        source: "Internal machine error.",
193    },
194    InterruptDescription {
195        vector: SIMD_FLOATING_POINT_VECTOR,
196        mnemonic: "#XM",
197        description: "SIMD Floating-Point",
198        irqtype: "Fault",
199        source: "SSE SIMD instructions.",
200    },
201    InterruptDescription {
202        vector: VIRTUALIZATION_VECTOR,
203        mnemonic: "#VE",
204        description: "Virtualization",
205        irqtype: "Fault",
206        source: "EPT violation.",
207    },
208    InterruptDescription {
209        vector: 21,
210        mnemonic: "",
211        description: "RESERVED",
212        irqtype: "",
213        source: ".",
214    },
215    InterruptDescription {
216        vector: 22,
217        mnemonic: "",
218        description: "RESERVED",
219        irqtype: "",
220        source: ".",
221    },
222    InterruptDescription {
223        vector: 23,
224        mnemonic: "",
225        description: "RESERVED",
226        irqtype: "",
227        source: ".",
228    },
229    InterruptDescription {
230        vector: 24,
231        mnemonic: "",
232        description: "RESERVED",
233        irqtype: "",
234        source: ".",
235    },
236    InterruptDescription {
237        vector: 25,
238        mnemonic: "",
239        description: "RESERVED",
240        irqtype: "",
241        source: ".",
242    },
243    InterruptDescription {
244        vector: 26,
245        mnemonic: "",
246        description: "RESERVED",
247        irqtype: "",
248        source: ".",
249    },
250    InterruptDescription {
251        vector: 27,
252        mnemonic: "",
253        description: "RESERVED",
254        irqtype: "",
255        source: "",
256    },
257    InterruptDescription {
258        vector: 28,
259        mnemonic: "",
260        description: "",
261        irqtype: "",
262        source: "",
263    },
264    InterruptDescription {
265        vector: 29,
266        mnemonic: "",
267        description: "RESERVED",
268        irqtype: "",
269        source: ".",
270    },
271    InterruptDescription {
272        vector: 30,
273        mnemonic: "",
274        description: "RESERVED",
275        irqtype: "",
276        source: "",
277    },
278    InterruptDescription {
279        vector: 31,
280        mnemonic: "",
281        description: "RESERVED",
282        irqtype: "",
283        source: "",
284    },
285];
286
287bitflags! {
288    // Taken from Intel Manual Section 4.7 Page-Fault Exceptions.
289    pub struct PageFaultError: u32 {
290        /// 0: The fault was caused by a non-present page.
291        /// 1: The fault was caused by a page-level protection violation
292        const P = bit!(0);
293
294        /// 0: The access causing the fault was a read.
295        /// 1: The access causing the fault was a write.
296        const WR = bit!(1);
297
298        /// 0: The access causing the fault originated when the processor
299        /// was executing in supervisor mode.
300        /// 1: The access causing the fault originated when the processor
301        /// was executing in user mode.
302        const US = bit!(2);
303
304        /// 0: The fault was not caused by reserved bit violation.
305        /// 1: The fault was caused by reserved bits set to 1 in a page directory.
306        const RSVD = bit!(3);
307
308        /// 0: The fault was not caused by an instruction fetch.
309        /// 1: The fault was caused by an instruction fetch.
310        const ID = bit!(4);
311
312        /// 0: The fault was not by protection keys.
313        /// 1: There was a protection key violation.
314        const PK = bit!(5);
315    }
316}
317
318impl fmt::Display for PageFaultError {
319    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
320        let p = match self.contains(PageFaultError::P) {
321            false => "The fault was caused by a non-present page.",
322            true => "The fault was caused by a page-level protection violation.",
323        };
324        let wr = match self.contains(PageFaultError::WR) {
325            false => "The access causing the fault was a read.",
326            true => "The access causing the fault was a write.",
327        };
328        let us = match self.contains(PageFaultError::US) {
329            false => {
330                "The access causing the fault originated when the processor was executing in \
331                 supervisor mode."
332            }
333            true => {
334                "The access causing the fault originated when the processor was executing in user \
335                 mode."
336            }
337        };
338        let rsvd = match self.contains(PageFaultError::RSVD) {
339            false => "The fault was not caused by reserved bit violation.",
340            true => "The fault was caused by reserved bits set to 1 in a page directory.",
341        };
342        let id = match self.contains(PageFaultError::ID) {
343            false => "The fault was not caused by an instruction fetch.",
344            true => "The fault was caused by an instruction fetch.",
345        };
346
347        write!(f, "{}\n{}\n{}\n{}\n{}", p, wr, us, rsvd, id)
348    }
349}
350
351/// Enable Interrupts.
352///
353/// # Safety
354/// Only allowed if we have IO privileges for the current operating level in RFlags.
355pub unsafe fn enable() {
356    asm!("sti");
357}
358
359/// Disable Interrupts.
360///
361/// # Safety
362/// Only allowed if we have IO privileges for the current operating level in RFlags.
363pub unsafe fn disable() {
364    asm!("cli");
365}
366
367/// Generate a software interrupt.
368/// This is a macro argument needs to be an immediate.
369#[macro_export]
370macro_rules! int {
371    ($x:expr) => {{
372        core::arch::asm!("int ${vec}", vec = const ($x));
373    }};
374}
375
376#[cfg(all(test, feature = "utest"))]
377mod test {
378    use super::*;
379    #[test]
380    fn bit_macro() {
381        assert!(PageFaultError::PK.bits() == 0b100000);
382        assert!(PageFaultError::ID.bits() == 0b10000);
383        assert!(PageFaultError::RSVD.bits() == 0b1000);
384        assert!(PageFaultError::US.bits() == 0b100);
385        assert!(PageFaultError::WR.bits() == 0b10);
386        assert!(PageFaultError::P.bits() == 0b1);
387    }
388}