Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions riscv/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Added

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

### Changed

Expand Down
32 changes: 28 additions & 4 deletions riscv/src/interrupt/machine.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
interrupt::Trap,
register::{mcause, mepc, mstatus},
register::{mcause, mepc, mie, mstatus},
};
use riscv_pac::{
result::{Error, Result},
Expand Down Expand Up @@ -96,18 +96,42 @@ unsafe impl ExceptionNumber for Exception {
}
}

/// Disables all interrupts in the current hart (machine mode).
/// Disables interrupts for a specific core interrupt source in the current hart (machine mode).
#[inline]
pub fn disable_interrupt<I: CoreInterruptNumber>(interrupt: I) {
// SAFETY: it is safe to disable an interrupt source
mie::disable_interrupt(interrupt);
}

/// Enables interrupts for a specific core interrupt source in the current hart (machine mode).
///
/// # Note
///
/// Interrupts will only be triggered if interrupts are globally enabled in the hart.
/// To do this, you must call [`enable`] after enabling the interrupt.
///
/// # Safety
///
/// Enabling interrupts might break critical sections or other synchronization mechanisms.
/// Ensure that this is called in a safe context where interrupts can be enabled.
#[inline]
pub unsafe fn enable_interrupt<I: CoreInterruptNumber>(interrupt: I) {
mie::enable_interrupt(interrupt);
}

/// Disables interrupts globally in the current hart (machine mode).
#[inline]
pub fn disable() {
// SAFETY: It is safe to disable interrupts
unsafe { mstatus::clear_mie() }
}

/// Enables all the interrupts in the current hart (machine mode).
/// Enables interrupts globally in the current hart (machine mode).
///
/// # Safety
///
/// Do not call this function inside a critical section.
/// Enabling interrupts might break critical sections or other synchronization mechanisms.
/// Ensure that this is called in a safe context where interrupts can be enabled.
#[inline]
pub unsafe fn enable() {
mstatus::set_mie()
Expand Down
32 changes: 28 additions & 4 deletions riscv/src/interrupt/supervisor.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
interrupt::Trap,
register::{scause, sepc, sstatus},
register::{scause, sepc, sie, sstatus},
};
use riscv_pac::{
result::{Error, Result},
Expand Down Expand Up @@ -88,18 +88,42 @@ unsafe impl ExceptionNumber for Exception {
}
}

/// Disables all interrupts in the current hart (supervisor mode).
/// Disables interrupts for a specific core interrupt source in the current hart (supervisor mode).
#[inline]
pub fn disable_interrupt<I: CoreInterruptNumber>(interrupt: I) {
// SAFETY: it is safe to disable an interrupt source
sie::disable_interrupt(interrupt);
}

/// Enables interrupts for a specific core interrupt source in the current hart (supervisor mode).
///
/// # Note
///
/// Interrupts will only be triggered if interrupts are globally enabled in the hart.
/// To do this, you must call [`enable`] after enabling the interrupt.
///
/// # Safety
///
/// Enabling interrupts might break critical sections or other synchronization mechanisms.
/// Ensure that this is called in a safe context where interrupts can be enabled.
#[inline]
pub unsafe fn enable_interrupt<I: CoreInterruptNumber>(interrupt: I) {
sie::enable_interrupt(interrupt);
}

/// Disables interrupts globally in the current hart (supervisor mode).
#[inline]
pub fn disable() {
// SAFETY: It is safe to disable interrupts
unsafe { sstatus::clear_sie() }
}

