From b68560da22c024d046acfab765485f975c70e562 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas?= Date: Mon, 4 Dec 2023 18:02:24 +0100 Subject: [PATCH 1/4] riscv-pac crate --- .github/workflows/changelog.yaml | 10 ++++ Cargo.toml | 1 + riscv-pac/CHANGELOG.md | 12 +++++ riscv-pac/Cargo.toml | 19 ++++++++ riscv-pac/README.md | 40 ++++++++++++++++ riscv-pac/src/lib.rs | 79 ++++++++++++++++++++++++++++++++ 6 files changed, 161 insertions(+) create mode 100644 riscv-pac/CHANGELOG.md create mode 100644 riscv-pac/Cargo.toml create mode 100644 riscv-pac/README.md create mode 100644 riscv-pac/src/lib.rs diff --git a/.github/workflows/changelog.yaml b/.github/workflows/changelog.yaml index 85ccda85..86541174 100644 --- a/.github/workflows/changelog.yaml +++ b/.github/workflows/changelog.yaml @@ -21,6 +21,8 @@ jobs: - 'riscv/**' riscv-rt: - 'riscv-rt/**' + riscv-pac: + - 'riscv-pac/**' - name: Check for CHANGELOG.md (riscv) if: steps.changes.outputs.riscv == 'true' @@ -37,3 +39,11 @@ jobs: changeLogPath: ./riscv-rt/CHANGELOG.md skipLabels: 'skip changelog' missingUpdateErrorMessage: 'Please add a changelog entry in the riscv-rt/CHANGELOG.md file.' + + - name: Check for CHANGELOG.md (riscv-pac) + if: steps.changes.outputs.riscv-pac == 'true' + uses: dangoslen/changelog-enforcer@v3 + with: + changeLogPath: ./riscv-pac/CHANGELOG.md + skipLabels: 'skip changelog' + missingUpdateErrorMessage: 'Please add a changelog entry in the riscv-pac/CHANGELOG.md file.' diff --git a/Cargo.toml b/Cargo.toml index 4533b2e7..b97d6de3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,5 +2,6 @@ resolver = "2" members = [ "riscv", + "riscv-pac", "riscv-rt", ] diff --git a/riscv-pac/CHANGELOG.md b/riscv-pac/CHANGELOG.md new file mode 100644 index 00000000..d17dc4a1 --- /dev/null +++ b/riscv-pac/CHANGELOG.md @@ -0,0 +1,12 @@ +# Change Log + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/). + +## [Unreleased] + +### Added + +- Add `InterruptNumber`, `PriorityNumber`, and `HartIdNumber` traits. diff --git a/riscv-pac/Cargo.toml b/riscv-pac/Cargo.toml new file mode 100644 index 00000000..1e8d5cc3 --- /dev/null +++ b/riscv-pac/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "riscv-pac" +version = "0.1.0" +edition = "2021" +rust-version = "1.60" +repository = "https://github.com/rust-embedded/riscv" +authors = ["The RISC-V Team "] +categories = ["embedded", "hardware-support", "no-std"] +description = "Low level access to RISC-V processors" +documentation = "https://docs.rs/riscv-pac" +keywords = ["riscv", "register", "peripheral"] +license = "ISC" + +[package.metadata.docs.rs] +default-target = "riscv64imac-unknown-none-elf" +targets = [ + "riscv32i-unknown-none-elf", "riscv32imc-unknown-none-elf", "riscv32imac-unknown-none-elf", + "riscv64imac-unknown-none-elf", "riscv64gc-unknown-none-elf", +] diff --git a/riscv-pac/README.md b/riscv-pac/README.md new file mode 100644 index 00000000..61c50447 --- /dev/null +++ b/riscv-pac/README.md @@ -0,0 +1,40 @@ +[![crates.io](https://img.shields.io/crates/d/riscv.svg)](https://crates.io/crates/riscv) +[![crates.io](https://img.shields.io/crates/v/riscv.svg)](https://crates.io/crates/riscv) + +# `riscv-pac` + +> Target-specific traits to be implemented by PACs + +This project is developed and maintained by the [RISC-V team][team]. + +## [Documentation](https://docs.rs/crate/riscv) + +## Minimum Supported Rust Version (MSRV) + +This crate is guaranteed to compile on stable Rust 1.60 and up. It *might* +compile with older versions but that may change in any new patch release. + +## License + +Copyright 2023-2024s [RISC-V team][team] + +Permission to use, copy, modify, and/or distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. + +## Code of Conduct + +Contribution to this crate is organized under the terms of the [Rust Code of +Conduct][CoC], the maintainer of this crate, the [RISC-V team][team], promises +to intervene to uphold that code of conduct. + +[CoC]: CODE_OF_CONDUCT.md +[team]: https://github.com/rust-embedded/wg#the-risc-v-team diff --git a/riscv-pac/src/lib.rs b/riscv-pac/src/lib.rs new file mode 100644 index 00000000..934e7aad --- /dev/null +++ b/riscv-pac/src/lib.rs @@ -0,0 +1,79 @@ +#![no_std] + +/// Trait for enums of target-specific external interrupt numbers. +/// +/// This trait should be implemented by a peripheral access crate (PAC) +/// on its enum of available external interrupts for a specific device. +/// Each variant must convert to a `u16` of its interrupt number. +/// +/// # Safety +/// +/// * This trait must only be implemented on a PAC of a RISC-V target. +/// * This trait must only be implemented on enums of external interrupts. +/// * Each enum variant must represent a distinct value (no duplicates are permitted), +/// * Each enum variant must always return the same value (do not change at runtime). +/// * All the interrupt numbers must be less than or equal to `MAX_INTERRUPT_NUMBER`. +/// * `MAX_INTERRUPT_NUMBER` must coincide with the highest allowed interrupt number. +pub unsafe trait InterruptNumber: Copy { + /// Highest number assigned to an interrupt source. + const MAX_INTERRUPT_NUMBER: u16; + + /// Converts an interrupt source to its corresponding number. + fn number(self) -> u16; + + /// Tries to convert a number to a valid interrupt source. + /// If the conversion fails, it returns an error with the number back. + fn from_number(value: u16) -> Result; +} + +/// Trait for enums of priority levels. +/// +/// This trait should be implemented by a peripheral access crate (PAC) +/// on its enum of available priority numbers for a specific device. +/// Each variant must convert to a `u8` of its priority level. +/// +/// # Safety +/// +/// * This trait must only be implemented on a PAC of a RISC-V target. +/// * This trait must only be implemented on enums of priority levels. +/// * Each enum variant must represent a distinct value (no duplicates are permitted). +/// * Each enum variant must always return the same value (do not change at runtime). +/// * All the priority level numbers must be less than or equal to `MAX_PRIORITY_NUMBER`. +/// * `MAX_PRIORITY_NUMBER` must coincide with the highest allowed priority number. +pub unsafe trait PriorityNumber: Copy { + /// Number assigned to the highest priority level. + const MAX_PRIORITY_NUMBER: u8; + + /// Converts a priority level to its corresponding number. + fn number(self) -> u8; + + /// Tries to convert a number to a valid priority level. + /// If the conversion fails, it returns an error with the number back. + fn from_number(value: u8) -> Result; +} + +/// Trait for enums of HART identifiers. +/// +/// This trait should be implemented by a peripheral access crate (PAC) +/// on its enum of available HARTs for a specific device. +/// Each variant must convert to a `u16` of its HART ID number. +/// +/// # Safety +/// +/// * This trait must only be implemented on a PAC of a RISC-V target. +/// * This trait must only be implemented on enums of HART IDs. +/// * Each enum variant must represent a distinct value (no duplicates are permitted), +/// * Each anum variant must always return the same value (do not change at runtime). +/// * All the HART ID numbers must be less than or equal to `MAX_HART_ID_NUMBER`. +/// * `MAX_HART_ID_NUMBER` must coincide with the highest allowed HART ID number. +pub unsafe trait HartIdNumber: Copy { + /// Highest number assigned to a context. + const MAX_HART_ID_NUMBER: u16; + + /// Converts a HART ID to its corresponding number. + fn number(self) -> u16; + + /// Tries to convert a number to a valid HART ID. + /// If the conversion fails, it returns an error with the number back. + fn from_number(value: u16) -> Result; +} From 41c50dd49e0077db3701f7a8210d3c9f8e6ff3ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas?= Date: Mon, 4 Dec 2023 19:04:35 +0100 Subject: [PATCH 2/4] support for S-mode interrupts --- .github/workflows/riscv.yaml | 8 +- riscv/CHANGELOG.md | 4 + riscv/Cargo.toml | 1 + riscv/src/critical_section.rs | 11 ++- riscv/src/interrupt.rs | 140 ++++++++++++++++++++++------------ riscv/src/lib.rs | 7 ++ 6 files changed, 118 insertions(+), 53 deletions(-) diff --git a/.github/workflows/riscv.yaml b/.github/workflows/riscv.yaml index e2156dfe..c086564e 100644 --- a/.github/workflows/riscv.yaml +++ b/.github/workflows/riscv.yaml @@ -1,6 +1,6 @@ on: push: - branches: [ master ] + branches: [ master, riscv-pac ] pull_request: merge_group: @@ -31,8 +31,12 @@ jobs: with: toolchain: ${{ matrix.toolchain }} targets: ${{ matrix.target }} - - name: Build (no features) + - name: Build (M-mode) run: cargo build --package riscv --target ${{ matrix.target }} + - name: Build (M-mode, critical section) + run: cargo build --package riscv --target ${{ matrix.target }} --features=critical-section-single-hart + - name: Build (S-mode) + run: cargo build --package riscv --target ${{ matrix.target }} --features=s-mode - name: Build (all features) run: cargo build --package riscv --target ${{ matrix.target }} --all-features diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index ab12ce7b..9d5edebe 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added +- `s-mode` feature for reexporting `machine::supervisor` or `interrupt::supervisor` to `interrupt` +- Support for supervisor-level interrupts in `interrupt::supervisor` - Add CI workflow to check that CHANGELOG.md file has been modified in PRs - Add `read_csr_as_rv32`, `set_rv32`, and `clear_rv32` macros - Add `mstatus::uxl` and `mstatus::sxl` @@ -20,6 +22,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed +- `critical-section` implementation depends on `s-mode` feature +- machine-level interrupt functions moved to `interrupt::machine` - Cargo workspace for riscv and riscv-rt - Update `embedded-hal` dependency to v1.0.0-rc.2 (bumps MSRV to 1.60) - `misa::MXL` renamed to `misa::XLEN` diff --git a/riscv/Cargo.toml b/riscv/Cargo.toml index 8e126fe7..c2d7f3a5 100644 --- a/riscv/Cargo.toml +++ b/riscv/Cargo.toml @@ -20,6 +20,7 @@ targets = [ ] [features] +s-mode = [] critical-section-single-hart = ["critical-section/restore-state-bool"] [dependencies] diff --git a/riscv/src/critical_section.rs b/riscv/src/critical_section.rs index b52e2373..908daec7 100644 --- a/riscv/src/critical_section.rs +++ b/riscv/src/critical_section.rs @@ -1,16 +1,23 @@ use critical_section::{set_impl, Impl, RawRestoreState}; use crate::interrupt; -use crate::register::mstatus; struct SingleHartCriticalSection; set_impl!(SingleHartCriticalSection); unsafe impl Impl for SingleHartCriticalSection { + #[cfg(not(feature = "s-mode"))] unsafe fn acquire() -> RawRestoreState { let mut mstatus: usize; core::arch::asm!("csrrci {}, mstatus, 0b1000", out(reg) mstatus); - core::mem::transmute::<_, mstatus::Mstatus>(mstatus).mie() + core::mem::transmute::<_, crate::register::mstatus::Mstatus>(mstatus).mie() + } + + #[cfg(feature = "s-mode")] + unsafe fn acquire() -> RawRestoreState { + let mut sstatus: usize; + core::arch::asm!("csrrci {}, sstatus, 0b0010", out(reg) sstatus); + core::mem::transmute::<_, crate::register::sstatus::Sstatus>(sstatus).sie() } unsafe fn release(was_active: RawRestoreState) { diff --git a/riscv/src/interrupt.rs b/riscv/src/interrupt.rs index ee564efc..f83558b8 100644 --- a/riscv/src/interrupt.rs +++ b/riscv/src/interrupt.rs @@ -1,63 +1,105 @@ //! Interrupts // NOTE: Adapted from cortex-m/src/interrupt.rs -use crate::register::mstatus; - -/// Disables all interrupts in the current hart. -#[inline] -pub unsafe fn disable() { - match () { - #[cfg(riscv)] - () => mstatus::clear_mie(), - #[cfg(not(riscv))] - () => unimplemented!(), + +pub mod machine { + use crate::register::mstatus; + + /// Disables all interrupts in the current hart (machine mode). + #[inline] + pub fn disable() { + unsafe { mstatus::clear_mie() } } -} -/// Enables all the interrupts in the current hart. -/// -/// # Safety -/// -/// - Do not call this function inside a critical section. -#[inline] -pub unsafe fn enable() { - match () { - #[cfg(riscv)] - () => mstatus::set_mie(), - #[cfg(not(riscv))] - () => unimplemented!(), + /// Enables all the interrupts in the current hart (machine mode). + /// + /// # Safety + /// + /// Do not call this function inside a critical section. + #[inline] + pub unsafe fn enable() { + mstatus::set_mie() } -} -/// Execute closure `f` with interrupts disabled in the current hart. -/// -/// This method does not synchronise multiple harts, so it is not suitable for -/// using as a critical section. See the `critical-section` crate for a cross-platform -/// way to enter a critical section which provides a `CriticalSection` token. -/// -/// This crate provides an implementation for `critical-section` suitable for single-hart systems, -/// based on disabling all interrupts. It can be enabled with the `critical-section-single-hart` feature. -#[inline] -pub fn free(f: F) -> R -where - F: FnOnce() -> R, -{ - let mstatus = mstatus::read(); - - // disable interrupts - unsafe { + /// Execute closure `f` with interrupts disabled in the current hart (machine mode). + /// + /// This method does not synchronise multiple harts, so it is not suitable for + /// using as a critical section. See the `critical-section` crate for a cross-platform + /// way to enter a critical section which provides a `CriticalSection` token. + /// + /// This crate provides an implementation for `critical-section` suitable for single-hart systems, + /// based on disabling all interrupts. It can be enabled with the `critical-section-single-hart` feature. + #[inline] + pub fn free(f: F) -> R + where + F: FnOnce() -> R, + { + let mstatus = mstatus::read(); + + // disable interrupts disable(); - } - let r = f(); + let r = f(); - // If the interrupts were active before our `disable` call, then re-enable - // them. Otherwise, keep them disabled - if mstatus.mie() { - unsafe { - enable(); + // If the interrupts were active before our `disable` call, then re-enable + // them. Otherwise, keep them disabled + if mstatus.mie() { + unsafe { enable() }; } + + r + } +} +pub mod supervisor { + use crate::register::sstatus; + + /// Disables all interrupts in the current hart (supervisor mode). + #[inline] + pub fn disable() { + unsafe { sstatus::clear_sie() } } - r + /// Enables all the interrupts in the current hart (supervisor mode). + /// + /// # Safety + /// + /// Do not call this function inside a critical section. + #[inline] + pub unsafe fn enable() { + sstatus::set_sie() + } + + /// Execute closure `f` with interrupts disabled in the current hart (supervisor mode). + /// + /// This method does not synchronise multiple harts, so it is not suitable for + /// using as a critical section. See the `critical-section` crate for a cross-platform + /// way to enter a critical section which provides a `CriticalSection` token. + /// + /// This crate provides an implementation for `critical-section` suitable for single-hart systems, + /// based on disabling all interrupts. It can be enabled with the `critical-section-single-hart` feature. + #[inline] + pub fn free(f: F) -> R + where + F: FnOnce() -> R, + { + let sstatus = sstatus::read(); + + // disable interrupts + disable(); + + let r = f(); + + // If the interrupts were active before our `disable` call, then re-enable + // them. Otherwise, keep them disabled + if sstatus.sie() { + unsafe { enable() }; + } + + r + } } + +#[cfg(not(feature = "s-mode"))] +pub use machine::*; +#[cfg(feature = "s-mode")] +pub use supervisor::*; diff --git a/riscv/src/lib.rs b/riscv/src/lib.rs index 8128fd81..7eacac7a 100644 --- a/riscv/src/lib.rs +++ b/riscv/src/lib.rs @@ -15,10 +15,17 @@ //! //! # Optional features //! +//! ## `s-mode` +//! +//! This feature re-exports in `interrupt` S-mode interrupt functions defined in `interrupt::supervisor`. +//! By default, the crate assumes that the target is running in M-mode. +//! Thus, `interrupt` re-exports the M-mode functions defined in `interrupt::machine`. +//! //! ## `critical-section-single-hart` //! //! This feature enables a [`critical-section`](https://github.com/rust-embedded/critical-section) //! implementation suitable for single-hart targets, based on disabling interrupts globally. +//! This feature uses S-mode interrupt handling if the `s-mode` feature is enabled, and M-mode otherwise. //! //! It is **unsound** to enable it on multi-hart targets, //! and may cause functional problems in systems where some interrupts must NOT be disabled From 4ad4cfdbff47014c5ffec46f8ebcef4a1c34d08b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas?= Date: Mon, 4 Dec 2023 19:12:20 +0100 Subject: [PATCH 3/4] Revert "support for S-mode interrupts" This reverts commit 41c50dd49e0077db3701f7a8210d3c9f8e6ff3ca. --- .github/workflows/riscv.yaml | 8 +- riscv/CHANGELOG.md | 4 - riscv/Cargo.toml | 1 - riscv/src/critical_section.rs | 11 +-- riscv/src/interrupt.rs | 140 ++++++++++++---------------------- riscv/src/lib.rs | 7 -- 6 files changed, 53 insertions(+), 118 deletions(-) diff --git a/.github/workflows/riscv.yaml b/.github/workflows/riscv.yaml index c086564e..e2156dfe 100644 --- a/.github/workflows/riscv.yaml +++ b/.github/workflows/riscv.yaml @@ -1,6 +1,6 @@ on: push: - branches: [ master, riscv-pac ] + branches: [ master ] pull_request: merge_group: @@ -31,12 +31,8 @@ jobs: with: toolchain: ${{ matrix.toolchain }} targets: ${{ matrix.target }} - - name: Build (M-mode) + - name: Build (no features) run: cargo build --package riscv --target ${{ matrix.target }} - - name: Build (M-mode, critical section) - run: cargo build --package riscv --target ${{ matrix.target }} --features=critical-section-single-hart - - name: Build (S-mode) - run: cargo build --package riscv --target ${{ matrix.target }} --features=s-mode - name: Build (all features) run: cargo build --package riscv --target ${{ matrix.target }} --all-features diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index 9d5edebe..ab12ce7b 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -9,8 +9,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added -- `s-mode` feature for reexporting `machine::supervisor` or `interrupt::supervisor` to `interrupt` -- Support for supervisor-level interrupts in `interrupt::supervisor` - Add CI workflow to check that CHANGELOG.md file has been modified in PRs - Add `read_csr_as_rv32`, `set_rv32`, and `clear_rv32` macros - Add `mstatus::uxl` and `mstatus::sxl` @@ -22,8 +20,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed -- `critical-section` implementation depends on `s-mode` feature -- machine-level interrupt functions moved to `interrupt::machine` - Cargo workspace for riscv and riscv-rt - Update `embedded-hal` dependency to v1.0.0-rc.2 (bumps MSRV to 1.60) - `misa::MXL` renamed to `misa::XLEN` diff --git a/riscv/Cargo.toml b/riscv/Cargo.toml index c2d7f3a5..8e126fe7 100644 --- a/riscv/Cargo.toml +++ b/riscv/Cargo.toml @@ -20,7 +20,6 @@ targets = [ ] [features] -s-mode = [] critical-section-single-hart = ["critical-section/restore-state-bool"] [dependencies] diff --git a/riscv/src/critical_section.rs b/riscv/src/critical_section.rs index 908daec7..b52e2373 100644 --- a/riscv/src/critical_section.rs +++ b/riscv/src/critical_section.rs @@ -1,23 +1,16 @@ use critical_section::{set_impl, Impl, RawRestoreState}; use crate::interrupt; +use crate::register::mstatus; struct SingleHartCriticalSection; set_impl!(SingleHartCriticalSection); unsafe impl Impl for SingleHartCriticalSection { - #[cfg(not(feature = "s-mode"))] unsafe fn acquire() -> RawRestoreState { let mut mstatus: usize; core::arch::asm!("csrrci {}, mstatus, 0b1000", out(reg) mstatus); - core::mem::transmute::<_, crate::register::mstatus::Mstatus>(mstatus).mie() - } - - #[cfg(feature = "s-mode")] - unsafe fn acquire() -> RawRestoreState { - let mut sstatus: usize; - core::arch::asm!("csrrci {}, sstatus, 0b0010", out(reg) sstatus); - core::mem::transmute::<_, crate::register::sstatus::Sstatus>(sstatus).sie() + core::mem::transmute::<_, mstatus::Mstatus>(mstatus).mie() } unsafe fn release(was_active: RawRestoreState) { diff --git a/riscv/src/interrupt.rs b/riscv/src/interrupt.rs index f83558b8..ee564efc 100644 --- a/riscv/src/interrupt.rs +++ b/riscv/src/interrupt.rs @@ -1,105 +1,63 @@ //! Interrupts // NOTE: Adapted from cortex-m/src/interrupt.rs - -pub mod machine { - use crate::register::mstatus; - - /// Disables all interrupts in the current hart (machine mode). - #[inline] - pub fn disable() { - unsafe { mstatus::clear_mie() } - } - - /// Enables all the interrupts in the current hart (machine mode). - /// - /// # Safety - /// - /// Do not call this function inside a critical section. - #[inline] - pub unsafe fn enable() { - mstatus::set_mie() - } - - /// Execute closure `f` with interrupts disabled in the current hart (machine mode). - /// - /// This method does not synchronise multiple harts, so it is not suitable for - /// using as a critical section. See the `critical-section` crate for a cross-platform - /// way to enter a critical section which provides a `CriticalSection` token. - /// - /// This crate provides an implementation for `critical-section` suitable for single-hart systems, - /// based on disabling all interrupts. It can be enabled with the `critical-section-single-hart` feature. - #[inline] - pub fn free(f: F) -> R - where - F: FnOnce() -> R, - { - let mstatus = mstatus::read(); - - // disable interrupts - disable(); - - let r = f(); - - // If the interrupts were active before our `disable` call, then re-enable - // them. Otherwise, keep them disabled - if mstatus.mie() { - unsafe { enable() }; - } - - r +use crate::register::mstatus; + +/// Disables all interrupts in the current hart. +#[inline] +pub unsafe fn disable() { + match () { + #[cfg(riscv)] + () => mstatus::clear_mie(), + #[cfg(not(riscv))] + () => unimplemented!(), } } -pub mod supervisor { - use crate::register::sstatus; - /// Disables all interrupts in the current hart (supervisor mode). - #[inline] - pub fn disable() { - unsafe { sstatus::clear_sie() } +/// Enables all the interrupts in the current hart. +/// +/// # Safety +/// +/// - Do not call this function inside a critical section. +#[inline] +pub unsafe fn enable() { + match () { + #[cfg(riscv)] + () => mstatus::set_mie(), + #[cfg(not(riscv))] + () => unimplemented!(), } +} - /// Enables all the interrupts in the current hart (supervisor mode). - /// - /// # Safety - /// - /// Do not call this function inside a critical section. - #[inline] - pub unsafe fn enable() { - sstatus::set_sie() - } - - /// Execute closure `f` with interrupts disabled in the current hart (supervisor mode). - /// - /// This method does not synchronise multiple harts, so it is not suitable for - /// using as a critical section. See the `critical-section` crate for a cross-platform - /// way to enter a critical section which provides a `CriticalSection` token. - /// - /// This crate provides an implementation for `critical-section` suitable for single-hart systems, - /// based on disabling all interrupts. It can be enabled with the `critical-section-single-hart` feature. - #[inline] - pub fn free(f: F) -> R - where - F: FnOnce() -> R, - { - let sstatus = sstatus::read(); - - // disable interrupts +/// Execute closure `f` with interrupts disabled in the current hart. +/// +/// This method does not synchronise multiple harts, so it is not suitable for +/// using as a critical section. See the `critical-section` crate for a cross-platform +/// way to enter a critical section which provides a `CriticalSection` token. +/// +/// This crate provides an implementation for `critical-section` suitable for single-hart systems, +/// based on disabling all interrupts. It can be enabled with the `critical-section-single-hart` feature. +#[inline] +pub fn free(f: F) -> R +where + F: FnOnce() -> R, +{ + let mstatus = mstatus::read(); + + // disable interrupts + unsafe { disable(); + } - let r = f(); + let r = f(); - // If the interrupts were active before our `disable` call, then re-enable - // them. Otherwise, keep them disabled - if sstatus.sie() { - unsafe { enable() }; + // If the interrupts were active before our `disable` call, then re-enable + // them. Otherwise, keep them disabled + if mstatus.mie() { + unsafe { + enable(); } - - r } -} -#[cfg(not(feature = "s-mode"))] -pub use machine::*; -#[cfg(feature = "s-mode")] -pub use supervisor::*; + r +} diff --git a/riscv/src/lib.rs b/riscv/src/lib.rs index 7eacac7a..8128fd81 100644 --- a/riscv/src/lib.rs +++ b/riscv/src/lib.rs @@ -15,17 +15,10 @@ //! //! # Optional features //! -//! ## `s-mode` -//! -//! This feature re-exports in `interrupt` S-mode interrupt functions defined in `interrupt::supervisor`. -//! By default, the crate assumes that the target is running in M-mode. -//! Thus, `interrupt` re-exports the M-mode functions defined in `interrupt::machine`. -//! //! ## `critical-section-single-hart` //! //! This feature enables a [`critical-section`](https://github.com/rust-embedded/critical-section) //! implementation suitable for single-hart targets, based on disabling interrupts globally. -//! This feature uses S-mode interrupt handling if the `s-mode` feature is enabled, and M-mode otherwise. //! //! It is **unsound** to enable it on multi-hart targets, //! and may cause functional problems in systems where some interrupts must NOT be disabled From fd0ecf0a93b3ec45eb4efb3adbdec46d7873bb3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas?= Date: Mon, 4 Dec 2023 19:26:14 +0100 Subject: [PATCH 4/4] forgot README --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8d8459dd..d694f26c 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,8 @@ This repository contains various crates useful for writing Rust programs on RISC-V microcontrollers: -* [`riscv`]: CPU peripheral access and intrinsics +* [`riscv`]: CPU registers access and intrinsics +* [`riscv-pac`]: Common traits to be implemented by RISC-V PACs * [`riscv-rt`]: Startup code and interrupt handling