Skip to content

Commit c8c0bba

Browse files
Merge pull request #330 from rust-embedded/riscv-interrupts
`riscv`: Use `riscv_pac::CoreInterrupt` in `mie` register
2 parents 73635b8 + a334f8a commit c8c0bba

File tree

5 files changed

+219
-10
lines changed

5 files changed

+219
-10
lines changed

riscv/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1010
### Added
1111

1212
- New convenience `try_new` and `new` associated functions for `Mtvec` and `Stvec`.
13+
- New methods and functions for enabling core interrupts in the `mie` and `sie` registers
14+
using the `riscv_pac::CoreInterrupt` trait.
15+
- New `riscv::interrupt::{is_interrupt_enabled, disable_interrupt, enable_interrupt}` functions.
1316

1417
### Changed
1518

riscv/src/interrupt/machine.rs

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{
22
interrupt::Trap,
3-
register::{mcause, mepc, mstatus},
3+
register::{mcause, mepc, mie, mstatus},
44
};
55
use riscv_pac::{
66
result::{Error, Result},
@@ -96,18 +96,51 @@ unsafe impl ExceptionNumber for Exception {
9696
}
9797
}
9898

99-
/// Disables all interrupts in the current hart (machine mode).
99+
/// Checks if a specific core interrupt source is enabled in the current hart (machine mode).
100+
#[inline]
101+
pub fn is_interrupt_enabled<I: CoreInterruptNumber>(interrupt: I) -> bool {
102+
mie::read().is_enabled(interrupt)
103+
}
104+
105+
/// Disables interrupts for a specific core interrupt source in the current hart (machine mode).
106+
#[inline]
107+
pub fn disable_interrupt<I: CoreInterruptNumber>(interrupt: I) {
108+
mie::disable(interrupt);
109+
}
110+
111+
/// Enables interrupts for a specific core interrupt source in the current hart (machine mode).
112+
///
113+
/// # Note
114+
///
115+
/// Interrupts will only be triggered if globally enabled in the hart. To do this, use [`enable`].
116+
///
117+
/// # Safety
118+
///
119+
/// Enabling interrupts might break critical sections or other synchronization mechanisms.
120+
/// Ensure that this is called in a safe context where interrupts can be enabled.
121+
#[inline]
122+
pub unsafe fn enable_interrupt<I: CoreInterruptNumber>(interrupt: I) {
123+
mie::enable(interrupt);
124+
}
125+
126+
/// Disables interrupts globally in the current hart (machine mode).
100127
#[inline]
101128
pub fn disable() {
102129
// SAFETY: It is safe to disable interrupts
103130
unsafe { mstatus::clear_mie() }
104131
}
105132

