abyss/interrupt/
mod.rs

1//! Interrupt
2#[cfg(doc)]
3use crate::spinlock::SpinLockGuard;
4use crate::{
5    unwind,
6    x86_64::{Rflags, interrupt::InterruptStackFrame, segmentation::Segment},
7};
8use core::{
9    arch::{asm, naked_asm},
10    sync::atomic::{AtomicBool, AtomicIsize, Ordering},
11};
12
13mod entry;
14pub use entry::do_handle_irq;
15
16static PER_CORE_STATE: [InterruptGuardInner; crate::MAX_CPU] =
17    [const { InterruptGuardInner::new() }; crate::MAX_CPU];
18
19struct InterruptGuardInner {
20    initial_state: AtomicBool,
21    cnt: AtomicIsize,
22}
23
24impl InterruptGuardInner {
25    const fn new() -> Self {
26        Self {
27            initial_state: AtomicBool::new(true),
28            cnt: AtomicIsize::new(0),
29        }
30    }
31
32    fn save_nested_interrupt_state(&self, state: InterruptState) {
33        if self.cnt.fetch_add(1, Ordering::SeqCst) == 0 {
34            self.initial_state
35                .store(state == InterruptState::On, Ordering::SeqCst);
36        }
37    }
38
39    fn load_nested_interrupt_state(&self) {
40        let prev = self.cnt.fetch_sub(1, Ordering::SeqCst);
41        assert!(prev > 0, "Mismatched InterruptGuard drop calls: {prev}");
42
43        if prev == 1 && self.initial_state.load(Ordering::SeqCst) {
44            unsafe { InterruptState::enable() };
45        }
46    }
47
48    fn decrement_count(&self) {
49        let prev = self.cnt.fetch_sub(1, Ordering::SeqCst);
50        assert!(prev > 0, "Mismatched InterruptGuard drop calls: {prev}");
51    }
52}
53
54/// Enumeration representing the interrupt state.
55#[derive(PartialEq, Eq, Debug)]
56pub enum InterruptState {
57    /// Interrupts are enabled.
58    On,
59    /// Interrupts are disabled.
60    Off,
61}
62
63impl InterruptState {
64    /// Reads the current interrupt state.
65    ///
66    /// # Returns
67    /// - [`InterruptState::On`] if interrupts are enabled.
68    /// - [`InterruptState::Off`] if interrupts are disabled.
69    pub fn current() -> Self {
70        if Rflags::read().contains(Rflags::IF) {
71            Self::On
72        } else {
73            Self::Off
74        }
75    }
76
77    pub unsafe fn enable() {
78        unsafe {
79            asm!("sti");
80        }
81    }
82
83    pub unsafe fn disable() {
84        unsafe {
85            asm!("cli");
86        }
87    }
88}
89
90/// An RAII-based guard for managing interrupt disabling.
91///
92/// When an `InterruptGuard` is created, interrupts are disabled. When it is
93/// dropped, the interrupt state is restored to what it was before the guard was
94/// created.
95///
96/// **Important:**
97/// - [`InterruptGuard`] instances **must be dropped in reverse order of their
98///   creation** to prevent unintended interrupt state changes.
99/// - Due to Rust's ownership and scoping rules, this invariant is naturally
100///   upheld unless `drop()` is explicitly called prematurely or an
101///   [`InterruptGuard`] is stored in a struct field.
102///
103/// This structure is created using [`InterruptGuard::new`].
104pub struct InterruptGuard {
105    core_id: usize,
106}
107
108impl !Send for InterruptGuard {}
109impl !Sync for InterruptGuard {}
110
111impl InterruptGuard {
112    /// Creates a new `InterruptGuard`, disabling interrupts.
113    ///
114    /// # Behavior
115    /// - Saves the current interrupt state.
116    /// - Disables interrupts (`cli` instruction).
117    ///
118    /// # Returns
119    /// A new instance of `InterruptGuard`, which will restore the original
120    /// interrupt state when dropped.
121    ///
122    /// # Example
123    /// ```rust
124    /// let _guard = InterruptGuard::new(); // Disables interrupts
125    /// // Critical section...
126    /// // Interrupts are restored when `_guard` goes out of scope.
127    /// ```
128    pub fn new() -> Self {
129        let state = InterruptState::current();
130        unsafe { InterruptState::disable() };
131        core::sync::atomic::fence(Ordering::SeqCst);
132
133        let core_id = crate::x86_64::intrinsics::cpuid();
134        let guard = &PER_CORE_STATE[core_id];
135
136        guard.save_nested_interrupt_state(state);
137
138        Self { core_id }
139    }
140
141    pub fn consume(self) {
142        let guard = &PER_CORE_STATE[self.core_id];
143        guard.decrement_count();
144
145        core::mem::forget(self);
146    }
147
148    pub fn is_guarded() -> bool {
149        let core_id = crate::x86_64::intrinsics::cpuid();
150        let guard = &PER_CORE_STATE[core_id];
151        guard.cnt.load(Ordering::SeqCst) > 0
152    }
153}
154
155impl Default for InterruptGuard {
156    fn default() -> Self {
157        Self::new()
158    }
159}
160
161impl Drop for InterruptGuard {
162    fn drop(&mut self) {
163        if self.core_id != crate::x86_64::intrinsics::cpuid() {
164            panic!(
165                "InterruptGuard dropped on different core: {} != {}",
166                self.core_id,
167                crate::x86_64::intrinsics::cpuid()
168            );
169        }
170
171        let guard = &PER_CORE_STATE[crate::x86_64::intrinsics::cpuid()];
172        guard.load_nested_interrupt_state();
173        core::sync::atomic::fence(Ordering::SeqCst);
174    }
175}
176
177/// X86_64's general purpose registers.
178#[repr(C)]
179#[derive(Clone, Copy, Debug, Default)]
180pub struct GeneralPurposeRegisters {
181    /// R15 register.
182    pub r15: usize,
183    /// R14 register.
184    pub r14: usize,
185    /// R13 register.
186    pub r13: usize,
187    /// R12 register.
188    pub r12: usize,
189    /// R11 register.
190    pub r11: usize,
191    /// R10 register.
192    pub r10: usize,
193    /// R9 register.
194    pub r9: usize,
195    /// R8 register.
196    pub r8: usize,
197    /// RSI register.
198    pub rsi: usize,
199    /// RDI register.
200    pub rdi: usize,
201    /// RBP register.
202    pub rbp: usize,
203    /// RDX register.
204    pub rdx: usize,
205    /// RCX register.
206    pub rcx: usize,
207    /// RBX register.
208    pub rbx: usize,
209    /// RAX register.
210    pub rax: usize,
211}
212
213/// x86_64 Trap frame.
214#[repr(C)]
215#[derive(Clone, Copy)]
216pub struct Registers {
217    pub gprs: GeneralPurposeRegisters,
218    error_code: u64,
219    #[doc(hidden)]
220    pub interrupt_stack_frame: InterruptStackFrame,
221}
222
223impl Default for Registers {
224    fn default() -> Self {
225        Self::new()
226    }
227}
228
229impl Registers {
230    /// Creates a new register frame for a user thread.
231    ///
232    /// This function initializes a [`Registers`] structure with default values
233    /// for a new user-space thread.
234    ///
235    /// # Returns
236    /// - A [`Registers`] instance with default values for user-space execution.
237    ///
238    /// # Example
239    /// ```rust
240    /// let mut regs = Registers::new();
241    /// *regs.rip() = 0x400000; // Set entry point
242    /// *regs.rsp() = 0x7FFFFFFFE000; // Set user stack pointer
243    /// ```
244    #[inline]
245    pub fn new() -> Self {
246        Self {
247            gprs: GeneralPurposeRegisters::default(),
248            error_code: 0,
249            interrupt_stack_frame: InterruptStackFrame {
250                rip: 0,                                /* Entry point of the user program should
251                                                        * be set later. */
252                cs: Segment::UserCode.into_selector(), // User-space code segment.
253                __pad0: 0,
254                __pad1: 0,
255                rflags: Rflags::IF | Rflags::_1, // Enables interrupts.
256                rsp: 0,                          /* User-space stack pointer should be set before
257                                                  * execution. */
258                ss: Segment::UserData.into_selector(), // User-space stack segment.
259                __pad2: 0,
260                __pad3: 0,
261            },
262        }
263    }
264
265    /// Returns a mutable reference to the instruction pointer (`RIP`).
266    ///
267    /// This function allows modifying the instruction pointer, which determines
268    /// the next instruction the CPU will execute when the thread resumes.
269    ///
270    /// # Returns
271    /// - A mutable reference to the `rip` field in the interrupt stack frame.
272    ///
273    /// # Example
274    /// ```rust
275    /// let mut regs = Registers::new();
276    /// *regs.rip() = 0x400000; // Set the entry point
277    /// ```
278    pub fn rip(&mut self) -> &mut usize {
279        &mut self.interrupt_stack_frame.rip
280    }
281
282    /// Returns a mutable reference to the stack pointer (`RSP`).
283    ///
284    /// This function allows modifying the stack pointer, which should point
285    /// to the top of the stack before execution.
286    ///
287    /// # Returns
288    /// - A mutable reference to the `rsp` field.
289    ///
290    /// # Example
291    /// ```rust
292    /// let mut regs = Registers::new();
293    /// *regs.rsp() = 0x7FFFFFFFE000; // Set the user stack pointer
294    /// ```
295    pub fn rsp(&mut self) -> &mut usize {
296        &mut self.interrupt_stack_frame.rsp
297    }
298
299    /// Launch the frame.
300    ///
301    /// Launches a thread by restoring its saved register state.
302    ///
303    /// This function returns the `never` type (`!`), meaning that once
304    /// executed, there is no way to return to the current execution
305    /// context.
306    ///
307    /// # Safety
308    /// - The kernel must release all temporary resources such as locally
309    ///   allocated `Box`, [`SpinLockGuard`], or [`InterruptGuard`] before
310    ///   calling this function.
311    ///
312    /// # Behavior
313    /// 1. Restores general-purpose registers from `self.gprs`.
314    /// 2. Enables interrupts.
315    /// 3. Transfers to saved execution state by executing `iretq`.
316    ///
317    /// # Example Usage
318    /// ```rust
319    /// let regs = Registers::new();
320    /// regs.launch(); // This function does not return
321    /// unreachable!() // Execution will never reach here
322    #[unsafe(naked)]
323    pub extern "C" fn launch(&self) -> ! {
324        naked_asm!(
325            "mov rax, [rdi + 0x70]",
326            "mov rbx, [rdi + 0x68]",
327            "mov rcx, [rdi + 0x60]",
328            "mov rdx, [rdi + 0x58]",
329            "mov rbp, [rdi + 0x50]",
330            "mov rsi, [rdi + 0x40]",
331            "mov r8, [rdi + 0x38]",
332            "mov r9, [rdi + 0x30]",
333            "mov r10, [rdi + 0x28]",
334            "mov r11, [rdi + 0x20]",
335            "mov r12, [rdi + 0x18]",
336            "mov r13, [rdi + 0x10]",
337            "mov r14, [rdi + 0x8]",
338            "mov r15, [rdi]",
339            "sti",
340            "lea rsp, [rdi + 0x80]",
341            "mov rdi, [rdi + 0x48]",
342            "iretq"
343        )
344    }
345
346    #[inline]
347    #[doc(hidden)]
348    pub fn to_stack_frame(&self) -> unwind::StackFrame {
349        unwind::StackFrame {
350            rax: self.gprs.rax,
351            rbx: self.gprs.rbx,
352            rcx: self.gprs.rcx,
353            rdx: self.gprs.rdx,
354            rsi: self.gprs.rsi,
355            rdi: self.gprs.rdi,
356            rbp: self.gprs.rbp,
357            rsp: self.interrupt_stack_frame.rsp,
358            r8: self.gprs.r8,
359            r9: self.gprs.r9,
360            r10: self.gprs.r10,
361            r11: self.gprs.r11,
362            r12: self.gprs.r12,
363            r13: self.gprs.r13,
364            r14: self.gprs.r14,
365            r15: self.gprs.r15,
366            rip: self.interrupt_stack_frame.rip,
367        }
368    }
369}
370
371impl core::fmt::Debug for Registers {
372    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
373        write!(
374            f,
375            "RAX: {:016x} | RBX: {:016x}  | RCX: {:016x} | RDX: {:016x}\n\
376             RSI: {:016x} | RDI: {:016x}  | RBP: {:016x} | RSP: {:016x}\n\
377             R8 : {:016x} | R9 : {:016x}  | R10: {:016x} | R11: {:016x}\n\
378             R12: {:016x} | R13: {:016x}  | R14: {:016x} | R15: {:016x}\n\
379             RIP: {:016x} | Error Code: {:#x} | RFLAGS: {:016x} [{:?}]\n\
380             CS:  {:?}   | SS: {:?}",
381            self.gprs.rax,
382            self.gprs.rbx,
383            self.gprs.rcx,
384            self.gprs.rdx,
385            self.gprs.rsi,
386            self.gprs.rdi,
387            self.gprs.rbp,
388            self.interrupt_stack_frame.rsp,
389            self.gprs.r8,
390            self.gprs.r9,
391            self.gprs.r10,
392            self.gprs.r11,
393            self.gprs.r12,
394            self.gprs.r13,
395            self.gprs.r14,
396            self.gprs.r15,
397            self.interrupt_stack_frame.rip,
398            self.error_code,
399            self.interrupt_stack_frame.rflags.bits(),
400            self.interrupt_stack_frame.rflags,
401            self.interrupt_stack_frame.cs,
402            self.interrupt_stack_frame.ss,
403        )
404    }
405}
406
407/// NMI Expection for Stopping CPUs on PANIC
408pub static NMI_EXPECTED_PANICKING: AtomicBool = AtomicBool::new(false);