x86_64/structures/idt.rs
1// Copyright 2017 Philipp Oppermann. See the README.md
2// file at the top-level directory of this distribution.
3//
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7// option. This file may not be copied, modified, or distributed
8// except according to those terms.
9
10//! Provides types for the Interrupt Descriptor Table and its entries.
11//!
12//! # For the builds without the `abi_x86_interrupt` feature
13//! The following types are opaque and non-constructable instead of function pointers.
14//!
15//! - [`DivergingHandlerFunc`]
16//! - [`DivergingHandlerFuncWithErrCode`]
17//! - [`HandlerFunc`]
18//! - [`HandlerFuncWithErrCode`]
19//! - [`PageFaultHandlerFunc`]
20//!
21//! These types are defined for the compatibility with the Nightly Rust build.
22
23use crate::registers::rflags::RFlags;
24use crate::{PrivilegeLevel, VirtAddr};
25use bit_field::BitField;
26use bitflags::bitflags;
27use core::convert::TryFrom;
28use core::fmt;
29use core::marker::PhantomData;
30use core::ops::Bound::{Excluded, Included, Unbounded};
31use core::ops::{
32 Bound, Deref, Index, IndexMut, Range, RangeBounds, RangeFrom, RangeFull, RangeInclusive,
33 RangeTo, RangeToInclusive,
34};
35use volatile::Volatile;
36
37use super::gdt::SegmentSelector;
38
39/// An Interrupt Descriptor Table with 256 entries.
40///
41/// The first 32 entries are used for CPU exceptions. These entries can be either accessed through
42/// fields on this struct or through an index operation, e.g. `idt[0]` returns the
43/// first entry, the entry for the `divide_error` exception. Note that the index access is
44/// not possible for entries for which an error code is pushed.
45///
46/// The remaining entries are used for interrupts. They can be accessed through index
47/// operations on the idt, e.g. `idt[32]` returns the first interrupt entry, which is the 32nd IDT
48/// entry).
49///
50///
51/// The field descriptions are taken from the
52/// [AMD64 manual volume 2](https://support.amd.com/TechDocs/24593.pdf)
53/// (with slight modifications).
54#[derive(Clone, Debug)]
55#[repr(C)]
56#[repr(align(16))]
57pub struct InterruptDescriptorTable {
58 /// A divide error (`#DE`) occurs when the denominator of a DIV instruction or
59 /// an IDIV instruction is 0. A `#DE` also occurs if the result is too large to be
60 /// represented in the destination.
61 ///
62 /// The saved instruction pointer points to the instruction that caused the `#DE`.
63 ///
64 /// The vector number of the `#DE` exception is 0.
65 pub divide_error: Entry<HandlerFunc>,
66
67 /// When the debug-exception mechanism is enabled, a `#DB` exception can occur under any
68 /// of the following circumstances:
69 ///
70 /// <details>
71 ///
72 /// - Instruction execution.
73 /// - Instruction single stepping.
74 /// - Data read.
75 /// - Data write.
76 /// - I/O read.
77 /// - I/O write.
78 /// - Task switch.
79 /// - Debug-register access, or general detect fault (debug register access when DR7.GD=1).
80 /// - Executing the INT1 instruction (opcode 0F1h).
81 ///
82 /// </details>
83 ///
84 /// `#DB` conditions are enabled and disabled using the debug-control register, `DR7`
85 /// and `RFLAGS.TF`.
86 ///
87 /// In the following cases, the saved instruction pointer points to the instruction that
88 /// caused the `#DB`:
89 ///
90 /// - Instruction execution.
91 /// - Invalid debug-register access, or general detect.
92 ///
93 /// In all other cases, the instruction that caused the `#DB` is completed, and the saved
94 /// instruction pointer points to the instruction after the one that caused the `#DB`.
95 ///
96 /// The vector number of the `#DB` exception is 1.
97 pub debug: Entry<HandlerFunc>,
98
99 /// An non maskable interrupt exception (NMI) occurs as a result of system logic
100 /// signaling a non-maskable interrupt to the processor.
101 ///
102 /// The processor recognizes an NMI at an instruction boundary.
103 /// The saved instruction pointer points to the instruction immediately following the
104 /// boundary where the NMI was recognized.
105 ///
106 /// The vector number of the NMI exception is 2.
107 pub non_maskable_interrupt: Entry<HandlerFunc>,
108
109 /// A breakpoint (`#BP`) exception occurs when an `INT3` instruction is executed. The
110 /// `INT3` is normally used by debug software to set instruction breakpoints by replacing
111 ///
112 /// The saved instruction pointer points to the byte after the `INT3` instruction.
113 ///
114 /// The vector number of the `#BP` exception is 3.
115 pub breakpoint: Entry<HandlerFunc>,
116
117 /// An overflow exception (`#OF`) occurs as a result of executing an `INTO` instruction
118 /// while the overflow bit in `RFLAGS` is set to 1.
119 ///
120 /// The saved instruction pointer points to the instruction following the `INTO`
121 /// instruction that caused the `#OF`.
122 ///
123 /// The vector number of the `#OF` exception is 4.
124 pub overflow: Entry<HandlerFunc>,
125
126 /// A bound-range exception (`#BR`) exception can occur as a result of executing
127 /// the `BOUND` instruction. The `BOUND` instruction compares an array index (first
128 /// operand) with the lower bounds and upper bounds of an array (second operand).
129 /// If the array index is not within the array boundary, the `#BR` occurs.
130 ///
131 /// The saved instruction pointer points to the `BOUND` instruction that caused the `#BR`.
132 ///
133 /// The vector number of the `#BR` exception is 5.
134 pub bound_range_exceeded: Entry<HandlerFunc>,
135
136 /// An invalid opcode exception (`#UD`) occurs when an attempt is made to execute an
137 /// invalid or undefined opcode. The validity of an opcode often depends on the
138 /// processor operating mode.
139 ///
140 /// <details><summary>A `#UD` occurs under the following conditions:</summary>
141 ///
142 /// - Execution of any reserved or undefined opcode in any mode.
143 /// - Execution of the `UD2` instruction.
144 /// - Use of the `LOCK` prefix on an instruction that cannot be locked.
145 /// - Use of the `LOCK` prefix on a lockable instruction with a non-memory target location.
146 /// - Execution of an instruction with an invalid-operand type.
147 /// - Execution of the `SYSENTER` or `SYSEXIT` instructions in long mode.
148 /// - Execution of any of the following instructions in 64-bit mode: `AAA`, `AAD`,
149 /// `AAM`, `AAS`, `BOUND`, `CALL` (opcode 9A), `DAA`, `DAS`, `DEC`, `INC`, `INTO`,
150 /// `JMP` (opcode EA), `LDS`, `LES`, `POP` (`DS`, `ES`, `SS`), `POPA`, `PUSH` (`CS`,
151 /// `DS`, `ES`, `SS`), `PUSHA`, `SALC`.
152 /// - Execution of the `ARPL`, `LAR`, `LLDT`, `LSL`, `LTR`, `SLDT`, `STR`, `VERR`, or
153 /// `VERW` instructions when protected mode is not enabled, or when virtual-8086 mode
154 /// is enabled.
155 /// - Execution of any legacy SSE instruction when `CR4.OSFXSR` is cleared to 0.
156 /// - Execution of any SSE instruction (uses `YMM`/`XMM` registers), or 64-bit media
157 /// instruction (uses `MMXTM` registers) when `CR0.EM` = 1.
158 /// - Execution of any SSE floating-point instruction (uses `YMM`/`XMM` registers) that
159 /// causes a numeric exception when `CR4.OSXMMEXCPT` = 0.
160 /// - Use of the `DR4` or `DR5` debug registers when `CR4.DE` = 1.
161 /// - Execution of `RSM` when not in `SMM` mode.
162 ///
163 /// </details>
164 ///
165 /// The saved instruction pointer points to the instruction that caused the `#UD`.
166 ///
167 /// The vector number of the `#UD` exception is 6.
168 pub invalid_opcode: Entry<HandlerFunc>,
169
170 /// A device not available exception (`#NM`) occurs under any of the following conditions:
171 ///
172 /// <details>
173 ///
174 /// - An `FWAIT`/`WAIT` instruction is executed when `CR0.MP=1` and `CR0.TS=1`.
175 /// - Any x87 instruction other than `FWAIT` is executed when `CR0.EM=1`.
176 /// - Any x87 instruction is executed when `CR0.TS=1`. The `CR0.MP` bit controls whether the
177 /// `FWAIT`/`WAIT` instruction causes an `#NM` exception when `TS=1`.
178 /// - Any 128-bit or 64-bit media instruction when `CR0.TS=1`.
179 ///
180 /// </details>
181 ///
182 /// The saved instruction pointer points to the instruction that caused the `#NM`.
183 ///
184 /// The vector number of the `#NM` exception is 7.
185 pub device_not_available: Entry<HandlerFunc>,
186
187 /// A double fault (`#DF`) exception can occur when a second exception occurs during
188 /// the handling of a prior (first) exception or interrupt handler.
189 ///
190 /// <details>
191 ///
192 /// Usually, the first and second exceptions can be handled sequentially without
193 /// resulting in a `#DF`. In this case, the first exception is considered _benign_, as
194 /// it does not harm the ability of the processor to handle the second exception. In some
195 /// cases, however, the first exception adversely affects the ability of the processor to
196 /// handle the second exception. These exceptions contribute to the occurrence of a `#DF`,
197 /// and are called _contributory exceptions_. The following exceptions are contributory:
198 ///
199 /// - Invalid-TSS Exception
200 /// - Segment-Not-Present Exception
201 /// - Stack Exception
202 /// - General-Protection Exception
203 ///
204 /// A double-fault exception occurs in the following cases:
205 ///
206 /// - If a contributory exception is followed by another contributory exception.
207 /// - If a divide-by-zero exception is followed by a contributory exception.
208 /// - If a page fault is followed by another page fault or a contributory exception.
209 ///
210 /// If a third interrupting event occurs while transferring control to the `#DF` handler,
211 /// the processor shuts down.
212 ///
213 /// </details>
214 ///
215 /// The returned error code is always zero. The saved instruction pointer is undefined,
216 /// and the program cannot be restarted.
217 ///
218 /// The vector number of the `#DF` exception is 8.
219 pub double_fault: Entry<DivergingHandlerFuncWithErrCode>,
220
221 /// This interrupt vector is reserved. It is for a discontinued exception originally used
222 /// by processors that supported external x87-instruction coprocessors. On those processors,
223 /// the exception condition is caused by an invalid-segment or invalid-page access on an
224 /// x87-instruction coprocessor-instruction operand. On current processors, this condition
225 /// causes a general-protection exception to occur.
226 coprocessor_segment_overrun: Entry<HandlerFunc>,
227
228 /// An invalid TSS exception (`#TS`) occurs only as a result of a control transfer through
229 /// a gate descriptor that results in an invalid stack-segment reference using an `SS`
230 /// selector in the TSS.
231 ///
232 /// The returned error code is the `SS` segment selector. The saved instruction pointer
233 /// points to the control-transfer instruction that caused the `#TS`.
234 ///
235 /// The vector number of the `#TS` exception is 10.
236 pub invalid_tss: Entry<HandlerFuncWithErrCode>,
237
238 /// An segment-not-present exception (`#NP`) occurs when an attempt is made to load a
239 /// segment or gate with a clear present bit.
240 ///
241 /// The returned error code is the segment-selector index of the segment descriptor
242 /// causing the `#NP` exception. The saved instruction pointer points to the instruction
243 /// that loaded the segment selector resulting in the `#NP`.
244 ///
245 /// The vector number of the `#NP` exception is 11.
246 pub segment_not_present: Entry<HandlerFuncWithErrCode>,
247
248 /// An stack segment exception (`#SS`) can occur in the following situations:
249 ///
250 /// - Implied stack references in which the stack address is not in canonical
251 /// form. Implied stack references include all push and pop instructions, and any
252 /// instruction using `RSP` or `RBP` as a base register.
253 /// - Attempting to load a stack-segment selector that references a segment descriptor
254 /// containing a clear present bit.
255 /// - Any stack access that fails the stack-limit check.
256 ///
257 /// The returned error code depends on the cause of the `#SS`. If the cause is a cleared
258 /// present bit, the error code is the corresponding segment selector. Otherwise, the
259 /// error code is zero. The saved instruction pointer points to the instruction that
260 /// caused the `#SS`.
261 ///
262 /// The vector number of the `#NP` exception is 12.
263 pub stack_segment_fault: Entry<HandlerFuncWithErrCode>,
264
265 /// A general protection fault (`#GP`) can occur in various situations. Common causes include:
266 ///
267 /// - Executing a privileged instruction while `CPL > 0`.
268 /// - Writing a 1 into any register field that is reserved, must be zero (MBZ).
269 /// - Attempting to execute an SSE instruction specifying an unaligned memory operand.
270 /// - Loading a non-canonical base address into the `GDTR` or `IDTR`.
271 /// - Using WRMSR to write a read-only MSR.
272 /// - Any long-mode consistency-check violation.
273 ///
274 /// The returned error code is a segment selector, if the cause of the `#GP` is
275 /// segment-related, and zero otherwise. The saved instruction pointer points to
276 /// the instruction that caused the `#GP`.
277 ///
278 /// The vector number of the `#GP` exception is 13.
279 pub general_protection_fault: Entry<HandlerFuncWithErrCode>,
280
281 /// A page fault (`#PF`) can occur during a memory access in any of the following situations:
282 ///
283 /// - A page-translation-table entry or physical page involved in translating the memory
284 /// access is not present in physical memory. This is indicated by a cleared present
285 /// bit in the translation-table entry.
286 /// - An attempt is made by the processor to load the instruction TLB with a translation
287 /// for a non-executable page.
288 /// - The memory access fails the paging-protection checks (user/supervisor, read/write,
289 /// or both).
290 /// - A reserved bit in one of the page-translation-table entries is set to 1. A `#PF`
291 /// occurs for this reason only when `CR4.PSE=1` or `CR4.PAE=1`.
292 ///
293 /// The virtual (linear) address that caused the `#PF` is stored in the `CR2` register.
294 /// The saved instruction pointer points to the instruction that caused the `#PF`.
295 ///
296 /// The page-fault error code is described by the
297 /// [`PageFaultErrorCode`](struct.PageFaultErrorCode.html) struct.
298 ///
299 /// The vector number of the `#PF` exception is 14.
300 pub page_fault: Entry<PageFaultHandlerFunc>,
301
302 /// vector nr. 15
303 reserved_1: Entry<HandlerFunc>,
304
305 /// The x87 Floating-Point Exception-Pending exception (`#MF`) is used to handle unmasked x87
306 /// floating-point exceptions. In 64-bit mode, the x87 floating point unit is not used
307 /// anymore, so this exception is only relevant when executing programs in the 32-bit
308 /// compatibility mode.
309 ///
310 /// The vector number of the `#MF` exception is 16.
311 pub x87_floating_point: Entry<HandlerFunc>,
312
313 /// An alignment check exception (`#AC`) occurs when an unaligned-memory data reference
314 /// is performed while alignment checking is enabled. An `#AC` can occur only when CPL=3.
315 ///
316 /// The returned error code is always zero. The saved instruction pointer points to the
317 /// instruction that caused the `#AC`.
318 ///
319 /// The vector number of the `#AC` exception is 17.
320 pub alignment_check: Entry<HandlerFuncWithErrCode>,
321
322 /// The machine check exception (`#MC`) is model specific. Processor implementations
323 /// are not required to support the `#MC` exception, and those implementations that do
324 /// support `#MC` can vary in how the `#MC` exception mechanism works.
325 ///
326 /// There is no reliable way to restart the program.
327 ///
328 /// The vector number of the `#MC` exception is 18.
329 pub machine_check: Entry<DivergingHandlerFunc>,
330
331 /// The SIMD Floating-Point Exception (`#XF`) is used to handle unmasked SSE
332 /// floating-point exceptions. The SSE floating-point exceptions reported by
333 /// the `#XF` exception are (including mnemonics):
334 ///
335 /// - IE: Invalid-operation exception (also called #I).
336 /// - DE: Denormalized-operand exception (also called #D).
337 /// - ZE: Zero-divide exception (also called #Z).
338 /// - OE: Overflow exception (also called #O).
339 /// - UE: Underflow exception (also called #U).
340 /// - PE: Precision exception (also called #P or inexact-result exception).
341 ///
342 /// The saved instruction pointer points to the instruction that caused the `#XF`.
343 ///
344 /// The vector number of the `#XF` exception is 19.
345 pub simd_floating_point: Entry<HandlerFunc>,
346
347 /// vector nr. 20
348 pub virtualization: Entry<HandlerFunc>,
349
350 /// A #CP exception is generated when shadow stacks are enabled and mismatch
351 /// scenarios are detected (possible error code cases below).
352 ///
353 /// The error code is the #CP error code, for each of the following situations:
354 /// - A RET (near) instruction encountered a return address mismatch.
355 /// - A RET (far) instruction encountered a return address mismatch.
356 /// - A RSTORSSP instruction encountered an invalid shadow stack restore token.
357 /// - A SETSSBY instruction encountered an invalid supervisor shadow stack token.
358 /// - A missing ENDBRANCH instruction if indirect branch tracking is enabled.
359 ///
360 /// vector nr. 21
361 pub cp_protection_exception: Entry<HandlerFuncWithErrCode>,
362
363 /// vector nr. 22-27
364 reserved_2: [Entry<HandlerFunc>; 6],
365
366 /// The Hypervisor Injection Exception (`#HV`) is injected by a hypervisor
367 /// as a doorbell to inform an `SEV-SNP` enabled guest running with the
368 /// `Restricted Injection` feature of events to be processed.
369 ///
370 /// `SEV-SNP` stands for the _"Secure Nested Paging"_ feature of the _"AMD
371 /// Secure Encrypted Virtualization"_ technology. The `Restricted
372 /// Injection` feature disables all hypervisor-based interrupt queuing
373 /// and event injection of all vectors except #HV.
374 ///
375 /// The `#HV` exception is a benign exception and can only be injected as
376 /// an exception and without an error code. `SEV-SNP` enabled guests are
377 /// expected to communicate with the hypervisor about events via a
378 /// software-managed para-virtualization interface.
379 ///
380 /// The vector number of the ``#HV`` exception is 28.
381 pub hv_injection_exception: Entry<HandlerFunc>,
382
383 /// The VMM Communication Exception (`#VC`) is always generated by hardware when an `SEV-ES`
384 /// enabled guest is running and an `NAE` event occurs.
385 ///
386 /// `SEV-ES` stands for the _"Encrypted State"_ feature of the _"AMD Secure Encrypted Virtualization"_
387 /// technology. `NAE` stands for an _"Non-Automatic Exit"_, which is an `VMEXIT` event that requires
388 /// hypervisor emulation. See
389 /// [this whitepaper](https://www.amd.com/system/files/TechDocs/Protecting%20VM%20Register%20State%20with%20SEV-ES.pdf)
390 /// for an overview of the `SEV-ES` feature.
391 ///
392 /// The `#VC` exception is a precise, contributory, fault-type exception utilizing exception vector 29.
393 /// This exception cannot be masked. The error code of the `#VC` exception is equal
394 /// to the `#VMEXIT` code of the event that caused the `NAE`.
395 ///
396 /// In response to a `#VC` exception, a typical flow would involve the guest handler inspecting the error
397 /// code to determine the cause of the exception and deciding what register state must be copied to the
398 /// `GHCB` (_"Guest Hypervisor Communication Block"_) for the event to be handled. The handler
399 /// should then execute the `VMGEXIT` instruction to
400 /// create an `AE` and invoke the hypervisor. After a later `VMRUN`, guest execution will resume after the
401 /// `VMGEXIT` instruction where the handler can view the results from the hypervisor and copy state from
402 /// the `GHCB` back to its internal state as needed.
403 ///
404 /// Note that it is inadvisable for the hypervisor to set the `VMCB` (_"Virtual Machine Control Block"_)
405 /// intercept bit for the `#VC` exception as
406 /// this would prevent proper handling of `NAE`s by the guest. Similarly, the hypervisor should avoid
407 /// setting intercept bits for events that would occur in the `#VC` handler (such as `IRET`).
408 ///
409 /// The vector number of the ``#VC`` exception is 29.
410 pub vmm_communication_exception: Entry<HandlerFuncWithErrCode>,
411
412 /// The Security Exception (`#SX`) signals security-sensitive events that occur while
413 /// executing the VMM, in the form of an exception so that the VMM may take appropriate
414 /// action. (A VMM would typically intercept comparable sensitive events in the guest.)
415 /// In the current implementation, the only use of the `#SX` is to redirect external INITs
416 /// into an exception so that the VMM may — among other possibilities.
417 ///
418 /// The only error code currently defined is 1, and indicates redirection of INIT has occurred.
419 ///
420 /// The vector number of the ``#SX`` exception is 30.
421 pub security_exception: Entry<HandlerFuncWithErrCode>,
422
423 /// vector nr. 31
424 reserved_3: Entry<HandlerFunc>,
425
426 /// User-defined interrupts can be initiated either by system logic or software. They occur
427 /// when:
428 ///
429 /// - System logic signals an external interrupt request to the processor. The signaling
430 /// mechanism and the method of communicating the interrupt vector to the processor are
431 /// implementation dependent.
432 /// - Software executes an `INTn` instruction. The `INTn` instruction operand provides
433 /// the interrupt vector number.
434 ///
435 /// Both methods can be used to initiate an interrupt into vectors 0 through 255. However,
436 /// because vectors 0 through 31 are defined or reserved by the AMD64 architecture,
437 /// software should not use vectors in this range for purposes other than their defined use.
438 ///
439 /// The saved instruction pointer depends on the interrupt source:
440 ///
441 /// - External interrupts are recognized on instruction boundaries. The saved instruction
442 /// pointer points to the instruction immediately following the boundary where the
443 /// external interrupt was recognized.
444 /// - If the interrupt occurs as a result of executing the INTn instruction, the saved
445 /// instruction pointer points to the instruction after the INTn.
446 interrupts: [Entry<HandlerFunc>; 256 - 32],
447}
448
449impl InterruptDescriptorTable {
450 /// Creates a new IDT filled with non-present entries.
451 #[inline]
452 #[rustversion::attr(since(1.61), const)]
453 pub fn new() -> InterruptDescriptorTable {
454 InterruptDescriptorTable {
455 divide_error: Entry::missing(),
456 debug: Entry::missing(),
457 non_maskable_interrupt: Entry::missing(),
458 breakpoint: Entry::missing(),
459 overflow: Entry::missing(),
460 bound_range_exceeded: Entry::missing(),
461 invalid_opcode: Entry::missing(),
462 device_not_available: Entry::missing(),
463 double_fault: Entry::missing(),
464 coprocessor_segment_overrun: Entry::missing(),
465 invalid_tss: Entry::missing(),
466 segment_not_present: Entry::missing(),
467 stack_segment_fault: Entry::missing(),
468 general_protection_fault: Entry::missing(),
469 page_fault: Entry::missing(),
470 reserved_1: Entry::missing(),
471 x87_floating_point: Entry::missing(),
472 alignment_check: Entry::missing(),
473 machine_check: Entry::missing(),
474 simd_floating_point: Entry::missing(),
475 virtualization: Entry::missing(),
476 cp_protection_exception: Entry::missing(),
477 reserved_2: [Entry::missing(); 6],
478 hv_injection_exception: Entry::missing(),
479 vmm_communication_exception: Entry::missing(),
480 security_exception: Entry::missing(),
481 reserved_3: Entry::missing(),
482 interrupts: [Entry::missing(); 256 - 32],
483 }
484 }
485
486 /// Resets all entries of this IDT in place.
487 #[inline]
488 pub fn reset(&mut self) {
489 *self = Self::new();
490 }
491
492 /// Loads the IDT in the CPU using the `lidt` command.
493 #[cfg(all(feature = "instructions", target_arch = "x86_64"))]
494 #[inline]
495 pub fn load(&'static self) {
496 unsafe { self.load_unsafe() }
497 }
498
499 /// Loads the IDT in the CPU using the `lidt` command.
500 ///
501 /// # Safety
502 ///
503 /// As long as it is the active IDT, you must ensure that:
504 ///
505 /// - `self` is never destroyed.
506 /// - `self` always stays at the same memory location. It is recommended to wrap it in
507 /// a `Box`.
508 ///
509 #[cfg(all(feature = "instructions", target_arch = "x86_64"))]
510 #[inline]
511 pub unsafe fn load_unsafe(&self) {
512 use crate::instructions::tables::lidt;
513 unsafe {
514 lidt(&self.pointer());
515 }
516 }
517
518 /// Creates the descriptor pointer for this table. This pointer can only be
519 /// safely used if the table is never modified or destroyed while in use.
520 #[cfg(all(feature = "instructions", target_arch = "x86_64"))]
521 fn pointer(&self) -> crate::structures::DescriptorTablePointer {
522 use core::mem::size_of;
523 crate::structures::DescriptorTablePointer {
524 base: VirtAddr::new(self as *const _ as u64),
525 limit: (size_of::<Self>() - 1) as u16,
526 }
527 }
528
529 /// Returns a normalized and ranged check slice range from a RangeBounds trait object.
530 ///
531 /// Panics if the entry is an exception.
532 fn condition_slice_bounds(&self, bounds: impl RangeBounds<u8>) -> (usize, usize) {
533 let lower_idx = match bounds.start_bound() {
534 Included(start) => usize::from(*start),
535 Excluded(start) => usize::from(*start) + 1,
536 Unbounded => 0,
537 };
538 let upper_idx = match bounds.end_bound() {
539 Included(end) => usize::from(*end) + 1,
540 Excluded(end) => usize::from(*end),
541 Unbounded => 256,
542 };
543
544 if lower_idx < 32 {
545 panic!("Cannot return slice from traps, faults, and exception handlers");
546 }
547 (lower_idx, upper_idx)
548 }
549
550 /// Returns slice of IDT entries with the specified range.
551 ///
552 /// Panics if the entry is an exception.
553 #[inline]
554 pub fn slice(&self, bounds: impl RangeBounds<u8>) -> &[Entry<HandlerFunc>] {
555 let (lower_idx, upper_idx) = self.condition_slice_bounds(bounds);
556 &self.interrupts[(lower_idx - 32)..(upper_idx - 32)]
557 }
558
559 /// Returns a mutable slice of IDT entries with the specified range.
560 ///
561 /// Panics if the entry is an exception.
562 #[inline]
563 pub fn slice_mut(&mut self, bounds: impl RangeBounds<u8>) -> &mut [Entry<HandlerFunc>] {
564 let (lower_idx, upper_idx) = self.condition_slice_bounds(bounds);
565 &mut self.interrupts[(lower_idx - 32)..(upper_idx - 32)]
566 }
567}
568
569impl Default for InterruptDescriptorTable {
570 #[inline]
571 fn default() -> Self {
572 Self::new()
573 }
574}
575
576impl Index<u8> for InterruptDescriptorTable {
577 type Output = Entry<HandlerFunc>;
578
579 /// Returns the IDT entry with the specified index.
580 ///
581 /// Panics if the entry is an exception that pushes an error code (use the struct fields for accessing these entries).
582 #[inline]
583 fn index(&self, index: u8) -> &Self::Output {
584 match index {
585 0 => &self.divide_error,
586 1 => &self.debug,
587 2 => &self.non_maskable_interrupt,
588 3 => &self.breakpoint,
589 4 => &self.overflow,
590 5 => &self.bound_range_exceeded,
591 6 => &self.invalid_opcode,
592 7 => &self.device_not_available,
593 9 => &self.coprocessor_segment_overrun,
594 16 => &self.x87_floating_point,
595 19 => &self.simd_floating_point,
596 20 => &self.virtualization,
597 28 => &self.hv_injection_exception,
598 i @ 32..=255 => &self.interrupts[usize::from(i) - 32],
599 i @ 15 | i @ 31 | i @ 22..=27 => panic!("entry {} is reserved", i),
600 i @ 8 | i @ 10..=14 | i @ 17 | i @ 21 | i @ 29 | i @ 30 => {
601 panic!("entry {} is an exception with error code", i)
602 }
603 i @ 18 => panic!("entry {} is an diverging exception (must not return)", i),
604 }
605 }
606}
607
608impl IndexMut<u8> for InterruptDescriptorTable {
609 /// Returns a mutable reference to the IDT entry with the specified index.
610 ///
611 /// Panics if the entry is an exception that pushes an error code (use the struct fields for accessing these entries).
612 #[inline]
613 fn index_mut(&mut self, index: u8) -> &mut Self::Output {
614 match index {
615 0 => &mut self.divide_error,
616 1 => &mut self.debug,
617 2 => &mut self.non_maskable_interrupt,
618 3 => &mut self.breakpoint,
619 4 => &mut self.overflow,
620 5 => &mut self.bound_range_exceeded,
621 6 => &mut self.invalid_opcode,
622 7 => &mut self.device_not_available,
623 9 => &mut self.coprocessor_segment_overrun,
624 16 => &mut self.x87_floating_point,
625 19 => &mut self.simd_floating_point,
626 20 => &mut self.virtualization,
627 28 => &mut self.hv_injection_exception,
628 i @ 32..=255 => &mut self.interrupts[usize::from(i) - 32],
629 i @ 15 | i @ 31 | i @ 22..=27 => panic!("entry {} is reserved", i),
630 i @ 8 | i @ 10..=14 | i @ 17 | i @ 21 | i @ 29 | i @ 30 => {
631 panic!("entry {} is an exception with error code", i)
632 }
633 i @ 18 => panic!("entry {} is an diverging exception (must not return)", i),
634 }
635 }
636}
637
638macro_rules! impl_index_for_idt {
639 ($ty:ty) => {
640 impl Index<$ty> for InterruptDescriptorTable {
641 type Output = [Entry<HandlerFunc>];
642
643 /// Returns the IDT entry with the specified index.
644 ///
645 /// Panics if index is outside the IDT (i.e. greater than 255) or if the entry is an
646 /// exception that pushes an error code (use the struct fields for accessing these entries).
647 #[inline]
648 fn index(&self, index: $ty) -> &Self::Output {
649 self.slice(index)
650 }
651 }
652
653 impl IndexMut<$ty> for InterruptDescriptorTable {
654 /// Returns a mutable reference to the IDT entry with the specified index.
655 ///
656 /// Panics if the entry is an exception that pushes an error code (use the struct fields for accessing these entries).
657 #[inline]
658 fn index_mut(&mut self, index: $ty) -> &mut Self::Output {
659 self.slice_mut(index)
660 }
661 }
662 };
663}
664
665// this list was stolen from the list of implementors in https://doc.rust-lang.org/core/ops/trait.RangeBounds.html
666impl_index_for_idt!((Bound<&u8>, Bound<&u8>));
667impl_index_for_idt!((Bound<u8>, Bound<u8>));
668impl_index_for_idt!(Range<&u8>);
669impl_index_for_idt!(Range<u8>);
670impl_index_for_idt!(RangeFrom<&u8>);
671impl_index_for_idt!(RangeFrom<u8>);
672impl_index_for_idt!(RangeInclusive<&u8>);
673impl_index_for_idt!(RangeInclusive<u8>);
674impl_index_for_idt!(RangeTo<u8>);
675impl_index_for_idt!(RangeTo<&u8>);
676impl_index_for_idt!(RangeToInclusive<&u8>);
677impl_index_for_idt!(RangeToInclusive<u8>);
678impl_index_for_idt!(RangeFull);
679
680/// An Interrupt Descriptor Table entry.
681///
682/// The generic parameter is some [`HandlerFuncType`], depending on the interrupt vector.
683#[derive(Clone, Copy)]
684#[repr(C)]
685pub struct Entry<F> {
686 pointer_low: u16,
687 options: EntryOptions,
688 pointer_middle: u16,
689 pointer_high: u32,
690 reserved: u32,
691 phantom: PhantomData<F>,
692}
693
694impl<T> fmt::Debug for Entry<T> {
695 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
696 f.debug_struct("Entry")
697 .field("handler_addr", &format_args!("{:#x}", self.handler_addr()))
698 .field("options", &self.options)
699 .finish()
700 }
701}
702
703impl<T> PartialEq for Entry<T> {
704 fn eq(&self, other: &Self) -> bool {
705 self.pointer_low == other.pointer_low
706 && self.options == other.options
707 && self.pointer_middle == other.pointer_middle
708 && self.pointer_high == other.pointer_high
709 && self.reserved == other.reserved
710 }
711}
712
713/// A handler function for an interrupt or an exception without error code.
714///
715/// This type alias is only usable with the `abi_x86_interrupt` feature enabled.
716#[cfg(all(
717 any(target_arch = "x86", target_arch = "x86_64"),
718 feature = "abi_x86_interrupt"
719))]
720pub type HandlerFunc = extern "x86-interrupt" fn(InterruptStackFrame);
721/// This type is not usable without the `abi_x86_interrupt` feature.
722#[cfg(not(all(
723 any(target_arch = "x86", target_arch = "x86_64"),
724 feature = "abi_x86_interrupt"
725)))]
726#[derive(Copy, Clone, Debug)]
727pub struct HandlerFunc(());
728
729/// A handler function for an exception that pushes an error code.
730///
731/// This type alias is only usable with the `abi_x86_interrupt` feature enabled.
732#[cfg(all(
733 any(target_arch = "x86", target_arch = "x86_64"),
734 feature = "abi_x86_interrupt"
735))]
736pub type HandlerFuncWithErrCode = extern "x86-interrupt" fn(InterruptStackFrame, error_code: u64);
737/// This type is not usable without the `abi_x86_interrupt` feature.
738#[cfg(not(all(
739 any(target_arch = "x86", target_arch = "x86_64"),
740 feature = "abi_x86_interrupt"
741)))]
742#[derive(Copy, Clone, Debug)]
743pub struct HandlerFuncWithErrCode(());
744
745/// A page fault handler function that pushes a page fault error code.
746///
747/// This type alias is only usable with the `abi_x86_interrupt` feature enabled.
748#[cfg(all(
749 any(target_arch = "x86", target_arch = "x86_64"),
750 feature = "abi_x86_interrupt"
751))]
752pub type PageFaultHandlerFunc =
753 extern "x86-interrupt" fn(InterruptStackFrame, error_code: PageFaultErrorCode);
754/// This type is not usable without the `abi_x86_interrupt` feature.
755#[cfg(not(all(
756 any(target_arch = "x86", target_arch = "x86_64"),
757 feature = "abi_x86_interrupt"
758)))]
759#[derive(Copy, Clone, Debug)]
760pub struct PageFaultHandlerFunc(());
761
762/// A handler function that must not return, e.g. for a machine check exception.
763///
764/// This type alias is only usable with the `abi_x86_interrupt` feature enabled.
765#[cfg(all(
766 any(target_arch = "x86", target_arch = "x86_64"),
767 feature = "abi_x86_interrupt"
768))]
769pub type DivergingHandlerFunc = extern "x86-interrupt" fn(InterruptStackFrame) -> !;
770/// This type is not usable without the `abi_x86_interrupt` feature.
771#[cfg(not(all(
772 any(target_arch = "x86", target_arch = "x86_64"),
773 feature = "abi_x86_interrupt"
774)))]
775#[derive(Copy, Clone, Debug)]
776pub struct DivergingHandlerFunc(());
777
778/// A handler function with an error code that must not return, e.g. for a double fault exception.
779///
780/// This type alias is only usable with the `abi_x86_interrupt` feature enabled.
781#[cfg(all(
782 any(target_arch = "x86", target_arch = "x86_64"),
783 feature = "abi_x86_interrupt"
784))]
785pub type DivergingHandlerFuncWithErrCode =
786 extern "x86-interrupt" fn(InterruptStackFrame, error_code: u64) -> !;
787/// This type is not usable without the `abi_x86_interrupt` feature.
788#[cfg(not(all(
789 any(target_arch = "x86", target_arch = "x86_64"),
790 feature = "abi_x86_interrupt"
791)))]
792#[derive(Copy, Clone, Debug)]
793pub struct DivergingHandlerFuncWithErrCode(());
794
795/// A general handler function for an interrupt or an exception with the interrupt/exceptions's index and an optional error code.
796pub type GeneralHandlerFunc = fn(InterruptStackFrame, index: u8, error_code: Option<u64>);
797
798impl<F> Entry<F> {
799 /// Creates a non-present IDT entry (but sets the must-be-one bits).
800 #[inline]
801 pub const fn missing() -> Self {
802 Entry {
803 pointer_low: 0,
804 pointer_middle: 0,
805 pointer_high: 0,
806 options: EntryOptions::minimal(),
807 reserved: 0,
808 phantom: PhantomData,
809 }
810 }
811
812 /// Sets the handler address for the IDT entry and sets the following defaults:
813 /// - The code selector is the code segment currently active in the CPU
814 /// - The present bit is set
815 /// - Interrupts are disabled on handler invocation
816 /// - The privilege level (DPL) is [`PrivilegeLevel::Ring0`]
817 /// - No IST is configured (existing stack will be used)
818 ///
819 /// The function returns a mutable reference to the entry's options that allows
820 /// further customization.
821 ///
822 /// # Safety
823 ///
824 /// The caller must ensure that `addr` is the address of a valid interrupt handler function,
825 /// and the signature of such a function is correct for the entry type.
826 #[cfg(all(feature = "instructions", target_arch = "x86_64"))]
827 #[inline]
828 pub unsafe fn set_handler_addr(&mut self, addr: VirtAddr) -> &mut EntryOptions {
829 use crate::instructions::segmentation::{Segment, CS};
830
831 let addr = addr.as_u64();
832 self.pointer_low = addr as u16;
833 self.pointer_middle = (addr >> 16) as u16;
834 self.pointer_high = (addr >> 32) as u32;
835
836 self.options = EntryOptions::minimal();
837 // SAFETY: The current CS is a valid, long-mode code segment.
838 unsafe { self.options.set_code_selector(CS::get_reg()) };
839 self.options.set_present(true);
840 &mut self.options
841 }
842
843 /// Returns the virtual address of this IDT entry's handler function.
844 #[inline]
845 pub fn handler_addr(&self) -> VirtAddr {
846 let addr = self.pointer_low as u64
847 | (self.pointer_middle as u64) << 16
848 | (self.pointer_high as u64) << 32;
849 // addr is a valid VirtAddr, as the pointer members are either all zero,
850 // or have been set by set_handler_addr (which takes a VirtAddr).
851 VirtAddr::new_truncate(addr)
852 }
853}
854
855#[cfg(all(feature = "instructions", target_arch = "x86_64"))]
856impl<F: HandlerFuncType> Entry<F> {
857 /// Sets the handler function for the IDT entry and sets the following defaults:
858 /// - The code selector is the code segment currently active in the CPU
859 /// - The present bit is set
860 /// - Interrupts are disabled on handler invocation
861 /// - The privilege level (DPL) is [`PrivilegeLevel::Ring0`]
862 /// - No IST is configured (existing stack will be used)
863 ///
864 /// The function returns a mutable reference to the entry's options that allows
865 /// further customization.
866 ///
867 /// This method is only usable with the `abi_x86_interrupt` feature enabled. Without it, the
868 /// unsafe [`Entry::set_handler_addr`] method has to be used instead.
869 #[inline]
870 pub fn set_handler_fn(&mut self, handler: F) -> &mut EntryOptions {
871 unsafe { self.set_handler_addr(handler.to_virt_addr()) }
872 }
873}
874
875/// A common trait for all handler functions usable in [`Entry`].
876///
877/// # Safety
878///
879/// Implementors have to ensure that `to_virt_addr` returns a valid address.
880pub unsafe trait HandlerFuncType {
881 /// Get the virtual address of the handler function.
882 fn to_virt_addr(self) -> VirtAddr;
883}
884
885macro_rules! impl_handler_func_type {
886 ($f:ty) => {
887 #[cfg(all(
888 any(target_arch = "x86", target_arch = "x86_64"),
889 feature = "abi_x86_interrupt"
890 ))]
891 unsafe impl HandlerFuncType for $f {
892 #[inline]
893 fn to_virt_addr(self) -> VirtAddr {
894 // Casting a function pointer to u64 is fine, if the pointer
895 // width doesn't exeed 64 bits.
896 #[cfg_attr(
897 any(target_pointer_width = "32", target_pointer_width = "64"),
898 allow(clippy::fn_to_numeric_cast)
899 )]
900 VirtAddr::new(self as u64)
901 }
902 }
903 };
904}
905
906impl_handler_func_type!(HandlerFunc);
907impl_handler_func_type!(HandlerFuncWithErrCode);
908impl_handler_func_type!(PageFaultHandlerFunc);
909impl_handler_func_type!(DivergingHandlerFunc);
910impl_handler_func_type!(DivergingHandlerFuncWithErrCode);
911
912/// Represents the 4 non-offset bytes of an IDT entry.
913#[repr(C)]
914#[derive(Clone, Copy, PartialEq)]
915pub struct EntryOptions {
916 cs: SegmentSelector,
917 bits: u16,
918}
919
920impl fmt::Debug for EntryOptions {
921 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
922 f.debug_struct("EntryOptions")
923 .field("code_selector", &self.cs)
924 .field("stack_index", &self.stack_index())
925 .field("type", &format_args!("{:#04b}", self.bits.get_bits(8..12)))
926 .field("privilege_level", &self.privilege_level())
927 .field("present", &self.present())
928 .finish()
929 }
930}
931
932impl EntryOptions {
933 /// Creates a minimal options field with all the must-be-one bits set. This
934 /// means the CS selector, IST, and DPL field are all 0.
935 #[inline]
936 const fn minimal() -> Self {
937 EntryOptions {
938 cs: SegmentSelector(0),
939 bits: 0b1110_0000_0000, // Default to a 64-bit Interrupt Gate
940 }
941 }
942
943 /// Set the code segment that will be used by this interrupt.
944 ///
945 /// ## Safety
946 /// This function is unsafe because the caller must ensure that the passed
947 /// segment selector points to a valid, long-mode code segment.
948 pub unsafe fn set_code_selector(&mut self, cs: SegmentSelector) -> &mut Self {
949 self.cs = cs;
950 self
951 }
952
953 /// Set or reset the preset bit.
954 #[inline]
955 pub fn set_present(&mut self, present: bool) -> &mut Self {
956 self.bits.set_bit(15, present);
957 self
958 }
959
960 fn present(&self) -> bool {
961 self.bits.get_bit(15)
962 }
963
964 /// Let the CPU disable hardware interrupts when the handler is invoked. By default,
965 /// interrupts are disabled on handler invocation.
966 #[inline]
967 pub fn disable_interrupts(&mut self, disable: bool) -> &mut Self {
968 self.bits.set_bit(8, !disable);
969 self
970 }
971
972 /// Set the required privilege level (DPL) for invoking the handler. The DPL can be 0, 1, 2,
973 /// or 3, the default is 0. If CPL < DPL, a general protection fault occurs.
974 #[inline]
975 pub fn set_privilege_level(&mut self, dpl: PrivilegeLevel) -> &mut Self {
976 self.bits.set_bits(13..15, dpl as u16);
977 self
978 }
979
980 fn privilege_level(&self) -> PrivilegeLevel {
981 PrivilegeLevel::from_u16(self.bits.get_bits(13..15))
982 }
983
984 /// Assigns a Interrupt Stack Table (IST) stack to this handler. The CPU will then always
985 /// switch to the specified stack before the handler is invoked. This allows kernels to
986 /// recover from corrupt stack pointers (e.g., on kernel stack overflow).
987 ///
988 /// An IST stack is specified by an IST index between 0 and 6 (inclusive). Using the same
989 /// stack for multiple interrupts can be dangerous when nested interrupts are possible.
990 ///
991 /// This function panics if the index is not in the range 0..7.
992 ///
993 /// ## Safety
994 ///
995 /// This function is unsafe because the caller must ensure that the passed stack index is
996 /// valid and not used by other interrupts. Otherwise, memory safety violations are possible.
997 #[inline]
998 pub unsafe fn set_stack_index(&mut self, index: u16) -> &mut Self {
999 // The hardware IST index starts at 1, but our software IST index
1000 // starts at 0. Therefore we need to add 1 here.
1001 self.bits.set_bits(0..3, index + 1);
1002 self
1003 }
1004
1005 fn stack_index(&self) -> u16 {
1006 self.bits.get_bits(0..3) - 1
1007 }
1008}
1009
1010/// Wrapper type for the interrupt stack frame pushed by the CPU.
1011///
1012/// This type derefs to an [`InterruptStackFrameValue`], which allows reading the actual values.
1013///
1014/// This wrapper type ensures that no accidental modification of the interrupt stack frame
1015/// occurs, which can cause undefined behavior (see the [`as_mut`](InterruptStackFrame::as_mut)
1016/// method for more information).
1017#[repr(transparent)]
1018pub struct InterruptStackFrame(InterruptStackFrameValue);
1019
1020impl InterruptStackFrame {
1021 /// Creates a new interrupt stack frame with the given values.
1022 #[inline]
1023 pub fn new(
1024 instruction_pointer: VirtAddr,
1025 code_segment: SegmentSelector,
1026 cpu_flags: RFlags,
1027 stack_pointer: VirtAddr,
1028 stack_segment: SegmentSelector,
1029 ) -> Self {
1030 Self(InterruptStackFrameValue::new(
1031 instruction_pointer,
1032 code_segment,
1033 cpu_flags,
1034 stack_pointer,
1035 stack_segment,
1036 ))
1037 }
1038
1039 /// Gives mutable access to the contents of the interrupt stack frame.
1040 ///
1041 /// The `Volatile` wrapper is used because LLVM optimizations remove non-volatile
1042 /// modifications of the interrupt stack frame.
1043 ///
1044 /// ## Safety
1045 ///
1046 /// This function is unsafe since modifying the content of the interrupt stack frame
1047 /// can easily lead to undefined behavior. For example, by writing an invalid value to
1048 /// the instruction pointer field, the CPU can jump to arbitrary code at the end of the
1049 /// interrupt.
1050 ///
1051 /// Also, it is not fully clear yet whether modifications of the interrupt stack frame are
1052 /// officially supported by LLVM's x86 interrupt calling convention.
1053 #[inline]
1054 pub unsafe fn as_mut(&mut self) -> Volatile<&mut InterruptStackFrameValue> {
1055 Volatile::new(&mut self.0)
1056 }
1057}
1058
1059impl Deref for InterruptStackFrame {
1060 type Target = InterruptStackFrameValue;
1061
1062 #[inline]
1063 fn deref(&self) -> &Self::Target {
1064 &self.0
1065 }
1066}
1067
1068impl fmt::Debug for InterruptStackFrame {
1069 #[inline]
1070 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1071 self.0.fmt(f)
1072 }
1073}
1074
1075/// Represents the interrupt stack frame pushed by the CPU on interrupt or exception entry.
1076#[derive(Clone, Copy)]
1077#[repr(C)]
1078pub struct InterruptStackFrameValue {
1079 /// This value points to the instruction that should be executed when the interrupt
1080 /// handler returns. For most interrupts, this value points to the instruction immediately
1081 /// following the last executed instruction. However, for some exceptions (e.g., page faults),
1082 /// this value points to the faulting instruction, so that the instruction is restarted on
1083 /// return. See the documentation of the [`InterruptDescriptorTable`] fields for more details.
1084 pub instruction_pointer: VirtAddr,
1085 /// The code segment selector at the time of the interrupt.
1086 pub code_segment: SegmentSelector,
1087 _reserved1: [u8; 6],
1088 /// The flags register before the interrupt handler was invoked.
1089 pub cpu_flags: RFlags,
1090 /// The stack pointer at the time of the interrupt.
1091 pub stack_pointer: VirtAddr,
1092 /// The stack segment descriptor at the time of the interrupt (often zero in 64-bit mode).
1093 pub stack_segment: SegmentSelector,
1094 _reserved2: [u8; 6],
1095}
1096
1097impl InterruptStackFrameValue {
1098 /// Creates a new interrupt stack frame with the given values.
1099 #[inline]
1100 pub fn new(
1101 instruction_pointer: VirtAddr,
1102 code_segment: SegmentSelector,
1103 cpu_flags: RFlags,
1104 stack_pointer: VirtAddr,
1105 stack_segment: SegmentSelector,
1106 ) -> Self {
1107 Self {
1108 instruction_pointer,
1109 code_segment,
1110 _reserved1: Default::default(),
1111 cpu_flags,
1112 stack_pointer,
1113 stack_segment,
1114 _reserved2: Default::default(),
1115 }
1116 }
1117
1118 /// Call the `iretq` (interrupt return) instruction.
1119 ///
1120 /// This function doesn't have to be called in an interrupt handler.
1121 /// By manually construction a new [`InterruptStackFrameValue`] it's possible to transition
1122 /// from a higher privilege level to a lower one.
1123 ///
1124 /// ## Safety
1125 ///
1126 /// Calling `iretq` is unsafe because setting the instruction pointer, stack pointer, RFlags,
1127 /// CS and SS register can all cause undefined behaviour when done incorrectly.
1128 ///
1129 #[inline(always)]
1130 #[cfg(all(feature = "instructions", target_arch = "x86_64"))]
1131 pub unsafe fn iretq(&self) -> ! {
1132 unsafe {
1133 core::arch::asm!(
1134 "push {stack_segment:r}",
1135 "push {new_stack_pointer}",
1136 "push {rflags}",
1137 "push {code_segment:r}",
1138 "push {new_instruction_pointer}",
1139 "iretq",
1140 rflags = in(reg) self.cpu_flags.bits(),
1141 new_instruction_pointer = in(reg) self.instruction_pointer.as_u64(),
1142 new_stack_pointer = in(reg) self.stack_pointer.as_u64(),
1143 code_segment = in(reg) self.code_segment.0,
1144 stack_segment = in(reg) self.stack_segment.0,
1145 options(noreturn)
1146 )
1147 }
1148 }
1149}
1150
1151impl fmt::Debug for InterruptStackFrameValue {
1152 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1153 let mut s = f.debug_struct("InterruptStackFrame");
1154 s.field("instruction_pointer", &self.instruction_pointer);
1155 s.field("code_segment", &self.code_segment);
1156 s.field("cpu_flags", &self.cpu_flags);
1157 s.field("stack_pointer", &self.stack_pointer);
1158 s.field("stack_segment", &self.stack_segment);
1159 s.finish()
1160 }
1161}
1162
1163bitflags! {
1164 /// Describes an page fault error code.
1165 ///
1166 /// This structure is defined by the following manual sections:
1167 /// * AMD Volume 2: 8.4.2
1168 /// * Intel Volume 3A: 4.7
1169 #[repr(transparent)]
1170 #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
1171 pub struct PageFaultErrorCode: u64 {
1172 /// If this flag is set, the page fault was caused by a page-protection violation,
1173 /// else the page fault was caused by a not-present page.
1174 const PROTECTION_VIOLATION = 1;
1175
1176 /// If this flag is set, the memory access that caused the page fault was a write.
1177 /// Else the access that caused the page fault is a memory read. This bit does not
1178 /// necessarily indicate the cause of the page fault was a read or write violation.
1179 const CAUSED_BY_WRITE = 1 << 1;
1180
1181 /// If this flag is set, an access in user mode (CPL=3) caused the page fault. Else
1182 /// an access in supervisor mode (CPL=0, 1, or 2) caused the page fault. This bit
1183 /// does not necessarily indicate the cause of the page fault was a privilege violation.
1184 const USER_MODE = 1 << 2;
1185
1186 /// If this flag is set, the page fault is a result of the processor reading a 1 from
1187 /// a reserved field within a page-translation-table entry.
1188 const MALFORMED_TABLE = 1 << 3;
1189
1190 /// If this flag is set, it indicates that the access that caused the page fault was an
1191 /// instruction fetch.
1192 const INSTRUCTION_FETCH = 1 << 4;
1193
1194 /// If this flag is set, it indicates that the page fault was caused by a protection key.
1195 const PROTECTION_KEY = 1 << 5;
1196
1197 /// If this flag is set, it indicates that the page fault was caused by a shadow stack
1198 /// access.
1199 const SHADOW_STACK = 1 << 6;
1200
1201 /// If this flag is set, it indicates that the page fault was caused by SGX access-control
1202 /// requirements (Intel-only).
1203 const SGX = 1 << 15;
1204
1205 /// If this flag is set, it indicates that the page fault is a result of the processor
1206 /// encountering an RMP violation (AMD-only).
1207 const RMP = 1 << 31;
1208 }
1209}
1210
1211/// Describes an error code referencing a segment selector.
1212#[derive(Clone, Copy, PartialEq, Eq, Hash)]
1213#[repr(transparent)]
1214pub struct SelectorErrorCode {
1215 flags: u64,
1216}
1217
1218impl SelectorErrorCode {
1219 /// Create a SelectorErrorCode. Returns None is any of the reserved bits (16-64) are set.
1220 pub const fn new(value: u64) -> Option<Self> {
1221 if value > u16::MAX as u64 {
1222 None
1223 } else {
1224 Some(Self { flags: value })
1225 }
1226 }
1227
1228 /// Create a new SelectorErrorCode dropping any reserved bits (16-64).
1229 pub const fn new_truncate(value: u64) -> Self {
1230 Self {
1231 flags: (value as u16) as u64,
1232 }
1233 }
1234
1235 /// If true, indicates that the exception occurred during delivery of an event
1236 /// external to the program, such as an interrupt or an earlier exception.
1237 pub fn external(&self) -> bool {
1238 self.flags.get_bit(0)
1239 }
1240
1241 /// The descriptor table this error code refers to.
1242 pub fn descriptor_table(&self) -> DescriptorTable {
1243 match self.flags.get_bits(1..3) {
1244 0b00 => DescriptorTable::Gdt,
1245 0b01 => DescriptorTable::Idt,
1246 0b10 => DescriptorTable::Ldt,
1247 0b11 => DescriptorTable::Idt,
1248 _ => unreachable!(),
1249 }
1250 }
1251
1252 /// The index of the selector which caused the error.
1253 pub fn index(&self) -> u64 {
1254 self.flags.get_bits(3..16)
1255 }
1256
1257 /// If true, the #SS or #GP has returned zero as opposed to a SelectorErrorCode.
1258 pub fn is_null(&self) -> bool {
1259 self.flags == 0
1260 }
1261}
1262
1263impl fmt::Debug for SelectorErrorCode {
1264 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1265 let mut s = f.debug_struct("Selector Error");
1266 s.field("external", &self.external());
1267 s.field("descriptor table", &self.descriptor_table());
1268 s.field("index", &self.index());
1269 s.finish()
1270 }
1271}
1272
1273/// The possible descriptor table values.
1274///
1275/// Used by the [`SelectorErrorCode`] to indicate which table caused the error.
1276#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1277pub enum DescriptorTable {
1278 /// Global Descriptor Table.
1279 Gdt,
1280 /// Interrupt Descriptor Table.
1281 Idt,
1282 /// Logical Descriptor Table.
1283 Ldt,
1284}
1285
1286/// This structure defines the CPU-internal exception vector numbers.
1287///
1288/// The values are defined by the following manual sections:
1289/// * AMD Volume 2: 8.2
1290/// * Intel Volume 3A: 6.3.1
1291#[repr(u8)]
1292#[non_exhaustive]
1293#[derive(Copy, Clone, Debug, PartialEq)]
1294pub enum ExceptionVector {
1295 /// Error during Division
1296 Division = 0x00,
1297
1298 /// Debug
1299 Debug = 0x01,
1300
1301 /// Non-Maskable Interrupt
1302 NonMaskableInterrupt = 0x02,
1303
1304 /// Breakpoint
1305 Breakpoint = 0x03,
1306
1307 /// Overflow
1308 Overflow = 0x04,
1309
1310 /// Bound Range Exceeded
1311 BoundRange = 0x05,
1312
1313 /// Invalid Opcode
1314 InvalidOpcode = 0x06,
1315
1316 /// Device Not Available
1317 DeviceNotAvailable = 0x07,
1318
1319 /// Double Fault
1320 Double = 0x08,
1321
1322 /// Invalid TSS
1323 InvalidTss = 0x0A,
1324
1325 /// Segment Not Present
1326 SegmentNotPresent = 0x0B,
1327
1328 /// Stack Fault
1329 Stack = 0x0C,
1330
1331 /// General Protection Fault
1332 GeneralProtection = 0x0D,
1333
1334 /// Page Fault
1335 Page = 0x0E,
1336
1337 /// x87 Floating-Point Exception
1338 X87FloatingPoint = 0x10,
1339
1340 /// Alignment Check
1341 AlignmentCheck = 0x11,
1342
1343 /// Machine Check
1344 MachineCheck = 0x12,
1345
1346 /// SIMD Floating-Point Exception
1347 SimdFloatingPoint = 0x13,
1348
1349 /// Virtualization Exception (Intel-only)
1350 Virtualization = 0x14,
1351
1352 /// Control Protection Exception
1353 ControlProtection = 0x15,
1354
1355 /// Hypervisor Injection (AMD-only)
1356 HypervisorInjection = 0x1C,
1357
1358 /// VMM Communication (AMD-only)
1359 VmmCommunication = 0x1D,
1360
1361 /// Security Exception
1362 Security = 0x1E,
1363}
1364
1365/// Exception vector number is invalid
1366#[derive(Debug)]
1367pub struct InvalidExceptionVectorNumber(u8);
1368
1369impl fmt::Display for InvalidExceptionVectorNumber {
1370 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1371 write!(f, "{} is not a valid exception vector", self.0)
1372 }
1373}
1374
1375impl TryFrom<u8> for ExceptionVector {
1376 type Error = InvalidExceptionVectorNumber;
1377
1378 /// Tries to convert the exception vector number to [`ExceptionVector`]
1379 ///
1380 /// Fails if exception vector number is Coprocessor Segment Overrun, reserved or not exception vector number
1381 fn try_from(exception_vector_number: u8) -> Result<Self, Self::Error> {
1382 match exception_vector_number {
1383 0x00 => Ok(Self::Division),
1384 0x01 => Ok(Self::Debug),
1385 0x02 => Ok(Self::NonMaskableInterrupt),
1386 0x03 => Ok(Self::Breakpoint),
1387 0x04 => Ok(Self::Overflow),
1388 0x05 => Ok(Self::BoundRange),
1389 0x06 => Ok(Self::InvalidOpcode),
1390 0x07 => Ok(Self::DeviceNotAvailable),
1391 0x08 => Ok(Self::Double),
1392 0x0A => Ok(Self::InvalidTss),
1393 0x0B => Ok(Self::SegmentNotPresent),
1394 0x0C => Ok(Self::Stack),
1395 0x0D => Ok(Self::GeneralProtection),
1396 0x0E => Ok(Self::Page),
1397 0x10 => Ok(Self::X87FloatingPoint),
1398 0x11 => Ok(Self::AlignmentCheck),
1399 0x12 => Ok(Self::MachineCheck),
1400 0x13 => Ok(Self::SimdFloatingPoint),
1401 0x14 => Ok(Self::Virtualization),
1402 0x15 => Ok(Self::ControlProtection),
1403 0x1C => Ok(Self::HypervisorInjection),
1404 0x1D => Ok(Self::VmmCommunication),
1405 0x1E => Ok(Self::Security),
1406 _ => Err(InvalidExceptionVectorNumber(exception_vector_number)),
1407 }
1408 }
1409}
1410
1411#[cfg(all(
1412 feature = "instructions",
1413 feature = "abi_x86_interrupt",
1414 target_arch = "x86_64"
1415))]
1416#[macro_export]
1417/// Set a general handler in an [`InterruptDescriptorTable`].
1418/// ```
1419/// #![feature(abi_x86_interrupt)]
1420/// use x86_64::set_general_handler;
1421/// use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
1422///
1423/// let mut idt = InterruptDescriptorTable::new();
1424/// fn my_general_handler(
1425/// stack_frame: InterruptStackFrame,
1426/// index: u8,
1427/// error_code: Option<u64>,
1428/// ) {
1429/// todo!("handle irq {}", index)
1430/// }
1431///
1432/// // set only one entry
1433/// # // there seems to be a bug in LLVM that causes rustc to crash on windows when compiling this test:
1434/// # // https://github.com/rust-osdev/x86_64/pull/285#issuecomment-962642984
1435/// # #[cfg(not(windows))]
1436/// set_general_handler!(&mut idt, my_general_handler, 14);
1437///
1438/// // set a range of entries
1439/// # // there seems to be a bug in LLVM that causes rustc to crash on windows when compiling this test:
1440/// # // https://github.com/rust-osdev/x86_64/pull/285#issuecomment-962642984
1441/// # #[cfg(not(windows))]
1442/// set_general_handler!(&mut idt, my_general_handler, 32..64);
1443///
1444/// // set all entries
1445/// # // there seems to be a bug in LLVM that causes rustc to crash on windows when compiling this test:
1446/// # // https://github.com/rust-osdev/x86_64/pull/285#issuecomment-962642984
1447/// # #[cfg(not(windows))]
1448/// set_general_handler!(&mut idt, my_general_handler);
1449/// ```
1450macro_rules! set_general_handler {
1451 ($idt:expr, $handler:ident) => {
1452 $crate::set_general_handler!($idt, $handler, 0..=255);
1453 };
1454 ($idt:expr, $handler:ident, $idx:literal) => {
1455 $crate::set_general_handler!($idt, $handler, $idx..=$idx);
1456 };
1457 ($idt:expr, $handler:ident, $range:expr) => {{
1458 /// This constant is used to avoid spamming the same compilation error ~200 times
1459 /// when the handler's signature is wrong.
1460 /// If we just passed `$handler` to `set_general_handler_recursive_bits`
1461 /// an error would be reported for every interrupt handler that tried to call it.
1462 /// With `GENERAL_HANDLER` the error is only reported once for this constant.
1463 const GENERAL_HANDLER: $crate::structures::idt::GeneralHandlerFunc = $handler;
1464
1465 {
1466 fn set_general_handler(
1467 idt: &mut $crate::structures::idt::InterruptDescriptorTable,
1468 range: impl ::core::ops::RangeBounds<u8>,
1469 ) {
1470 $crate::set_general_handler_recursive_bits!(idt, GENERAL_HANDLER, range);
1471 }
1472 set_general_handler($idt, $range);
1473 }
1474 }};
1475}
1476
1477#[cfg(all(
1478 feature = "instructions",
1479 feature = "abi_x86_interrupt",
1480 target_arch = "x86_64"
1481))]
1482#[macro_export]
1483#[doc(hidden)]
1484/// We can't loop in macros, but we can use recursion.
1485/// This macro recursively adds one more bit to it's arguments until we have 8 bits so that we can call set_general_handler_entry.
1486macro_rules! set_general_handler_recursive_bits {
1487 // if we have 8 all bits, construct the index from the bits, check if the entry is in range and invoke the macro that sets the handler
1488 ($idt:expr, $handler:ident, $range:expr, $bit7:tt, $bit6:tt, $bit5:tt, $bit4:tt, $bit3:tt, $bit2:tt, $bit1:tt, $bit0:tt) => {{
1489 const IDX: u8 = $bit0 | ($bit1 << 1) | ($bit2 << 2) | ($bit3 << 3) | ($bit4 << 4) | ($bit5 << 5) | ($bit6 << 6) | ($bit7 << 7);
1490
1491 #[allow(unreachable_code)]
1492 if $range.contains(&IDX) {
1493 $crate::set_general_handler_entry!($idt, $handler, IDX, $bit7, $bit6, $bit5, $bit4, $bit3, $bit2, $bit1, $bit0);
1494 }
1495 }};
1496 // otherwise recursively invoke the macro adding one more bit
1497 ($idt:expr, $handler:ident, $range:expr $(, $bits:tt)*) => {
1498 $crate::set_general_handler_recursive_bits!($idt, $handler, $range $(, $bits)*, 0);
1499 $crate::set_general_handler_recursive_bits!($idt, $handler, $range $(, $bits)*, 1);
1500 };
1501}
1502
1503#[cfg(all(
1504 feature = "instructions",
1505 feature = "abi_x86_interrupt",
1506 target_arch = "x86_64"
1507))]
1508#[macro_export]
1509#[doc(hidden)]
1510macro_rules! set_general_handler_entry {
1511 // special case entries that don't have the `HandlerFunc` signature
1512 ($idt:expr, $handler:ident, $idx:expr, 0, 0, 0, 0, 1, 0, 0, 0) => {{
1513 extern "x86-interrupt" fn handler(
1514 frame: $crate::structures::idt::InterruptStackFrame,
1515 error_code: u64,
1516 ) -> ! {
1517 $handler(frame, $idx.into(), Some(error_code));
1518 panic!("General handler returned on double fault");
1519 }
1520 $idt.double_fault.set_handler_fn(handler);
1521 }};
1522 ($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 0, 1, 0, 1, 0) => {{
1523 extern "x86-interrupt" fn handler(
1524 frame: $crate::structures::idt::InterruptStackFrame,
1525 error_code: u64,
1526 ) {
1527 $handler(frame, $idx.into(), Some(error_code));
1528 }
1529 $idt.invalid_tss.set_handler_fn(handler);
1530 }};
1531 ($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 0, 1, 0, 1, 1) => {{
1532 extern "x86-interrupt" fn handler(
1533 frame: $crate::structures::idt::InterruptStackFrame,
1534 error_code: u64,
1535 ) {
1536 $handler(frame, $idx.into(), Some(error_code));
1537 }
1538 $idt.segment_not_present.set_handler_fn(handler);
1539 }};
1540 ($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 0, 1, 1, 0, 0) => {{
1541 extern "x86-interrupt" fn handler(
1542 frame: $crate::structures::idt::InterruptStackFrame,
1543 error_code: u64,
1544 ) {
1545 $handler(frame, $idx.into(), Some(error_code));
1546 }
1547 $idt.stack_segment_fault.set_handler_fn(handler);
1548 }};
1549 ($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 0, 1, 1, 0, 1) => {{
1550 extern "x86-interrupt" fn handler(
1551 frame: $crate::structures::idt::InterruptStackFrame,
1552 error_code: u64,
1553 ) {
1554 $handler(frame, $idx.into(), Some(error_code));
1555 }
1556 $idt.general_protection_fault.set_handler_fn(handler);
1557 }};
1558 ($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 0, 1, 1, 1, 0) => {{
1559 extern "x86-interrupt" fn handler(
1560 frame: $crate::structures::idt::InterruptStackFrame,
1561 error_code: $crate::structures::idt::PageFaultErrorCode,
1562 ) {
1563 $handler(frame, IDX.into(), Some(error_code.bits()));
1564 }
1565 $idt.page_fault.set_handler_fn(handler);
1566 }};
1567 ($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 1, 0, 0, 0, 1) => {{
1568 extern "x86-interrupt" fn handler(
1569 frame: $crate::structures::idt::InterruptStackFrame,
1570 error_code: u64,
1571 ) {
1572 $handler(frame, $idx.into(), Some(error_code));
1573 }
1574 $idt.alignment_check.set_handler_fn(handler);
1575 }};
1576 ($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 1, 0, 0, 1, 0) => {{
1577 extern "x86-interrupt" fn handler(
1578 frame: $crate::structures::idt::InterruptStackFrame,
1579 ) -> ! {
1580 $handler(frame, $idx.into(), None);
1581 panic!("General handler returned on machine check exception");
1582 }
1583 $idt.machine_check.set_handler_fn(handler);
1584 }};
1585 ($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 1, 0, 1, 0, 1) => {{
1586 extern "x86-interrupt" fn handler(
1587 frame: $crate::structures::idt::InterruptStackFrame,
1588 error_code: u64,
1589 ) {
1590 $handler(frame, $idx.into(), Some(error_code));
1591 }
1592 $idt.cp_protection_exception.set_handler_fn(handler);
1593 }};
1594 ($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 1, 1, 1, 0, 1) => {
1595 extern "x86-interrupt" fn handler(
1596 frame: $crate::structures::idt::InterruptStackFrame,
1597 error_code: u64,
1598 ) {
1599 $handler(frame, $idx.into(), Some(error_code));
1600 }
1601 $idt.vmm_communication_exception.set_handler_fn(handler);
1602 };
1603 ($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 1, 1, 1, 1, 0) => {{
1604 extern "x86-interrupt" fn handler(
1605 frame: $crate::structures::idt::InterruptStackFrame,
1606 error_code: u64,
1607 ) {
1608 $handler(frame, $idx.into(), Some(error_code));
1609 }
1610 $idt.security_exception.set_handler_fn(handler);
1611 }};
1612
1613 // reserved_1
1614 ($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 0, 1, 1, 1, 1) => {};
1615 // reserved_2
1616 ($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 1, 0, 1, 1, 0) => {};
1617 ($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 1, 0, 1, 1, 1) => {};
1618 ($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 1, 1, 0, 0, 0) => {};
1619 ($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 1, 1, 0, 0, 1) => {};
1620 ($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 1, 1, 0, 1, 0) => {};
1621 ($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 1, 1, 0, 1, 1) => {};
1622 // reserved_3
1623 ($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 1, 1, 1, 1, 1) => {};
1624
1625 // set entries with `HandlerFunc` signature
1626 ($idt:expr, $handler:ident, $idx:ident $(, $_bits:tt)*) => {{
1627 extern "x86-interrupt" fn handler(frame: $crate::structures::idt::InterruptStackFrame) {
1628 $handler(frame, $idx.into(), None);
1629 }
1630 $idt[$idx].set_handler_fn(handler);
1631 }};
1632}
1633
1634#[cfg(test)]
1635mod test {
1636 use super::*;
1637
1638 #[allow(dead_code)]
1639 fn entry_present(idt: &InterruptDescriptorTable, index: u8) -> bool {
1640 let options = match index {
1641 8 => &idt.double_fault.options,
1642 10 => &idt.invalid_tss.options,
1643 11 => &idt.segment_not_present.options,
1644 12 => &idt.stack_segment_fault.options,
1645 13 => &idt.general_protection_fault.options,
1646 14 => &idt.page_fault.options,
1647 15 => &idt.reserved_1.options,
1648 17 => &idt.alignment_check.options,
1649 18 => &idt.machine_check.options,
1650 21 => &idt.cp_protection_exception.options,
1651 i @ 22..=27 => &idt.reserved_2[usize::from(i) - 22].options,
1652 28 => &idt.hv_injection_exception.options,
1653 29 => &idt.vmm_communication_exception.options,
1654 30 => &idt.security_exception.options,
1655 31 => &idt.reserved_3.options,
1656 other => &idt[other].options,
1657 };
1658 options.bits.get_bit(15)
1659 }
1660
1661 #[test]
1662 fn size_test() {
1663 use core::mem::size_of;
1664 assert_eq!(size_of::<Entry<HandlerFunc>>(), 16);
1665 assert_eq!(size_of::<InterruptDescriptorTable>(), 256 * 16);
1666 assert_eq!(size_of::<InterruptStackFrame>(), 40);
1667 assert_eq!(size_of::<InterruptStackFrameValue>(), 40);
1668 }
1669
1670 #[cfg(all(
1671 feature = "instructions",
1672 feature = "abi_x86_interrupt",
1673 target_arch = "x86_64"
1674 ))]
1675 // there seems to be a bug in LLVM that causes rustc to crash on windows when compiling this test:
1676 // https://github.com/rust-osdev/x86_64/pull/285#issuecomment-962642984
1677 #[cfg(not(windows))]
1678 #[test]
1679 fn default_handlers() {
1680 fn general_handler(
1681 _stack_frame: InterruptStackFrame,
1682 _index: u8,
1683 _error_code: Option<u64>,
1684 ) {
1685 }
1686
1687 let mut idt = InterruptDescriptorTable::new();
1688 set_general_handler!(&mut idt, general_handler, 0);
1689 for i in 0..=255 {
1690 if i == 0 {
1691 assert!(entry_present(&idt, i));
1692 } else {
1693 assert!(!entry_present(&idt, i));
1694 }
1695 }
1696 set_general_handler!(&mut idt, general_handler, 14);
1697 for i in 0..=255 {
1698 if i == 0 || i == 14 {
1699 assert!(entry_present(&idt, i));
1700 } else {
1701 assert!(!entry_present(&idt, i));
1702 }
1703 }
1704 set_general_handler!(&mut idt, general_handler, 32..64);
1705 for i in 1..=255 {
1706 if i == 0 || i == 14 || (32..64).contains(&i) {
1707 assert!(entry_present(&idt, i), "{}", i);
1708 } else {
1709 assert!(!entry_present(&idt, i));
1710 }
1711 }
1712 set_general_handler!(&mut idt, general_handler);
1713 for i in 0..=255 {
1714 if i == 15 || i == 31 || (22..=27).contains(&i) {
1715 // reserved entries should not be set
1716 assert!(!entry_present(&idt, i));
1717 } else {
1718 assert!(entry_present(&idt, i));
1719 }
1720 }
1721 }
1722
1723 #[test]
1724 fn entry_derive_test() {
1725 fn foo(_: impl Copy + PartialEq + fmt::Debug) {}
1726
1727 foo(Entry::<HandlerFuncWithErrCode> {
1728 pointer_low: 0,
1729 options: EntryOptions::minimal(),
1730 pointer_middle: 0,
1731 pointer_high: 0,
1732 reserved: 0,
1733 phantom: PhantomData,
1734 })
1735 }
1736
1737 #[test]
1738 fn isr_frame_manipulation() {
1739 let mut frame = InterruptStackFrame(InterruptStackFrameValue {
1740 instruction_pointer: VirtAddr::new(0x1000),
1741 code_segment: SegmentSelector(0),
1742 cpu_flags: RFlags::empty(),
1743 stack_pointer: VirtAddr::new(0x2000),
1744 stack_segment: SegmentSelector(0),
1745 _reserved1: Default::default(),
1746 _reserved2: Default::default(),
1747 });
1748
1749 unsafe {
1750 frame.as_mut().update(|f| f.instruction_pointer += 2u64);
1751 }
1752 }
1753}