kernel/cpu/interrupts/
mod.rs

1pub mod apic;
2mod handlers;
3
4use crate::sync::{once::OnceLock, spin::mutex::Mutex};
5
6use super::{
7    gdt::USER_RING,
8    idt::{BasicInterruptHandler, InterruptDescriptorTable, InterruptHandlerWithAllState},
9};
10
11static INTERRUPTS: OnceLock<Mutex<Interrupts>> = OnceLock::new();
12
13pub(super) mod stack_index {
14    pub const FAULTS_STACK: u8 = 0;
15    pub const DOUBLE_FAULT_STACK: u8 = 1;
16}
17
18const USER_INTERRUPTS_START: u8 = 0x20;
19const MAX_USER_INTERRUPTS: u8 = 0xe0 - 0x10;
20pub const SPECIAL_SCHEDULER_INTERRUPT: u8 = 0xdf; // last one (0xFF)
21pub const SPECIAL_SYSCALL_INTERRUPT: u8 =
22    kernel_user_link::syscalls::SYSCALL_INTERRUPT_NUMBER - USER_INTERRUPTS_START;
23
24struct Interrupts {
25    idt: InterruptDescriptorTable,
26    last_used_user_interrupt: u16,
27}
28
29impl Interrupts {
30    // only apply init for static context
31    fn init(&'static mut self) {
32        self.idt.init_default_handlers();
33
34        // this is only done once
35        self.idt.apply_idt();
36    }
37
38    fn get_next_interrupt(&mut self) -> u8 {
39        if self.last_used_user_interrupt >= MAX_USER_INTERRUPTS as u16 {
40            panic!("No more user interrupts available");
41        }
42
43        let interrupt = self.last_used_user_interrupt;
44        self.last_used_user_interrupt += 1;
45
46        interrupt as u8
47    }
48
49    fn allocate_basic_user_interrupt(&mut self, handler: BasicInterruptHandler) -> u8 {
50        let interrupt = self.get_next_interrupt();
51
52        self.idt.user_defined[interrupt as usize].set_handler(handler);
53
54        interrupt + USER_INTERRUPTS_START
55    }
56
57    fn allocate_user_interrupt_all_saved(&mut self, handler: InterruptHandlerWithAllState) -> u8 {
58        let interrupt = self.get_next_interrupt();
59
60        self.idt.user_defined[interrupt as usize]
61            .set_handler_with_number(handler, interrupt + USER_INTERRUPTS_START);
62
63        interrupt + USER_INTERRUPTS_START
64    }
65}
66
67pub fn init_interrupts() {
68    if INTERRUPTS.try_get().is_some() {
69        panic!("Interrupts already initialized");
70    }
71
72    INTERRUPTS
73        .get_or_init(|| {
74            let interrupts = Interrupts {
75                idt: InterruptDescriptorTable::empty(),
76                last_used_user_interrupt: 0,
77            };
78            Mutex::new(interrupts)
79        })
80        .run_with_mut(|interrupts| {
81            interrupts.init();
82        });
83}
84
85// All Types of interrupt handlers
86pub trait InterruptHandler {
87    fn allocate_and_set_handler(val: Self) -> u8;
88}
89
90impl InterruptHandler for BasicInterruptHandler {
91    fn allocate_and_set_handler(handler: Self) -> u8 {
92        INTERRUPTS
93            .get()
94            .lock()
95            .allocate_basic_user_interrupt(handler)
96    }
97}
98
99impl InterruptHandler for InterruptHandlerWithAllState {
100    fn allocate_and_set_handler(handler: Self) -> u8 {
101        INTERRUPTS
102            .get()
103            .lock()
104            .allocate_user_interrupt_all_saved(handler)
105    }
106}
107
108/// Puts the handler in the IDT and returns the interrupt/vector number
109pub(super) fn allocate_user_interrupt<F: InterruptHandler>(handler: F) -> u8 {
110    F::allocate_and_set_handler(handler)
111}
112
113/// Puts the handler in the IDT and returns the interrupt/vector number
114pub(super) fn allocate_basic_user_interrupt(handler: BasicInterruptHandler) -> u8 {
115    BasicInterruptHandler::allocate_and_set_handler(handler)
116}
117
118/// Puts the handler in the IDT and returns the interrupt/vector number
119pub(super) fn allocate_user_interrupt_all_saved(handler: InterruptHandlerWithAllState) -> u8 {
120    InterruptHandlerWithAllState::allocate_and_set_handler(handler)
121}
122
123pub fn create_scheduler_interrupt(handler: InterruptHandlerWithAllState) {
124    let mut interrupts = INTERRUPTS.get().lock();
125    interrupts.idt.user_defined[SPECIAL_SCHEDULER_INTERRUPT as usize]
126        .set_handler_with_number(handler, SPECIAL_SCHEDULER_INTERRUPT + USER_INTERRUPTS_START)
127        .set_disable_interrupts(true);
128}
129
130pub fn create_syscall_interrupt(handler: InterruptHandlerWithAllState) {
131    let mut interrupts = INTERRUPTS.get().lock();
132    interrupts.idt.user_defined[SPECIAL_SYSCALL_INTERRUPT as usize]
133        .set_handler_with_number(handler, SPECIAL_SYSCALL_INTERRUPT + USER_INTERRUPTS_START)
134        .set_privilege_level(USER_RING)
135        .set_disable_interrupts(false);
136}