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    /// Called when a COM port interrupt is fired and a new byte is available.
63    fn serial_input(port: u8, byte: u8);
64
65    fn test_interrupt<C>(_cx: C)
66    where
67        C: ctx::Context<Registers = R>,
68    {
69        // nop
70    }
71}
72
73/// Errors that may occur while registering an interrupt handler.
74#[derive(Clone, Eq, PartialEq, thiserror::Error)]
75#[error("{kind}")]
76pub struct RegistrationError {
77    kind: RegistrationErrorKind,
78}
79
80#[derive(Debug)]
81pub struct CriticalGuard<'a, C: Control + ?Sized> {
82    ctrl: &'a mut C,
83}
84
85#[derive(Debug, Clone, Eq, PartialEq, thiserror::Error)]
86enum RegistrationErrorKind {
87    #[error("the provided interrupt vector does not exist")]
88    Nonexistant,
89    #[error("an interrupt handler is already registered for this vector")]
90    AlreadyRegistered,
91    #[error("{0}")]
92    Other(&'static str),
93}
94
95// === impl CriticalGuard ===
96
97impl<C: Control + ?Sized> Drop for CriticalGuard<'_, C> {
98    fn drop(&mut self) {
99        unsafe {
100            self.ctrl.enable();
101        }
102    }
103}
104
105// === impl RegistrationError ===
106impl RegistrationError {
107    /// Returns a new error indicating that the registered interrupt vector does
108    /// not exist.
109    pub fn nonexistant() -> Self {
110        Self {
111            kind: RegistrationErrorKind::Nonexistant,
112        }
113    }
114
115    /// Returns a new error indicating that the registered interrupt vector has
116    /// already been registered and cannot be registered again.
117    pub fn already_registered() -> Self {
118        Self {
119            kind: RegistrationErrorKind::AlreadyRegistered,
120        }
121    }
122
123    /// Returns a new platform-specific error with the provided message.
124    pub fn other(message: &'static str) -> Self {
125        Self {
126            kind: RegistrationErrorKind::Other(message),
127        }
128    }
129
130    pub fn is_nonexistant(&self) -> bool {
131        matches!(self.kind, RegistrationErrorKind::Nonexistant)
132    }
133
134    pub fn is_already_registered(&self) -> bool {
135        matches!(self.kind, RegistrationErrorKind::AlreadyRegistered)
136    }
137}
138
139impl fmt::Debug for RegistrationError {
140    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141        let Self { kind } = self;
142        f.debug_struct("RegistrationError")
143            .field("kind", kind)
144            .finish()
145    }
146}