diff options
Diffstat (limited to 'crates/driver_riscv_timer/src/lib.rs')
-rw-r--r-- | crates/driver_riscv_timer/src/lib.rs | 47 |
1 files changed, 47 insertions, 0 deletions
diff --git a/crates/driver_riscv_timer/src/lib.rs b/crates/driver_riscv_timer/src/lib.rs new file mode 100644 index 0000000..aebaba2 --- /dev/null +++ b/crates/driver_riscv_timer/src/lib.rs @@ -0,0 +1,47 @@ +//! Support for RISC-V's timers, using the Sstc extension. +#![cfg(target_arch = "riscv64")] +#![no_std] + +use core::{arch::asm, ops::Add, time::Duration}; + +/// The number of `Instant` "ticks" in a second. Initialized by the early-boot DeviceTree parser. +pub static mut TIMEBASE_FREQUENCY: u32 = 0; + +/// A moment in time. +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +pub struct Instant(u64); + +impl Instant { + /// Returns the current time as an `Instant`. + pub fn now() -> Instant { + let out; + // SAFETY: We require the Sstc extension, enable it before jumping to Rust, and never + // disable it. + unsafe { + asm!("rdtime {out}", out = out(reg) out, options(nomem, nostack)); + } + Instant(out) + } +} + +impl Add<Duration> for Instant { + type Output = Instant; + + #[allow(clippy::suspicious_arithmetic_impl)] + fn add(self, duration: Duration) -> Instant { + // SAFETY: TIMEBASE_FREQUENCY is never concurrently written to. + let ticks_per_second = unsafe { TIMEBASE_FREQUENCY }; + let ticks = duration.as_nanos().wrapping_mul(ticks_per_second as u128) / 1_000_000_000; + Instant(self.0.wrapping_add(ticks as u64)) + } +} + +/// Sets the timer interrupt to fire at the given instant. Note that this sets a global value, +/// rather than interacting with the scheduler in any way. +pub fn set_timer(instant: Instant) { + // SAFETY: We require the Sstc extension, enable it before jumping to Rust, and never + // disable it. + unsafe { + asm!("csrw stimecmp, {instant}", instant = in(reg) instant.0, options(nomem, nostack)); + } +} |