keos/
interrupt.rs

1//! Interrupt management.
2use crate::{sync::SpinLock, thread::with_current};
3use abyss::{
4    x86_64::{Cr2, PrivilegeLevel, interrupt::PFErrorCode},
5    {addressing::Va, interrupt::Registers},
6};
7use alloc::sync::Arc;
8
9type Handler = Option<Arc<dyn Fn(&mut Registers) + Send + Sync>>;
10#[allow(clippy::declare_interior_mutable_const)]
11const INIT: SpinLock<Handler> = SpinLock::new(None);
12static HANDLERS: [SpinLock<Handler>; 224] = [INIT; 224];
13
14#[doc(hidden)]
15#[unsafe(no_mangle)]
16pub fn do_handle_interrupt(idx: usize, frame: &mut Registers) {
17    let guard = HANDLERS.get(idx).unwrap().lock();
18    let handler = guard.clone();
19    guard.unlock();
20
21    match &handler {
22        Some(handler) => handler(frame),
23        _ => {
24            panic!("Unknown interrupt #{}", idx + 32);
25        }
26    }
27
28    if frame.interrupt_stack_frame.cs.dpl() == PrivilegeLevel::Ring3 {
29        crate::thread::__check_for_signal();
30    }
31}
32
33/// Register the interrupt handler
34pub fn register(vec: usize, handler: impl Fn(&mut Registers) + Send + Sync + 'static) {
35    let mut guard = HANDLERS.get(vec - 32).expect("Invalid index").lock();
36    *guard = Some(Arc::new(handler));
37    guard.unlock();
38}
39
40/// The entry points of the page fault.
41#[doc(hidden)]
42#[unsafe(no_mangle)]
43pub extern "C" fn handle_page_fault(frame: &mut Registers, ec: PFErrorCode) {
44    with_current(|th| match th.task.as_mut() {
45        Some(task) => {
46            let cr2 = Va::new(Cr2::current().into_usize()).unwrap();
47            // Enable interrupt after resolving the faulting address.
48            unsafe {
49                core::arch::asm!("sti");
50            }
51            task.page_fault(ec, cr2);
52        }
53        _ => {
54            panic!("Unexpected page fault: {:?} {:#?}", ec, frame);
55        }
56    });
57}