Skip to content
Closed
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
10 changes: 9 additions & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ jobs:
run: cargo check --target riscv64imac-unknown-none-elf
- name: Run CI script for riscv64gc-unknown-none-elf under ${{ matrix.rust }}
run: cargo check --target riscv64gc-unknown-none-elf
- name: Run CI script for x86_64-unknown-linux-gnu under ${{ matrix.rust }} with critical-section-single-core
run: cargo check --target x86_64-unknown-linux-gnu --features critical-section-single-core
- name: Run CI script for riscv32imac-unknown-none-elf under ${{ matrix.rust }} with critical-section-single-core
run: cargo check --target riscv32imac-unknown-none-elf --features critical-section-single-core
- name: Run CI script for riscv64imac-unknown-none-elf under ${{ matrix.rust }} with critical-section-single-core
run: cargo check --target riscv64imac-unknown-none-elf --features critical-section-single-core
- name: Run CI script for riscv64gc-unknown-none-elf under ${{ matrix.rust }} with critical-section-single-core
run: cargo check --target riscv64gc-unknown-none-elf --features critical-section-single-core

# On macOS and Windows, we at least make sure that the crate builds and links.
build-other:
Expand All @@ -56,4 +64,4 @@ jobs:
toolchain: stable
override: true
- name: Build crate for host OS
run: cargo build
run: cargo build --features critical-section-single-core
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

### Added

- Added `critical-section-single-core` feature which provides an implementation for the `critical_section` crate for single-core systems, based on disabling all interrupts.

### Fixed

- Fix `asm::delay()` to ensure count register is always reloaded
Expand Down
6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[package]
name = "riscv"
version = "0.8.0"
edition = "2021"
rust-version = "1.59"
repository = "https://github.com/rust-embedded/riscv"
authors = ["The RISC-V Team <[email protected]>"]
Expand All @@ -16,7 +17,10 @@ targets = [
"riscv64imac-unknown-none-elf", "riscv64gc-unknown-none-elf",
]

[features]
critical-section-single-core = ["critical-section/restore-state-bool"]

[dependencies]
bare-metal = "1.0.0"
bit_field = "0.10.0"
critical-section = "1.1.0"
embedded-hal = "0.2.6"
22 changes: 22 additions & 0 deletions src/critical_section.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use critical_section::{set_impl, Impl, RawRestoreState};

use crate::interrupt;
use crate::register::mstatus;

struct SingleCoreCriticalSection;
set_impl!(SingleCoreCriticalSection);

unsafe impl Impl for SingleCoreCriticalSection {
unsafe fn acquire() -> RawRestoreState {
let was_active = mstatus::read().mie();
interrupt::disable();
was_active
}

unsafe fn release(was_active: RawRestoreState) {
// Only re-enable interrupts if they were enabled before the critical section.
if was_active {
interrupt::enable()
}
}
}
22 changes: 13 additions & 9 deletions src/interrupt.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
//! Interrupts

// NOTE: Adapted from cortex-m/src/interrupt.rs
pub use bare_metal::{CriticalSection, Mutex};
use register::mstatus;
use crate::register::mstatus;

/// Disables all interrupts
/// Disables all interrupts in the current core.
#[inline]
pub unsafe fn disable() {
match () {
Expand All @@ -15,11 +14,11 @@ pub unsafe fn disable() {
}
}

/// Enables all the interrupts
/// Enables all the interrupts in the current core.
///
/// # Safety
///
/// - Do not call this function inside an `interrupt::free` critical section
/// - Do not call this function inside a critical section.
#[inline]
pub unsafe fn enable() {
match () {
Expand All @@ -30,13 +29,18 @@ pub unsafe fn enable() {
}
}

/// Execute closure `f` in an interrupt-free context.
/// Execute closure `f` with interrupts disabled in the current core.
///
/// This as also known as a "critical section".
/// This method does not synchronise multiple cores, 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-core systems,
/// based on disabling all interrupts. It can be enabled with the `critical-section-single-core` feature.
#[inline]
pub fn free<F, R>(f: F) -> R
where
F: FnOnce(&CriticalSection) -> R,
F: FnOnce() -> R,
{
let mstatus = mstatus::read();

Expand All @@ -45,7 +49,7 @@ where
disable();
}

let r = f(unsafe { &CriticalSection::new() });
let r = f();

// If the interrupts were active before our `disable` call, then re-enable
// them. Otherwise, keep them disabled
Expand Down
14 changes: 10 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,20 @@

#![no_std]

extern crate bare_metal;
extern crate bit_field;
extern crate embedded_hal;

pub mod asm;
pub mod delay;
pub mod interrupt;
pub mod register;

#[macro_use]
mod macros;

#[cfg(all(riscv, feature = "critical-section-single-core"))]
mod critical_section;

/// Used to reexport items for use in macros. Do not use directly.
/// Not covered by semver guarantees.
#[doc(hidden)]
pub mod _export {
pub use critical_section;
}
7 changes: 5 additions & 2 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
/// at most once in the whole lifetime of the program.
///
/// # Note
/// this macro is unsound on multi-core systems
///
/// this macro requires a `critical-section` implementation to be set. For single core systems, you can
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe feature-gate this macro with critical-section-single-core?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The macro can still be used if critical-section-single-core is not enabled, if the user supplies a c-s implementation from somewhere else (such as a chip-specific impl for a multicore chip, from its HAL crate).

/// enable the `critical-section-single-core` feature for this crate. For multi core systems, you
/// have to provide one from elsewhere, typically your chip's HAL crate.
///
/// # Example
///
Expand All @@ -29,7 +32,7 @@
#[macro_export]
macro_rules! singleton {
(: $ty:ty = $expr:expr) => {
$crate::interrupt::free(|_| {
$crate::_export::critical_section::with(|_| {
static mut VAR: Option<$ty> = None;

#[allow(unsafe_code)]
Expand Down