Skip to main content

osiris/
irq.rs

1use crate::{
2    error::Result,
3    sync::{self, spinlock::RwSpinLocked},
4    types::array::Vec,
5};
6
7/// The IRQ handler type. The first argument is a pointer to the context, the second argument is the IRQ vector, and the third argument is userdata.
8pub use hal_api::IrqHandler;
9
10#[derive(Clone, Copy)]
11struct Handler {
12    func: IrqHandler,
13    userdata: Option<usize>,
14}
15
16// TODO: Amount of lines should be configured by the DeviceTree.
17static HANDLERS: [RwSpinLocked<Vec<Handler, 1>>; 240] =
18    [const { RwSpinLocked::new(Vec::new()) }; 240];
19
20/// Register an IRQ handler for the given vector.
21///
22/// `vector` - The IRQ vector to register the handler for.
23/// `handler` - The IRQ handler to register.
24/// `userdata` - Optional userdata to pass to the handler when the IRQ is triggered.
25///
26/// # Safety
27/// - The caller must ensure that the handler is safe to call in an IRQ context and that the userdata is valid for the lifetime of the handler.
28/// - This functions must not be called from an IRQ context.
29pub unsafe fn register_irq(
30    vector: usize,
31    handler: IrqHandler,
32    userdata: Option<usize>,
33) -> Result<()> {
34    if vector >= HANDLERS.len() {
35        Err(kerr!(EINVAL, "Invalid IRQ vector."))?;
36    }
37
38    let handler = Handler {
39        func: handler,
40        userdata,
41    };
42
43    // If an irq happens while HANDLERS is locked this will deadlock.
44    // Thats why we need to modify it in an irq free section.
45    sync::atomic::irq_free(|| HANDLERS[vector].write_lock().push(handler))
46}
47
48/// `IrqRegister`-shaped wrapper around [`register_irq`] for HAL init.
49pub fn register_irq_safe(
50    vector: usize,
51    handler: IrqHandler,
52    userdata: Option<usize>,
53) -> hal_api::Result<()> {
54    unsafe { register_irq(vector, handler, userdata) }.map_err(|e| e.kind)
55}
56
57/// Unregister all IRQ handlers for the given vector.
58///
59/// `vector` - The IRQ vector to unregister the handlers for.
60///
61/// # Safety
62/// - This function must not be called from an IRQ context.
63pub unsafe fn unregister_irq(vector: usize) -> Result<()> {
64    if vector >= HANDLERS.len() {
65        Err(kerr!(EINVAL, "Invalid IRQ vector."))?;
66    }
67
68    sync::atomic::irq_free(|| {
69        HANDLERS[vector].write_lock().clear();
70    });
71
72    Ok(())
73}
74
75#[unsafe(no_mangle)]
76extern "C" fn kernel_irq_handler(ctx: *mut u8, vector: usize) {
77    if vector >= HANDLERS.len() {
78        warn!("Invalid IRQ vector {}", vector);
79        return;
80    }
81
82    // It is forbidden to hold a HANDLERS write_lock in an irq context.
83    let handler = HANDLERS[vector].read_lock();
84
85    if handler.is_empty() {
86        warn!("Unhandled IRQ {}", vector);
87        return;
88    }
89
90    for i in 0..handler.len() {
91        let handler = handler[i];
92        (handler.func)(ctx, vector, handler.userdata)
93    }
94}