-
-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
44: interrupt: Various improvements r=taiki-e a=taiki-e - Support RISC-V supervisor mode under `portable_atomic_s_mode` cfg > On RISC-V without A-extension, this generates code for machine-mode (M-mode) by default. If you pass the `--cfg portable_atomic_s_mode` together, this generates code for supervisor-mode (S-mode). In particular, `qemu-system-riscv*` uses [OpenSBI](https://github.com/riscv-software-src/opensbi) as the default firmware. - Support disabling FIQs on pre-v6 ARM under `portable_atomic_disable_fiq` cfg > On pre-v6 ARM, this disables only IRQs by default. For many systems (e.g., GBA) this is enough. If the system need to disable both IRQs and FIQs, you need to pass the `--cfg portable_atomic_disable_fiq` together. - Interrupt-related documentation improvements - [README.md](https://github.com/taiki-e/portable-atomic/blob/18961fab6716c3fe45e89cbf2abf46c6a10fad21/README.md#optional-cfg) - [src/imp/interrupt/README.md](https://github.com/taiki-e/portable-atomic/blob/18961fab6716c3fe45e89cbf2abf46c6a10fad21/src/imp/interrupt/README.md) - Defer mask until just before branch > This does not change the code generation, but in the actual generated code the mask is deferred until just before the branch, like this. Since there has been some misleading discussion about this in the past, we will use code that more closely matches the generated code. For MSP430 and AVR, it will be done in #40. Co-authored-by: Taiki Endo <[email protected]>
- Loading branch information
Showing
8 changed files
with
142 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Implementation of disabling interrupts | ||
|
||
This module is used to provide atomic CAS for targets where atomic CAS is not available in the standard library. | ||
|
||
- On MSP430 and AVR, they are always single-core, so this module is always used. | ||
- On ARMv6-M (thumbv6m), pre-v6 ARM (e.g., thumbv4t, thumbv5te), RISC-V without A-extension, they could be multi-core, so this module is used when `--cfg portable_atomic_unsafe_assume_single_core` is enabled. | ||
|
||
The implementation uses privileged instructions to disable interrupts, so it usually doesn't work on unprivileged mode. | ||
Enabling this cfg in an environment where privileged instructions are not available, or if the instructions used are not sufficient to disable interrupts in the system, it is also usually considered **unsound**, although the details are system-dependent. | ||
|
||
For some targets, the implementation can be changed by explicitly enabling cfg. | ||
|
||
- On ARMv6-M, this disables interrupts by modifying the PRIMASK register. | ||
- On pre-v6 ARM, this disables interrupts by modifying the I (IRQ mask) bit of the CPSR. | ||
- On pre-v6 ARM with `--cfg portable_atomic_disable_fiq`, this disables interrupts by modifying the I (IRQ mask) bit and F (FIQ mask) bit of the CPSR. | ||
- On RISC-V (without A-extension), this disables interrupts by modifying the MIE (Machine Interrupt Enable) bit of the `mstatus` register. | ||
- On RISC-V (without A-extension) with `--cfg portable_atomic_s_mode`, this disables interrupts by modifying the SIE (Supervisor Interrupt Enable) bit of the `sstatus` register. | ||
- On MSP430, this disables interrupts by modifying the GIE (Global Interrupt Enable) bit of the status register (SR). | ||
- On AVR, this disables interrupts by modifying the I (Global Interrupt Enable) bit of the status register (SREG). | ||
|
||
Feel free to submit an issue if your target is not supported yet. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,41 +1,73 @@ | ||
// Based on asm generated for functions of interrupt module of https://github.com/rust-embedded/riscv. | ||
// Refs: | ||
// - https://five-embeddev.com/riscv-isa-manual/latest/machine.html#machine-status-registers-mstatus-and-mstatush | ||
// - https://five-embeddev.com/riscv-isa-manual/latest/supervisor.html#sstatus | ||
// | ||
// Generated asm: | ||
// - riscv64gc https://godbolt.org/z/TnPvPa4c4 | ||
|
||
#[cfg(not(portable_atomic_no_asm))] | ||
use core::arch::asm; | ||
|
||
pub(super) use super::super::riscv as atomic; | ||
|
||
// Status register | ||
#[cfg(not(portable_atomic_s_mode))] | ||
macro_rules! status { | ||
() => { | ||
"mstatus" | ||
}; | ||
} | ||
#[cfg(portable_atomic_s_mode)] | ||
macro_rules! status { | ||
() => { | ||
"sstatus" | ||
}; | ||
} | ||
|
||
// MIE (Machine Interrupt Enable) bit (1 << 3) | ||
#[cfg(not(portable_atomic_s_mode))] | ||
const MASK: usize = 0x8; | ||
#[cfg(not(portable_atomic_s_mode))] | ||
macro_rules! mask { | ||
() => { | ||
"0x8" | ||
}; | ||
} | ||
// SIE (Supervisor Interrupt Enable) bit (1 << 1) | ||
#[cfg(portable_atomic_s_mode)] | ||
const MASK: usize = 0x2; | ||
#[cfg(portable_atomic_s_mode)] | ||
macro_rules! mask { | ||
() => { | ||
"0x2" | ||
}; | ||
} | ||
|
||
#[derive(Clone, Copy)] | ||
pub(super) struct WasEnabled(bool); | ||
pub(super) struct State(usize); | ||
|
||
/// Disables interrupts and returns the previous interrupt state. | ||
#[inline] | ||
pub(super) fn disable() -> WasEnabled { | ||
pub(super) fn disable() -> State { | ||
let r: usize; | ||
// SAFETY: reading mstatus and disabling interrupts is safe. | ||
// (see module-level comments of interrupt/mod.rs on the safety of using privileged instructions) | ||
unsafe { | ||
// Do not use `nomem` and `readonly` because prevent subsequent memory accesses from being reordered before interrupts are disabled. | ||
asm!( | ||
"csrr {0}, mstatus", | ||
"csrci mstatus, 0x8", | ||
out(reg) r, | ||
options(nostack, preserves_flags), | ||
); | ||
asm!(concat!("csrrci {0}, ", status!(), ", ", mask!()), out(reg) r, options(nostack, preserves_flags)); | ||
} | ||
// MIE (Machine Interrupt Enable) bit (1 << 3) | ||
WasEnabled(r & 0x8 != 0) | ||
State(r) | ||
} | ||
|
||
/// Restores the previous interrupt state. | ||
#[inline] | ||
pub(super) unsafe fn restore(WasEnabled(was_enabled): WasEnabled) { | ||
if was_enabled { | ||
pub(super) unsafe fn restore(State(r): State) { | ||
if r & MASK != 0 { | ||
// SAFETY: the caller must guarantee that the state was retrieved by the previous `disable`, | ||
// and we've checked that interrupts were enabled before disabling interrupts. | ||
unsafe { | ||
// Do not use `nomem` and `readonly` because prevent preceding memory accesses from being reordered after interrupts are enabled. | ||
asm!("csrsi mstatus, 0x8", options(nostack, preserves_flags)); | ||
asm!(concat!("csrsi ", status!(), ", ", mask!()), options(nostack, preserves_flags)); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters