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}