hal_core/
interrupt.rs

1use core::fmt;
2
3pub mod ctx;
4pub use self::ctx::Context;
5
6/// An interrupt controller for a platform.
7pub trait Control {
8    type Registers: fmt::Debug + fmt::Display;
9
10    /// Disable all interrupts.
11    ///
12    /// # Safety
13    ///
14    /// This may cause a fault if called when interrupts are already disabled
15    /// (depending on the platform). It does not guarantee that interrupts will
16    /// ever be unmasked.
17    unsafe fn disable(&mut self);
18
19    /// Enable all interrupts.
20    ///
21    /// # Safety
22    ///
23    /// This may cause a fault if called when interrupts are already enabled
24    /// (depending on the platform).
25    unsafe fn enable(&mut self);
26
27    /// Returns `true` if interrupts are enabled.
28    fn is_enabled(&self) -> bool;
29
30    fn register_handlers<H>(&mut self) -> Result<(), RegistrationError>
31    where
32        H: Handlers<Self::Registers>;
33
34    /// Enter a critical section, returning a guard.
35    fn enter_critical(&mut self) -> CriticalGuard<'_, Self> {
36        unsafe {
37            self.disable();
38        }
39        CriticalGuard { ctrl: self }
40    }
41}
42
43pub trait Handlers<R: fmt::Debug + fmt::Display> {
44    fn page_fault<C>(cx: C)
45    where
46        C: ctx::Context<Registers = R> + ctx::PageFault;
47
48    fn code_fault<C>(cx: C)
49    where
50        C: ctx::Context<Registers = R> + ctx::CodeFault;
51
52    fn double_fault<C>(cx: C)
53    where
54        C: ctx::Context<Registers = R>;
55
56    fn timer_tick();
57
58    /// Called when a PS/2 keyboard interrupt is fired. The handler is provided
59    /// with the scancode read from the PS/2 keyboard controller.
60    fn ps2_keyboard(scancode: u8);
61
62    fn test_interrupt<C>(_cx: C)
63    where
64        C: ctx::Context<Registers = R>,
65    {
66        // nop
67    }
68}
69
70/// Errors that may occur while registering an interrupt handler.
71#[derive(Clone, Eq, PartialEq, thiserror::Error)]
72#[error("{kind}")]
73pub struct RegistrationError {
74    kind: RegistrationErrorKind,
75}
76
77#[derive(Debug)]
78pub struct CriticalGuard<'a, C: Control + ?Sized> {
79    ctrl: &'a mut C,
80}
81
82#[derive(Debug, Clone, Eq, PartialEq, thiserror::Error)]
83enum RegistrationErrorKind {
84    #[error("the provided interrupt vector does not exist")]
85    Nonexistant,
86    #[error("an interrupt handler is already registered for this vector")]
87    AlreadyRegistered,
88    #[error("{0}")]
89    Other(&'static str),
90}
91
92// === impl CriticalGuard ===
93
94impl<C: Control + ?Sized> Drop for CriticalGuard<'_, C> {
95    fn drop(&mut self) {
96        unsafe {
97            self.ctrl.enable();
98        }
99    }
100}
101
102// === impl RegistrationError ===
103impl RegistrationError {
104    /// Returns a new error indicating that the registered interrupt vector does
105    /// not exist.
106    pub fn nonexistant() -> Self {
107        Self {
108            kind: RegistrationErrorKind::Nonexistant,
109        }
110    }
111
112    /// Returns a new error indicating that the registered interrupt vector has
113    /// already been registered and cannot be registered again.
114    pub fn already_registered() -> Self {
115        Self {
116            kind: RegistrationErrorKind::AlreadyRegistered,
117        }
118    }
119
120    /// Returns a new platform-specific error with the provided message.
121    pub fn other(message: &'static str) -> Self {
122        Self {
123            kind: RegistrationErrorKind::Other(message),
124        }
125    }
126
127    pub fn is_nonexistant(&self) -> bool {
128        matches!(self.kind, RegistrationErrorKind::Nonexistant)
129    }
130
131    pub fn is_already_registered(&self) -> bool {
132        matches!(self.kind, RegistrationErrorKind::AlreadyRegistered)
133    }
134}
135
136impl fmt::Debug for RegistrationError {
137    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138        let Self { kind } = self;
139        f.debug_struct("RegistrationError")
140            .field("kind", kind)
141            .finish()
142    }
143}