1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
//! Support for aarch64's generic timer and system counter.
//!
//! Docs: <https://developer.arm.com/documentation/102379/latest/>

#![no_std]
#![feature(negative_impls)]

// This crate is only relevant on aarch64 systems,
// but we use a cfg gate here to allow it to be included in x86 builds
// because the build system currently builds _all_ crates for x86.
#[cfg(target_arch = "aarch64")]
pub use aarch64::*;

#[cfg(target_arch = "aarch64")]
mod aarch64 {

use cortex_a::registers::*;
use log::*;
use time::{Monotonic, ClockSource, Instant, Period, register_clock_source};
use tock_registers::interfaces::Writeable;
use tock_registers::interfaces::Readable;


/// Initializes the aarch64 generic system timer
/// and registers it as a monotonic [`ClockSource`].
///
/// This only needs to be invoked once, system-wide.
/// However, each CPU will need to enable their own timer interrupt separately,
/// as this function itself does not enable the timer interrupt.
pub fn init() {
    let period = Period::new(timer_period_femtoseconds());
    register_clock_source::<PhysicalSystemCounter>(period);
}

/// A ClockSource for the time crate, implemented using
/// the System Counter of the Generic Arm Timer. The
/// period of this timer is computed in `init` above.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct PhysicalSystemCounter;
impl !Send for PhysicalSystemCounter { }
impl PhysicalSystemCounter {
    /// An instant (no-op) function that returns the current CPU's system counter. 
    pub fn get() -> Self {
        Self
    }
}
impl ClockSource for PhysicalSystemCounter {
    type ClockType = Monotonic;

    fn now() -> Instant {
        Instant::new(CNTPCT_EL0.get())
    }
}

/// Returns the period in femtoseconds of the generic system timer.
///
/// This reads the `CNTFRQ_EL0` system register.
pub fn timer_period_femtoseconds() -> u64 {
    let counter_freq_hz = CNTFRQ_EL0.get();
    let fs_in_one_sec = 1_000_000_000_000_000;
    fs_in_one_sec / counter_freq_hz
}

/// Sets the current CPU's system timer interrupt to fire after `ticks_to_elapse` from now.
pub fn set_next_timer_interrupt(ticks_to_elapse: u64) {
    enable_timer_interrupt(false);
    CNTP_TVAL_EL0.set(ticks_to_elapse);
    enable_timer_interrupt(true);
}

/// Enables/disables the generic system timer and its interrupt on the current CPU.
///
/// This writes the `CNTP_CTL_EL0` system register.
pub fn enable_timer_interrupt(enable: bool) {
    // If enable: unmask the interrupt (set bit to 0), and enable the timer.
    // If disable: mask the interrupt (set bit to 1), and disable the timer.
    CNTP_CTL_EL0.write(
        CNTP_CTL_EL0::ENABLE.val(enable as u64)
        + CNTP_CTL_EL0::IMASK.val(!enable as u64)
    );

    if false {
        info!("timer enabled: {:?}", CNTP_CTL_EL0.read(CNTP_CTL_EL0::ENABLE));
        info!("timer IMASK: {:?}",   CNTP_CTL_EL0.read(CNTP_CTL_EL0::IMASK));
        info!("timer status: {:?}",  CNTP_CTL_EL0.read(CNTP_CTL_EL0::ISTATUS));
    }
}

}