diff --git a/nel_os_kernel/src/interrupt/idt.rs b/nel_os_kernel/src/interrupt/idt.rs index 53d37c0..beebf5d 100644 --- a/nel_os_kernel/src/interrupt/idt.rs +++ b/nel_os_kernel/src/interrupt/idt.rs @@ -5,6 +5,7 @@ use crate::{ interrupt::{ apic::{EOI, LAPIC}, gdt, + subscriber::InterruptContext, }, time, warn, }; @@ -40,6 +41,17 @@ pub fn init_idt() { } extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) { + let context = InterruptContext { + vector: 3, + instruction_pointer: stack_frame.instruction_pointer.as_u64(), + code_segment: stack_frame.code_segment.0 as u64, + cpu_flags: stack_frame.cpu_flags.bits(), + stack_pointer: stack_frame.stack_pointer.as_u64(), + stack_segment: stack_frame.stack_segment.0 as u64, + }; + + crate::interrupt::subscriber::dispatch_to_subscribers(&context); + warn!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame); } @@ -47,6 +59,17 @@ extern "x86-interrupt" fn double_fault_handler( stack_frame: InterruptStackFrame, _error_code: u64, ) -> ! { + let context = InterruptContext { + vector: 8, + instruction_pointer: stack_frame.instruction_pointer.as_u64(), + code_segment: stack_frame.code_segment.0 as u64, + cpu_flags: stack_frame.cpu_flags.bits(), + stack_pointer: stack_frame.stack_pointer.as_u64(), + stack_segment: stack_frame.stack_segment.0 as u64, + }; + + crate::interrupt::subscriber::dispatch_to_subscribers(&context); + panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame); } @@ -56,6 +79,17 @@ extern "x86-interrupt" fn page_fault_handler( ) { use x86_64::registers::control::Cr2; + let context = InterruptContext { + vector: 14, + instruction_pointer: stack_frame.instruction_pointer.as_u64(), + code_segment: stack_frame.code_segment.0 as u64, + cpu_flags: stack_frame.cpu_flags.bits(), + stack_pointer: stack_frame.stack_pointer.as_u64(), + stack_segment: stack_frame.stack_segment.0 as u64, + }; + + crate::interrupt::subscriber::dispatch_to_subscribers(&context); + panic!( "EXCEPTION: PAGE FAULT\n{:#?}\nAccessed address: {:#x}", stack_frame, @@ -63,7 +97,18 @@ extern "x86-interrupt" fn page_fault_handler( ); } -extern "x86-interrupt" fn timer_handler(_stack_frame: InterruptStackFrame) { +extern "x86-interrupt" fn timer_handler(stack_frame: InterruptStackFrame) { + let context = InterruptContext { + vector: IRQ_TIMER as u8, + instruction_pointer: stack_frame.instruction_pointer.as_u64(), + code_segment: stack_frame.code_segment.0 as u64, + cpu_flags: stack_frame.cpu_flags.bits(), + stack_pointer: stack_frame.stack_pointer.as_u64(), + stack_segment: stack_frame.stack_segment.0 as u64, + }; + + crate::interrupt::subscriber::dispatch_to_subscribers(&context); + time::tick(); LAPIC.get().unwrap().write(EOI, 0); } diff --git a/nel_os_kernel/src/interrupt/mod.rs b/nel_os_kernel/src/interrupt/mod.rs index 45c8d5c..c6aa667 100644 --- a/nel_os_kernel/src/interrupt/mod.rs +++ b/nel_os_kernel/src/interrupt/mod.rs @@ -1,3 +1,4 @@ pub mod apic; pub mod gdt; pub mod idt; +pub mod subscriber; diff --git a/nel_os_kernel/src/interrupt/subscriber.rs b/nel_os_kernel/src/interrupt/subscriber.rs new file mode 100644 index 0000000..489aece --- /dev/null +++ b/nel_os_kernel/src/interrupt/subscriber.rs @@ -0,0 +1,68 @@ +use spin::Mutex; + +#[derive(Debug)] +pub struct InterruptContext { + pub vector: u8, + pub instruction_pointer: u64, + pub code_segment: u64, + pub cpu_flags: u64, + pub stack_pointer: u64, + pub stack_segment: u64, +} + +pub type SubscriberCallback = fn(*mut core::ffi::c_void, &InterruptContext); + +#[derive(Debug, Clone, Copy)] +pub struct Subscriber { + pub callback: SubscriberCallback, + pub context: *mut core::ffi::c_void, +} + +unsafe impl Send for Subscriber {} +unsafe impl Sync for Subscriber {} + +const MAX_SUBSCRIBERS: usize = 10; + +static SUBSCRIBERS: Mutex<[Option; MAX_SUBSCRIBERS]> = + Mutex::new([None; MAX_SUBSCRIBERS]); + +pub fn subscribe( + callback: SubscriberCallback, + context: *mut core::ffi::c_void, +) -> Result<(), &'static str> { + let mut subscribers = SUBSCRIBERS.lock(); + + for slot in subscribers.iter_mut() { + if slot.is_none() { + *slot = Some(Subscriber { callback, context }); + return Ok(()); + } + } + + Err("No available subscriber slots") +} + +pub fn unsubscribe(callback: SubscriberCallback) -> Result<(), &'static str> { + let mut subscribers = SUBSCRIBERS.lock(); + + for slot in subscribers.iter_mut() { + if let Some(subscriber) = slot { + if subscriber.callback == callback { + *slot = None; + return Ok(()); + } + } + } + + Err("Subscriber not found") +} + +pub fn dispatch_to_subscribers(context: &InterruptContext) { + let subscribers = SUBSCRIBERS.lock(); + + for subscriber in subscribers.iter() { + if let Some(subscriber) = subscriber { + (subscriber.callback)(subscriber.context, context); + } + } +}