/// Enables all the interrupts in the current hart (supervisor mode).
/// Enables interrupts globally in the current hart (supervisor mode).
///
/// # Safety
///
/// Do not call this function inside a critical section.
/// Enabling interrupts might break critical sections or other synchronization mechanisms.
/// Ensure that this is called in a safe context where interrupts can be enabled.
#[inline]
pub unsafe fn enable() {
sstatus::set_sie()
Expand Down
78 changes: 77 additions & 1 deletion riscv/src/register/mie.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
//! mie register

use riscv_pac::CoreInterruptNumber;

read_write_csr! {
/// `mie` register
Mie: 0x304,
mask: 0xaaa,
mask: usize::MAX,
}

read_write_csr_field! {
Expand Down Expand Up @@ -42,6 +44,26 @@ read_write_csr_field! {
mext: 11,
}

impl Mie {
/// Check if a specific core interrupt source is enabled.
#[inline]
pub fn is_enabled<I: CoreInterruptNumber>(&self, interrupt: I) -> bool {
(self.bits & (1 << interrupt.number())) != 0
}

/// Enable a specific core interrupt source.
#[inline]
pub fn enable<I: CoreInterruptNumber>(&mut self, interrupt: I) {
self.bits |= 1 << interrupt.number();
}

/// Disable a specific core interrupt source.
#[inline]
pub fn disable<I: CoreInterruptNumber>(&mut self, interrupt: I) {
self.bits &= !(1 << interrupt.number());
}
}

set!(0x304);
clear!(0x304);

Expand All @@ -64,9 +86,28 @@ set_clear_csr!(
/// Machine External Interrupt Enable
, set_mext, clear_mext, 1 << 11);

/// Disables a specific core interrupt source.
#[inline]
pub fn disable_interrupt<I: CoreInterruptNumber>(interrupt: I) {
// SAFETY: it is safe to disable an interrupt source
unsafe { _clear(1 << interrupt.number()) };
}

/// Enables a specific core interrupt source.
///
/// # Safety
///
/// Enabling interrupts might break critical sections or other synchronization mechanisms.
/// Ensure that this is called in a safe context where interrupts can be enabled.
#[inline]
pub unsafe fn enable_interrupt<I: CoreInterruptNumber>(interrupt: I) {
unsafe { _set(1 << interrupt.number()) };
}

#[cfg(test)]
mod tests {
use super::*;
use crate::interrupt::machine::Interrupt;

#[test]
fn test_mie() {
Expand All @@ -79,4 +120,39 @@ mod tests {
test_csr_field!(m, sext);
test_csr_field!(m, mext);
}

#[test]
fn test_mie_interrupt() {
let mut m = Mie::from_bits(0);

m.enable(Interrupt::SupervisorSoft);
assert!(m.is_enabled(Interrupt::SupervisorSoft));
m.disable(Interrupt::SupervisorSoft);
assert!(!m.is_enabled(Interrupt::SupervisorSoft));

m.enable(Interrupt::MachineSoft);
assert!(m.is_enabled(Interrupt::MachineSoft));
m.disable(Interrupt::MachineSoft);
assert!(!m.is_enabled(Interrupt::MachineSoft));

m.enable(Interrupt::SupervisorTimer);
assert!(m.is_enabled(Interrupt::SupervisorTimer));
m.disable(Interrupt::SupervisorTimer);
assert!(!m.is_enabled(Interrupt::SupervisorTimer));

m.enable(Interrupt::MachineTimer);
assert!(m.is_enabled(Interrupt::MachineTimer));
m.disable(Interrupt::MachineTimer);
assert!(!m.is_enabled(Interrupt::MachineTimer));

m.enable(Interrupt::SupervisorExternal);
assert!(m.is_enabled(Interrupt::SupervisorExternal));
m.disable(Interrupt::SupervisorExternal);
assert!(!m.is_enabled(Interrupt::SupervisorExternal));

m.enable(Interrupt::MachineExternal);
assert!(m.is_enabled(Interrupt::MachineExternal));
m.disable(Interrupt::MachineExternal);
assert!(!m.is_enabled(Interrupt::MachineExternal));
}
}
63 changes: 62 additions & 1 deletion riscv/src/register/sie.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
//! sie register

use riscv_pac::CoreInterruptNumber;

read_write_csr! {
/// sie register
Sie: 0x104,
mask: 0x222,
mask: usize::MAX,
}

read_write_csr_field! {
Expand All @@ -24,6 +26,26 @@ read_write_csr_field! {
sext: 9,
}

impl Sie {
/// Check if a specific core interrupt source is enabled.
#[inline]
pub fn is_enabled<I: CoreInterruptNumber>(&self, interrupt: I) -> bool {
(self.bits & (1 << interrupt.number())) != 0
}

/// Enable a specific core interrupt source.
#[inline]
pub fn enable<I: CoreInterruptNumber>(&mut self, interrupt: I) {
self.bits |= 1 << interrupt.number();
}

/// Disable a specific core interrupt source.
#[inline]
pub fn disable<I: CoreInterruptNumber>(&mut self, interrupt: I) {
self.bits &= !(1 << interrupt.number());
}
}

set!(0x104);
clear!(0x104);

Expand All @@ -37,9 +59,28 @@ set_clear_csr!(
/// Supervisor External Interrupt Enable
, set_sext, clear_sext, 1 << 9);

/// Disables a specific core interrupt source.
#[inline]
pub fn disable_interrupt<I: CoreInterruptNumber>(interrupt: I) {
// SAFETY: it is safe to disable an interrupt source
unsafe { _clear(1 << interrupt.number()) };
}

/// Enables a specific core interrupt source.
///
/// # Safety
///
/// Enabling interrupts might break critical sections or other synchronization mechanisms.
/// Ensure that this is called in a safe context where interrupts can be enabled.
#[inline]
pub unsafe fn enable_interrupt<I: CoreInterruptNumber>(interrupt: I) {
unsafe { _set(1 << interrupt.number()) };
}

#[cfg(test)]
mod tests {
use super::*;
use crate::interrupt::supervisor::Interrupt;

#[test]
fn test_sie() {
Expand All @@ -49,4 +90,24 @@ mod tests {
test_csr_field!(sie, stimer);
test_csr_field!(sie, sext);
}

#[test]
fn test_sie_interrupt() {
let mut s = Sie::from_bits(0);

s.enable(Interrupt::SupervisorSoft);
assert!(s.is_enabled(Interrupt::SupervisorSoft));
s.disable(Interrupt::SupervisorSoft);
assert!(!s.is_enabled(Interrupt::SupervisorSoft));

s.enable(Interrupt::SupervisorTimer);
assert!(s.is_enabled(Interrupt::SupervisorTimer));
s.disable(Interrupt::SupervisorTimer);
assert!(!s.is_enabled(Interrupt::SupervisorTimer));

s.enable(Interrupt::SupervisorExternal);
assert!(s.is_enabled(Interrupt::SupervisorExternal));
s.disable(Interrupt::SupervisorExternal);
assert!(!s.is_enabled(Interrupt::SupervisorExternal));
}
}
Loading