1use 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
33pub 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#[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 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}