Skip to content

riscv: Use riscv_pac::CoreInterrupt in mie register #330

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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::{is_interrupt_enabled, disable_interrupt, enable_interrupt}` functions.

### Changed

Expand Down
41 changes: 37 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,51 @@ unsafe impl ExceptionNumber for Exception {
}
}

/// Disables all interrupts in the current hart (machine mode).
/// Checks if a specific core interrupt source is enabled in the current hart (machine mode).
#[inline]
pub fn is_interrupt_enabled<I: CoreInterruptNumber>(interrupt: I) -> bool {
mie::read().is_enabled(interrupt)
}

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

/// Enables interrupts for a specific core interrupt source in the current hart (machine mode).
///
/// # Note
///
/// Interrupts will only be triggered if globally enabled in the hart. To do this, use [`enable`].
///
/// # 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);
}

/// 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).
///
/// # Note
///
/// Only enabled interrupt sources will be triggered.
/// To enable specific interrupt sources, use [`enable_interrupt`].
///
/// # 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
42 changes: 38 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,52 @@ unsafe impl ExceptionNumber for Exception {
}
}

/// Disables all interrupts in the current hart (supervisor mode).
/// Checks if a specific core interrupt source is enabled in the current hart (supervisor mode).
#[inline]
pub fn is_interrupt_enabled<I: CoreInterruptNumber>(interrupt: I) -> bool {
sie::read().is_enabled(interrupt)
}

/// 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);
}

/// Enables interrupts for a specific core interrupt source in the current hart (supervisor mode).
///
/// # Note
///
/// Interrupts will only be triggered if globally enabled in the hart. To do this, use [`enable`].
///
/// # 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);
}

/// 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).
///
/// # Note
///
/// Only enabled interrupt sources will be triggered.
/// To enable specific interrupt sources, use [`enable_interrupt`].
///
/// # 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
79 changes: 78 additions & 1 deletion riscv/src/register/mie.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
//! mie register

use crate::bits::{bf_extract, bf_insert};
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 +45,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 {
bf_extract(self.bits, interrupt.number(), 1) != 0
}

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

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

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

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

/// Disables a specific core interrupt source.
#[inline]
pub fn disable<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<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 +121,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));
}
}
64 changes: 63 additions & 1 deletion riscv/src/register/sie.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
//! sie register

use crate::bits::{bf_extract, bf_insert};
use riscv_pac::CoreInterruptNumber;

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

read_write_csr_field! {
Expand All @@ -24,6 +27,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 {
bf_extract(self.bits, interrupt.number(), 1) != 0
}

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

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

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

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

/// Disables a specific core interrupt source.
#[inline]
pub fn disable<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<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 +91,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