/rust/registry/src/index.crates.io-1949cf8c6b5b557f/x86-0.47.0/src/irq.rs
Line | Count | Source |
1 | | //! Shared interrupt description and set-up code. |
2 | | //! See the `bits*::irq` modules for arch-specific portions. |
3 | | |
4 | | use bitflags::*; |
5 | | |
6 | | use core::arch::asm; |
7 | | use core::fmt; |
8 | | |
9 | | /// x86 Exception description (see also Intel Vol. 3a Chapter 6). |
10 | | #[derive(Debug)] |
11 | | pub 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 | | |
19 | | impl fmt::Display for InterruptDescription { |
20 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
21 | 0 | write!( |
22 | 0 | f, |
23 | 0 | "{} ({}, vec={}) {}", |
24 | | self.mnemonic, self.irqtype, self.vector, self.description |
25 | | ) |
26 | 0 | } |
27 | | } |
28 | | |
29 | | pub const DIVIDE_ERROR_VECTOR: u8 = 0; |
30 | | pub const DEBUG_VECTOR: u8 = 1; |
31 | | pub const NONMASKABLE_INTERRUPT_VECTOR: u8 = 2; |
32 | | pub const BREAKPOINT_VECTOR: u8 = 3; |
33 | | pub const OVERFLOW_VECTOR: u8 = 4; |
34 | | pub const BOUND_RANGE_EXCEEDED_VECTOR: u8 = 5; |
35 | | pub const INVALID_OPCODE_VECTOR: u8 = 6; |
36 | | pub const DEVICE_NOT_AVAILABLE_VECTOR: u8 = 7; |
37 | | pub const DOUBLE_FAULT_VECTOR: u8 = 8; |
38 | | pub const COPROCESSOR_SEGMENT_OVERRUN_VECTOR: u8 = 9; |
39 | | pub const INVALID_TSS_VECTOR: u8 = 10; |
40 | | pub const SEGMENT_NOT_PRESENT_VECTOR: u8 = 11; |
41 | | pub const STACK_SEGEMENT_FAULT_VECTOR: u8 = 12; |
42 | | pub const GENERAL_PROTECTION_FAULT_VECTOR: u8 = 13; |
43 | | pub const PAGE_FAULT_VECTOR: u8 = 14; |
44 | | pub const X87_FPU_VECTOR: u8 = 16; |
45 | | pub const ALIGNMENT_CHECK_VECTOR: u8 = 17; |
46 | | pub const MACHINE_CHECK_VECTOR: u8 = 18; |
47 | | pub const SIMD_FLOATING_POINT_VECTOR: u8 = 19; |
48 | | pub const VIRTUALIZATION_VECTOR: u8 = 20; |
49 | | |
50 | | /// x86 External Interrupts (1-32). |
51 | | pub 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 | | |
287 | | bitflags! { |
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 | | |
318 | | impl fmt::Display for PageFaultError { |
319 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
320 | 0 | let p = match self.contains(PageFaultError::P) { |
321 | 0 | false => "The fault was caused by a non-present page.", |
322 | 0 | true => "The fault was caused by a page-level protection violation.", |
323 | | }; |
324 | 0 | let wr = match self.contains(PageFaultError::WR) { |
325 | 0 | false => "The access causing the fault was a read.", |
326 | 0 | true => "The access causing the fault was a write.", |
327 | | }; |
328 | 0 | let us = match self.contains(PageFaultError::US) { |
329 | | false => { |
330 | 0 | "The access causing the fault originated when the processor was executing in \ |
331 | 0 | supervisor mode." |
332 | | } |
333 | | true => { |
334 | 0 | "The access causing the fault originated when the processor was executing in user \ |
335 | 0 | mode." |
336 | | } |
337 | | }; |
338 | 0 | let rsvd = match self.contains(PageFaultError::RSVD) { |
339 | 0 | false => "The fault was not caused by reserved bit violation.", |
340 | 0 | true => "The fault was caused by reserved bits set to 1 in a page directory.", |
341 | | }; |
342 | 0 | let id = match self.contains(PageFaultError::ID) { |
343 | 0 | false => "The fault was not caused by an instruction fetch.", |
344 | 0 | true => "The fault was caused by an instruction fetch.", |
345 | | }; |
346 | | |
347 | 0 | write!(f, "{}\n{}\n{}\n{}\n{}", p, wr, us, rsvd, id) |
348 | 0 | } |
349 | | } |
350 | | |
351 | | /// Enable Interrupts. |
352 | | /// |
353 | | /// # Safety |
354 | | /// Only allowed if we have IO privileges for the current operating level in RFlags. |
355 | 0 | pub unsafe fn enable() { |
356 | 0 | asm!("sti"); |
357 | 0 | } |
358 | | |
359 | | /// Disable Interrupts. |
360 | | /// |
361 | | /// # Safety |
362 | | /// Only allowed if we have IO privileges for the current operating level in RFlags. |
363 | 0 | pub unsafe fn disable() { |
364 | 0 | asm!("cli"); |
365 | 0 | } |
366 | | |
367 | | /// Generate a software interrupt. |
368 | | /// This is a macro argument needs to be an immediate. |
369 | | #[macro_export] |
370 | | macro_rules! int { |
371 | | ($x:expr) => {{ |
372 | | asm!("int ${vec}", vec = const ($x)); |
373 | | }}; |
374 | | } |
375 | | |
376 | | #[cfg(all(test, feature = "utest"))] |
377 | | mod 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 | | } |