diff --git a/kernel/interrupt.rs b/kernel/interrupt.rs index 729f0c4a..758de332 100644 --- a/kernel/interrupt.rs +++ b/kernel/interrupt.rs @@ -1,48 +1,52 @@ //! Interrupt handling. -use alloc::boxed::Box; -use core::mem::MaybeUninit; +use alloc::{boxed::Box, vec::Vec}; use kerla_runtime::{arch::enable_irq, spinlock::SpinLock}; -use kerla_utils::bitmap::BitMap; use crate::{deferred_job::run_deferred_jobs, interval_work}; -fn empty_irq_handler() {} - type IrqHandler = dyn FnMut() + Send + Sync; -const UNINITIALIZED_IRQ_HANDLER: MaybeUninit> = MaybeUninit::uninit(); -static IRQ_HANDLERS: SpinLock<[MaybeUninit>; 256]> = - SpinLock::new([UNINITIALIZED_IRQ_HANDLER; 256]); -static ATTACHED_IRQS: SpinLock> = SpinLock::new(BitMap::zeroed()); +const NUM_IRQ_NUMBERS: usize = 256; -pub fn init() { - let mut handlers = IRQ_HANDLERS.lock(); - for handler in handlers.iter_mut() { - handler.write(Box::new(empty_irq_handler)); - } +/// Holds the interrupt handlers. The index is the IRQ number and this vector +/// contains `NUM_IRQ_NUMBERS` entries. +static IRQ_VECTORS: SpinLock> = SpinLock::new(Vec::new()); + +pub struct IrqVector { + handlers: Vec>, } -pub fn attach_irq(irq: u8, f: Box) { - let mut attached_irq_map = ATTACHED_IRQS.lock(); - match attached_irq_map.get(irq as usize) { - Some(true) => panic!("handler for IRQ #{} is already attached", irq), - Some(false) => { - attached_irq_map.set(irq as usize); - IRQ_HANDLERS.lock()[irq as usize].write(f); - enable_irq(irq); +impl IrqVector { + pub fn new() -> IrqVector { + IrqVector { + handlers: Vec::new(), } - None => panic!("IRQ #{} is out of bound", irq), } + + pub fn handlers_mut(&mut self) -> &mut [Box] { + &mut self.handlers + } + + pub fn add_handler(&mut self, f: Box) { + self.handlers.push(f); + } +} + +pub fn attach_irq(irq: u8, f: Box) { + debug_assert!((irq as usize) < NUM_IRQ_NUMBERS); + IRQ_VECTORS.lock()[irq as usize].add_handler(f); + enable_irq(irq); } pub fn handle_irq(irq: u8) { { - let handler = &mut IRQ_HANDLERS.lock()[irq as usize]; - unsafe { - (*handler.assume_init_mut())(); + debug_assert!((irq as usize) < NUM_IRQ_NUMBERS); + let mut vectors = IRQ_VECTORS.lock(); + for handler in vectors[irq as usize].handlers_mut() { + handler(); } - // `handler` is dropped here to release IRQ_HANDLERS's lock since + // `vectors` is dropped here to release IRQ_HANDLERS's lock since // we re-enable interrupts just before running deferred jobs. } @@ -53,3 +57,10 @@ pub fn handle_irq(irq: u8) { interval_work(); run_deferred_jobs(); } + +pub fn init() { + let mut vectors = IRQ_VECTORS.lock(); + for _ in 0..NUM_IRQ_NUMBERS { + vectors.push(IrqVector::new()); + } +}