Skip to content

Commit 36b29ec

Browse files
committed
Migrate interrupt and exception enums to riscv::interrupt
1 parent f9c94b5 commit 36b29ec

File tree

5 files changed

+592
-542
lines changed

5 files changed

+592
-542
lines changed

riscv/src/interrupt.rs

+46-164
Original file line numberDiff line numberDiff line change
@@ -2,188 +2,70 @@
22
33
// NOTE: Adapted from cortex-m/src/interrupt.rs
44

5-
pub mod machine {
6-
use crate::register::{mepc, mstatus};
5+
pub use riscv_pac::{CoreInterruptNumber, ExceptionNumber, InterruptNumber}; // re-export useful riscv-pac traits
76

8-
/// Disables all interrupts in the current hart (machine mode).
9-
#[inline]
10-
pub fn disable() {
11-
// SAFETY: It is safe to disable interrupts
12-
unsafe { mstatus::clear_mie() }
13-
}
7+
pub mod machine;
8+
pub mod supervisor;
149

15-
/// Enables all the interrupts in the current hart (machine mode).
16-
///
17-
/// # Safety
18-
///
19-
/// Do not call this function inside a critical section.
20-
#[inline]
21-
pub unsafe fn enable() {
22-
mstatus::set_mie()
23-
}
24-
25-
/// Execute closure `f` with interrupts disabled in the current hart (machine mode).
26-
///
27-
/// This method does not synchronise multiple harts, so it is not suitable for
28-
/// using as a critical section. See the `critical-section` crate for a cross-platform
29-
/// way to enter a critical section which provides a `CriticalSection` token.
30-
///
31-
/// This crate provides an implementation for `critical-section` suitable for single-hart systems,
32-
/// based on disabling all interrupts. It can be enabled with the `critical-section-single-hart` feature.
33-
#[inline]
34-
pub fn free<F, R>(f: F) -> R
35-
where
36-
F: FnOnce() -> R,
37-
{
38-
let mstatus = mstatus::read();
10+
#[cfg(not(feature = "s-mode"))]
11+
pub use machine::*;
12+
#[cfg(feature = "s-mode")]
13+
pub use supervisor::*;
3914

40-
// disable interrupts
41-
disable();
15+
/// Trap Cause
16+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
17+
pub enum Trap<I, E> {
18+
Interrupt(I),
19+
Exception(E),
20+
}
4221

43-
let r = f();
22+
/// Trap Error
23+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
24+
pub enum TrapError {
25+
InvalidInterrupt(usize),
26+
InvalidException(usize),
27+
}
4428

45-
// If the interrupts were active before our `disable` call, then re-enable
46-
// them. Otherwise, keep them disabled
47-
if mstatus.mie() {
48-
unsafe { enable() };
29+
impl Trap<usize, usize> {
30+
/// Converts a target-specific trap cause to a generic trap cause
31+
#[inline]
32+
pub fn from<I: CoreInterruptNumber, E: ExceptionNumber>(trap: Trap<I, E>) -> Self {
33+
match trap {
34+
Trap::Interrupt(interrupt) => Trap::Interrupt(interrupt.number()),
35+
Trap::Exception(exception) => Trap::Exception(exception.number()),
4936
}
50-
51-
r
5237
}
5338

54-
/// Execute closure `f` with interrupts enabled in the current hart (machine mode).
55-
///
56-
/// This method is assumed to be called within an interrupt handler, and allows
57-
/// nested interrupts to occur. After the closure `f` is executed, the [`mstatus`]
58-
/// and [`mepc`] registers are properly restored to their previous values.
59-
///
60-
/// # Safety
61-
///
62-
/// - Do not call this function inside a critical section.
63-
/// - This method is assumed to be called within an interrupt handler.
64-
/// - Make sure to clear the interrupt flag that caused the interrupt before calling
65-
/// this method. Otherwise, the interrupt will be re-triggered before executing `f`.
39+
/// Tries to convert the generic trap cause to a target-specific trap cause
6640
#[inline]
67-
pub unsafe fn nested<F, R>(f: F) -> R
41+
pub fn try_into<I, E>(self) -> Result<Trap<I, E>, TrapError>
6842
where
69-
F: FnOnce() -> R,
43+
I: CoreInterruptNumber,
44+
E: ExceptionNumber,
7045
{
71-
let mstatus = mstatus::read();
72-
let mepc = mepc::read();
73-
74-
// enable interrupts to allow nested interrupts
75-
enable();
76-
77-
let r = f();
78-
79-
// If the interrupts were inactive before our `enable` call, then re-disable
80-
// them. Otherwise, keep them enabled
81-
if !mstatus.mie() {
82-
disable();
46+
match self {
47+
Trap::Interrupt(code) => match I::from_number(code) {
48+
Ok(interrupt) => Ok(Trap::Interrupt(interrupt)),
49+
Err(code) => Err(TrapError::InvalidInterrupt(code)),
50+
},
51+
Trap::Exception(code) => match E::from_number(code) {
52+
Ok(exception) => Ok(Trap::Exception(exception)),
53+
Err(code) => Err(TrapError::InvalidException(code)),
54+
},
8355
}
84-
85-
// Restore MSTATUS.PIE, MSTATUS.MPP, and SEPC
86-
if mstatus.mpie() {
87-
mstatus::set_mpie();
88-
}
89-
mstatus::set_mpp(mstatus.mpp());
90-
mepc::write(mepc);
91-
92-
r
9356
}
9457
}
9558

96-
pub mod supervisor {
97-
use crate::register::{sepc, sstatus};
98-
99-
/// Disables all interrupts in the current hart (supervisor mode).
100-
#[inline]
101-
pub fn disable() {
102-
// SAFETY: It is safe to disable interrupts
103-
unsafe { sstatus::clear_sie() }
104-
}
105-
106-
/// Enables all the interrupts in the current hart (supervisor mode).
107-
///
108-
/// # Safety
109-
///
110-
/// Do not call this function inside a critical section.
59+
impl<I: CoreInterruptNumber, E: ExceptionNumber> Trap<I, E> {
60+
/// Converts a target-specific trap cause to a generic trap cause
11161
#[inline]
112-
pub unsafe fn enable() {
113-
sstatus::set_sie()
62+
pub fn into(self) -> Trap<usize, usize> {
63+
Trap::from(self)
11464
}
11565

116-
/// Execute closure `f` with interrupts disabled in the current hart (supervisor mode).
117-
///
118-
/// This method does not synchronise multiple harts, so it is not suitable for
119-
/// using as a critical section. See the `critical-section` crate for a cross-platform
120-
/// way to enter a critical section which provides a `CriticalSection` token.
121-
///
122-
/// This crate provides an implementation for `critical-section` suitable for single-hart systems,
123-
/// based on disabling all interrupts. It can be enabled with the `critical-section-single-hart` feature.
66+
/// Tries to convert the generic trap cause to a target-specific trap cause
12467
#[inline]
125-
pub fn free<F, R>(f: F) -> R
126-
where
127-
F: FnOnce() -> R,
128-
{
129-
let sstatus = sstatus::read();
130-
131-
// disable interrupts
132-
disable();
133-
134-
let r = f();
135-
136-
// If the interrupts were active before our `disable` call, then re-enable
137-
// them. Otherwise, keep them disabled
138-
if sstatus.sie() {
139-
unsafe { enable() };
140-
}
141-
142-
r
143-
}
144-
145-
/// Execute closure `f` with interrupts enabled in the current hart (supervisor mode).
146-
/// This method is assumed to be called within an interrupt handler, and allows
147-
/// nested interrupts to occur. After the closure `f` is executed, the [`sstatus`]
148-
/// and [`sepc`] registers are properly restored to their previous values.
149-
///
150-
/// # Safety
151-
///
152-
/// - Do not call this function inside a critical section.
153-
/// - This method is assumed to be called within an interrupt handler.
154-
/// - Make sure to clear the interrupt flag that caused the interrupt before calling
155-
/// this method. Otherwise, the interrupt will be re-triggered before executing `f`.
156-
#[inline]
157-
pub unsafe fn nested<F, R>(f: F) -> R
158-
where
159-
F: FnOnce() -> R,
160-
{
161-
let sstatus = sstatus::read();
162-
let sepc = sepc::read();
163-
164-
// enable interrupts to allow nested interrupts
165-
enable();
166-
167-
let r = f();
168-
169-
// If the interrupts were inactive before our `enable` call, then re-disable
170-
// them. Otherwise, keep them enabled
171-
if !sstatus.sie() {
172-
disable();
173-
}
174-
175-
// Restore SSTATUS.SPIE, SSTATUS.SPP, and SEPC
176-
if sstatus.spie() {
177-
sstatus::set_spie();
178-
}
179-
sstatus::set_spp(sstatus.spp());
180-
sepc::write(sepc);
181-
182-
r
68+
pub fn try_from(trap: Trap<usize, usize>) -> Result<Self, TrapError> {
69+
trap.try_into()
18370
}
18471
}
185-
186-
#[cfg(not(feature = "s-mode"))]
187-
pub use machine::*;
188-
#[cfg(feature = "s-mode")]
189-
pub use supervisor::*;

0 commit comments

Comments
 (0)