106-
/// Enables all the interrupts in the current hart (machine mode).
133+
/// Enables interrupts globally in the current hart (machine mode).
134+
///
135+
/// # Note
136+
///
137+
/// Only enabled interrupt sources will be triggered.
138+
/// To enable specific interrupt sources, use [`enable_interrupt`].
107139
///
108140
/// # Safety
109141
///
110-
/// Do not call this function inside a critical section.
142+
/// Enabling interrupts might break critical sections or other synchronization mechanisms.
143+
/// Ensure that this is called in a safe context where interrupts can be enabled.
111144
#[inline]
112145
pub unsafe fn enable() {
113146
mstatus::set_mie()

riscv/src/interrupt/supervisor.rs

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{
22
interrupt::Trap,
3-
register::{scause, sepc, sstatus},
3+
register::{scause, sepc, sie, sstatus},
44
};
55
use riscv_pac::{
66
result::{Error, Result},
@@ -88,18 +88,52 @@ unsafe impl ExceptionNumber for Exception {
8888
}
8989
}
9090

91-
/// Disables all interrupts in the current hart (supervisor mode).
91+
/// Checks if a specific core interrupt source is enabled in the current hart (supervisor mode).
92+
#[inline]
93+
pub fn is_interrupt_enabled<I: CoreInterruptNumber>(interrupt: I) -> bool {
94+
sie::read().is_enabled(interrupt)
95+
}
96+
97+
/// Disables interrupts for a specific core interrupt source in the current hart (supervisor mode).
98+
#[inline]
99+
pub fn disable_interrupt<I: CoreInterruptNumber>(interrupt: I) {
100+
// SAFETY: it is safe to disable an interrupt source
101+
sie::disable(interrupt);
102+
}
103+
104+
/// Enables interrupts for a specific core interrupt source in the current hart (supervisor mode).
105+
///
106+
/// # Note
107+
///
108+
/// Interrupts will only be triggered if globally enabled in the hart. To do this, use [`enable`].
109+
///
110+
/// # Safety
111+
///
112+
/// Enabling interrupts might break critical sections or other synchronization mechanisms.
113+
/// Ensure that this is called in a safe context where interrupts can be enabled.
114+
#[inline]
115+
pub unsafe fn enable_interrupt<I: CoreInterruptNumber>(interrupt: I) {
116+
sie::enable(interrupt);
117+
}
118+
119+
/// Disables interrupts globally in the current hart (supervisor mode).
92120
#[inline]
93121
pub fn disable() {
94122
// SAFETY: It is safe to disable interrupts
95123
unsafe { sstatus::clear_sie() }
96124
}
97125

98-
/// Enables all the interrupts in the current hart (supervisor mode).
126+
/// Enables interrupts globally in the current hart (supervisor mode).
127+
///
128+
/// # Note
129+
///
130+
/// Only enabled interrupt sources will be triggered.
131+
/// To enable specific interrupt sources, use [`enable_interrupt`].
99132
///
100133
/// # Safety
101134
///
102-
/// Do not call this function inside a critical section.
135+
/// Enabling interrupts might break critical sections or other synchronization mechanisms.
136+
/// Ensure that this is called in a safe context where interrupts can be enabled.
103137
#[inline]
104138
pub unsafe fn enable() {
105139
sstatus::set_sie()

riscv/src/register/mie.rs

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
//! mie register
22
3+
use crate::bits::{bf_extract, bf_insert};
4+
use riscv_pac::CoreInterruptNumber;
5+
36
read_write_csr! {
47
/// `mie` register
58
Mie: 0x304,
6-
mask: 0xaaa,
9+
mask: usize::MAX,
710
}
811

912
read_write_csr_field! {
@@ -42,6 +45,26 @@ read_write_csr_field! {
4245
mext: 11,
4346
}
4447

48+
impl Mie {
49+
/// Check if a specific core interrupt source is enabled.
50+
#[inline]
51+
pub fn is_enabled<I: CoreInterruptNumber>(&self, interrupt: I) -> bool {
52+
bf_extract(self.bits, interrupt.number(), 1) != 0
53+
}
54+
55+
/// Enable a specific core interrupt source.
56+
#[inline]
57+
pub fn enable<I: CoreInterruptNumber>(&mut self, interrupt: I) {
58+
self.bits = bf_insert(self.bits, interrupt.number(), 1, 1);
59+
}
60+
61+
/// Disable a specific core interrupt source.
62+
#[inline]
63+
pub fn disable<I: CoreInterruptNumber>(&mut self, interrupt: I) {
64+
self.bits = bf_insert(self.bits, interrupt.number(), 1, 0);
65+
}
66+
}
67+
4568
set!(0x304);
4669
clear!(0x304);
4770

@@ -64,9 +87,28 @@ set_clear_csr!(
6487
/// Machine External Interrupt Enable
6588
, set_mext, clear_mext, 1 << 11);
6689

90+
/// Disables a specific core interrupt source.
91+
#[inline]
92+
pub fn disable<I: CoreInterruptNumber>(interrupt: I) {
93+
// SAFETY: it is safe to disable an interrupt source
94+
unsafe { _clear(1 << interrupt.number()) };
95+
}
96+
97+
/// Enables a specific core interrupt source.
98+
///
99+
/// # Safety
100+
///
101+
/// Enabling interrupts might break critical sections or other synchronization mechanisms.
102+
/// Ensure that this is called in a safe context where interrupts can be enabled.
103+
#[inline]
104+
pub unsafe fn enable<I: CoreInterruptNumber>(interrupt: I) {
105+
unsafe { _set(1 << interrupt.number()) };
106+
}
107+
67108
#[cfg(test)]
68109
mod tests {
69110
use super::*;
111+
use crate::interrupt::machine::Interrupt;
70112

71113
#[test]
72114
fn test_mie() {
@@ -79,4 +121,39 @@ mod tests {
79121
test_csr_field!(m, sext);
80122
test_csr_field!(m, mext);
81123
}
124+
125+
#[test]
126+
fn test_mie_interrupt() {
127+
let mut m = Mie::from_bits(0);
128+
129+
m.enable(Interrupt::SupervisorSoft);
130+
assert!(m.is_enabled(Interrupt::SupervisorSoft));
131+
m.disable(Interrupt::SupervisorSoft);
132+
assert!(!m.is_enabled(Interrupt::SupervisorSoft));
133+
134+
m.enable(Interrupt::MachineSoft);
135+
assert!(m.is_enabled(Interrupt::MachineSoft));
136+
m.disable(Interrupt::MachineSoft);
137+
assert!(!m.is_enabled(Interrupt::MachineSoft));
138+
139+
m.enable(Interrupt::SupervisorTimer);
140+
assert!(m.is_enabled(Interrupt::SupervisorTimer));
141+
m.disable(Interrupt::SupervisorTimer);
142+
assert!(!m.is_enabled(Interrupt::SupervisorTimer));
143+
144+
m.enable(Interrupt::MachineTimer);
145+
assert!(m.is_enabled(Interrupt::MachineTimer));
146+
m.disable(Interrupt::MachineTimer);
147+
assert!(!m.is_enabled(Interrupt::MachineTimer));
148+
149+
m.enable(Interrupt::SupervisorExternal);
150+
assert!(m.is_enabled(Interrupt::SupervisorExternal));
151+
m.disable(Interrupt::SupervisorExternal);
152+
assert!(!m.is_enabled(Interrupt::SupervisorExternal));
153+
154+
m.enable(Interrupt::MachineExternal);
155+
assert!(m.is_enabled(Interrupt::MachineExternal));
156+
m.disable(Interrupt::MachineExternal);
157+
assert!(!m.is_enabled(Interrupt::MachineExternal));
158+
}
82159
}

riscv/src/register/sie.rs

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
//! sie register
22
3+
use crate::bits::{bf_extract, bf_insert};
4+
use riscv_pac::CoreInterruptNumber;
5+
36
read_write_csr! {
47
/// sie register
58
Sie: 0x104,
6-
mask: 0x222,
9+
mask: usize::MAX,
710
}
811

912
read_write_csr_field! {
@@ -24,6 +27,26 @@ read_write_csr_field! {
2427
sext: 9,
2528
}
2629

30+
impl Sie {
31+
/// Check if a specific core interrupt source is enabled.
32+
#[inline]
33+
pub fn is_enabled<I: CoreInterruptNumber>(&self, interrupt: I) -> bool {
34+
bf_extract(self.bits, interrupt.number(), 1) != 0
35+
}
36+
37+
/// Enable a specific core interrupt source.
38+
#[inline]
39+
pub fn enable<I: CoreInterruptNumber>(&mut self, interrupt: I) {
40+
self.bits = bf_insert(self.bits, interrupt.number(), 1, 1);
41+
}
42+
43+
/// Disable a specific core interrupt source.
44+
#[inline]
45+
pub fn disable<I: CoreInterruptNumber>(&mut self, interrupt: I) {
46+
self.bits = bf_insert(self.bits, interrupt.number(), 1, 0);
47+
}
48+
}
49+
2750
set!(0x104);
2851
clear!(0x104);
2952

@@ -37,9 +60,28 @@ set_clear_csr!(
3760
/// Supervisor External Interrupt Enable
3861
, set_sext, clear_sext, 1 << 9);
3962

63+
/// Disables a specific core interrupt source.
64+
#[inline]
65+
pub fn disable<I: CoreInterruptNumber>(interrupt: I) {
66+
// SAFETY: it is safe to disable an interrupt source
67+
unsafe { _clear(1 << interrupt.number()) };
68+
}
69+
70+
/// Enables a specific core interrupt source.
71+
///
72+
/// # Safety
73+
///
74+
/// Enabling interrupts might break critical sections or other synchronization mechanisms.
75+
/// Ensure that this is called in a safe context where interrupts can be enabled.
76+
#[inline]
77+
pub unsafe fn enable<I: CoreInterruptNumber>(interrupt: I) {
78+
unsafe { _set(1 << interrupt.number()) };
79+
}
80+
4081
#[cfg(test)]
4182
mod tests {
4283
use super::*;
84+
use crate::interrupt::supervisor::Interrupt;
4385

4486
#[test]
4587
fn test_sie() {
@@ -49,4 +91,24 @@ mod tests {
4991
test_csr_field!(sie, stimer);
5092
test_csr_field!(sie, sext);
5193
}
94+
95+
#[test]
96+
fn test_sie_interrupt() {
97+
let mut s = Sie::from_bits(0);
98+
99+
s.enable(Interrupt::SupervisorSoft);
100+
assert!(s.is_enabled(Interrupt::SupervisorSoft));
101+
s.disable(Interrupt::SupervisorSoft);
102+
assert!(!s.is_enabled(Interrupt::SupervisorSoft));
103+
104+
s.enable(Interrupt::SupervisorTimer);
105+
assert!(s.is_enabled(Interrupt::SupervisorTimer));
106+
s.disable(Interrupt::SupervisorTimer);
107+
assert!(!s.is_enabled(Interrupt::SupervisorTimer));
108+
109+
s.enable(Interrupt::SupervisorExternal);
110+
assert!(s.is_enabled(Interrupt::SupervisorExternal));
111+
s.disable(Interrupt::SupervisorExternal);
112+
assert!(!s.is_enabled(Interrupt::SupervisorExternal));
113+
}
52114
}

0 commit comments

Comments
 (0)