1 // SPDX-License-Identifier: Apache-2.0 OR MIT
2
3 /*
4 Refs:
5 - https://github.com/riscv/riscv-isa-manual/blob/riscv-isa-release-8b9dc50-2024-08-30/src/machine.adoc#machine-status-mstatus-and-mstatush-registers
6 - https://github.com/riscv/riscv-isa-manual/blob/riscv-isa-release-8b9dc50-2024-08-30/src/supervisor.adoc#supervisor-status-sstatus-register
7
8 See also src/imp/riscv.rs.
9
10 Generated asm:
11 - riscv64gc https://godbolt.org/z/zTrzT1Ee7
12 */
13
14 #[cfg(not(portable_atomic_no_asm))]
15 use core::arch::asm;
16
17 pub(super) use super::super::riscv as atomic;
18
19 // Status register
20 #[cfg(not(portable_atomic_s_mode))]
21 macro_rules! status {
22 () => {
23 "mstatus"
24 };
25 }
26 #[cfg(portable_atomic_s_mode)]
27 macro_rules! status {
28 () => {
29 "sstatus"
30 };
31 }
32
33 // MIE (Machine Interrupt Enable) bit (1 << 3)
34 #[cfg(not(portable_atomic_s_mode))]
35 const MASK: State = 0x8;
36 #[cfg(not(portable_atomic_s_mode))]
37 macro_rules! mask {
38 () => {
39 "0x8"
40 };
41 }
42 // SIE (Supervisor Interrupt Enable) bit (1 << 1)
43 #[cfg(portable_atomic_s_mode)]
44 const MASK: State = 0x2;
45 #[cfg(portable_atomic_s_mode)]
46 macro_rules! mask {
47 () => {
48 "0x2"
49 };
50 }
51
52 #[cfg(target_arch = "riscv32")]
53 pub(super) type State = u32;
54 #[cfg(target_arch = "riscv64")]
55 pub(super) type State = u64;
56
57 /// Disables interrupts and returns the previous interrupt state.
58 #[inline(always)]
disable() -> State59 pub(super) fn disable() -> State {
60 let r: State;
61 // SAFETY: reading mstatus and disabling interrupts is safe.
62 // (see module-level comments of interrupt/mod.rs on the safety of using privileged instructions)
63 unsafe {
64 // Do not use `nomem` and `readonly` because prevent subsequent memory accesses from being reordered before interrupts are disabled.
65 asm!(concat!("csrrci {0}, ", status!(), ", ", mask!()), out(reg) r, options(nostack, preserves_flags));
66 }
67 r
68 }
69
70 /// Restores the previous interrupt state.
71 ///
72 /// # Safety
73 ///
74 /// The state must be the one retrieved by the previous `disable`.
75 #[inline(always)]
restore(r: State)76 pub(super) unsafe fn restore(r: State) {
77 if r & MASK != 0 {
78 // SAFETY: the caller must guarantee that the state was retrieved by the previous `disable`,
79 // and we've checked that interrupts were enabled before disabling interrupts.
80 unsafe {
81 // Do not use `nomem` and `readonly` because prevent preceding memory accesses from being reordered after interrupts are enabled.
82 asm!(concat!("csrsi ", status!(), ", ", mask!()), options(nostack, preserves_flags));
83 }
84 }
85 }
86