diff --git a/CHANGELOG.md b/CHANGELOG.md index 782dbd20..34f30e90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - CI actions updated. They now use `checkout@v3` and `dtolnay/rust-toolchain`. - `mcause::{Interrupt, Exception}` and `scause::{Interrupt, Exception}` now implement `From` trait for `usize` +- Set safety of `asm::nop` and `asm::delay` functions to safe. ### Fixed diff --git a/Cargo.toml b/Cargo.toml index 9832f9ec..80184254 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,4 +26,4 @@ plic = ["volatile-register"] bit_field = "0.10.0" critical-section = "1.1.0" embedded-hal = "0.2.6" -volatile-register = {version = "0.2.1", optional = true} +volatile-register = { version = "0.2.1", optional = true } diff --git a/src/asm.rs b/src/asm.rs index 3e4b186b..37530c9d 100644 --- a/src/asm.rs +++ b/src/asm.rs @@ -1,7 +1,7 @@ //! Assembly instructions macro_rules! instruction { - ($(#[$attr:meta])*, $fnname:ident, $asm:expr) => ( + ($(#[$attr:meta])*, unsafe $fnname:ident, $asm:expr) => ( $(#[$attr])* #[inline] pub unsafe fn $fnname() { @@ -13,25 +13,42 @@ macro_rules! instruction { () => unimplemented!(), } } - ) + ); + ($(#[$attr:meta])*, $fnname:ident, $asm:expr) => ( + $(#[$attr])* + #[inline] + pub fn $fnname() { + match () { + #[cfg(riscv)] + () => unsafe { core::arch::asm!($asm) }, + + #[cfg(not(riscv))] + () => unimplemented!(), + } + } + ); } instruction!( /// `nop` instruction wrapper /// - /// Generates a no-operation. Useful to prevent delay loops from being optimized away. + /// The `NOP` instruction does not change any architecturally visible state, except for + /// advancing the pc and incrementing any applicable performance counters. + /// + /// This function generates a no-operation; it's useful to prevent delay loops from being + /// optimized away. , nop, "nop"); instruction!( /// `EBREAK` instruction wrapper /// /// Generates a breakpoint exception. - , ebreak, "ebreak"); + , unsafe ebreak, "ebreak"); instruction!( /// `WFI` instruction wrapper /// /// Provides a hint to the implementation that the current hart can be stalled until an interrupt might need servicing. /// The WFI instruction is just a hint, and a legal implementation is to implement WFI as a NOP. - , wfi, "wfi"); + , unsafe wfi, "wfi"); instruction!( /// `SFENCE.VMA` instruction wrapper (all address spaces and page table levels) /// @@ -40,7 +57,7 @@ instruction!( /// are ordinarily not ordered with respect to loads and stores in the instruction stream. /// Executing an `SFENCE.VMA` instruction guarantees that any stores in the instruction stream prior to the /// `SFENCE.VMA` are ordered before all implicit references subsequent to the `SFENCE.VMA`. - , sfence_vma_all, "sfence.vma"); + , unsafe sfence_vma_all, "sfence.vma"); instruction!( /// `FENCE` instruction wrapper /// @@ -54,7 +71,7 @@ instruction!( /// The FENCE instruction also orders memory reads and writes made by the hart as observed by /// memory reads and writes made by an external device. However, FENCE does not order observations /// of events made by an external device using any other signaling mechanism. - , fence, "fence"); + , unsafe fence, "fence"); instruction!( /// `FENCE.I` instruction wrapper /// @@ -72,7 +89,7 @@ instruction!( /// The unused fields in the FENCE.I instruction, imm\[11:0\], rs1, and rd, are reserved for /// finer-grain fences in future extensions. For forward compatibility, base /// implementations shall ignore these fields, and standard software shall zero these fields. - , fence_i, "fence.i"); + , unsafe fence_i, "fence.i"); /// `SFENCE.VMA` instruction wrapper /// @@ -104,10 +121,10 @@ pub unsafe fn sfence_vma(asid: usize, addr: usize) { /// any other case please use a more accurate method to produce a delay. #[inline] #[allow(unused_variables)] -pub unsafe fn delay(cycles: u32) { +pub fn delay(cycles: u32) { match () { #[cfg(riscv)] - () => { + () => unsafe { let real_cyc = 1 + cycles / 2; core::arch::asm!( "1:", @@ -116,7 +133,7 @@ pub unsafe fn delay(cycles: u32) { inout(reg) real_cyc => _, options(nomem, nostack), ) - } + }, #[cfg(not(riscv))] () => unimplemented!(),