sel4_kit/arch/aarch64/
timer.rs

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
//! 时钟相关的 crate
//!
//! 使用 `CNTP_xx_EL0` 来获取当前时间,进行定时器控制。
//! `cntp_ctl_el0`, `cntp_cval_el0`, `cntpct_el0`, `cntfrq_el0` 分别是控制寄存器、比较寄存器、计数寄存器、频率寄存器。
//!
//! `CNTP_CVAL_EL0` <https://developer.arm.com/documentation/ddi0601/2024-12/AArch64-Registers/CNTP-CVAL-EL0--Counter-timer-Physical-Timer-CompareValue-Register>
//! `CNTP_CTL_EL0` <https://developer.arm.com/documentation/ddi0601/2024-12/AArch64-Registers/CNTP-CTL-EL0--Counter-timer-Physical-Timer-Control-Register>
//! `CNTPCT_EL0` <https://developer.arm.com/documentation/ddi0601/2024-12/AArch64-Registers/CNTPCT-EL0--Counter-timer-Physical-Count-Register>
//! `CNTFRQ_EL0` <https://developer.arm.com/documentation/ddi0601/2024-12/AArch64-Registers/CNTFRQ-EL0--Counter-timer-Frequency-Register>
//!

use core::time::Duration;

/// PCNT 使用的中断号
pub const GENERIC_TIMER_PCNT_IRQ: usize = 30;

const NS_PER_SEC: usize = 1_000_000_000;

/// 获取当前的时间(ns)
#[cfg(target_arch = "aarch64")]
#[inline]
pub fn current_time() -> core::time::Duration {
    let cnt: usize;
    let freq: usize = get_freq();
    unsafe {
        core::arch::asm!("mrs  {}, cntpct_el0", out(reg) cnt);
    }
    core::time::Duration::new((cnt / freq) as _, ((cnt % freq) * NS_PER_SEC / freq) as _)
}

/// 获取当前的时钟频率
#[inline]
fn get_freq() -> usize {
    let freq: usize;
    unsafe {
        core::arch::asm!("mrs  {}, cntfrq_el0", out(reg) freq);
    }
    freq
}

/// 设置定时器
#[inline]
pub fn set_timer(next: Duration) {
    let freq = get_freq();
    let next_ticks =
        next.as_secs() as usize * freq + next.subsec_nanos() as usize * freq / NS_PER_SEC;
    let enable = if next.is_zero() { 0 } else { 1 };
    unsafe {
        core::arch::asm!(
            "msr cntp_cval_el0, {}",
            "msr cntp_ctl_el0, {:x}",
            in(reg) next_ticks,
            in(reg) enable
        );
    }
}

/// 获取当前 timer 定时的时间
#[inline]
pub fn get_cval() -> Duration {
    let cval: usize;
    let freq = get_freq();
    unsafe {
        core::arch::asm!("mrs  {}, cntp_cval_el0", out(reg) cval);
    }
    core::time::Duration::new((cval / freq) as _, ((cval % freq) * NS_PER_SEC / freq) as _)
}