ax_cpu/arch/aarch64/
timer.rs1use core::{arch::asm, marker::PhantomData};
4
5macro_rules! read_register {
6 ($name:literal) => {{
7 let value: u64;
8 unsafe { asm!(concat!("mrs {}, ", $name), out(reg) value, options(nomem, nostack)); }
10 value
11 }};
12}
13
14macro_rules! write_register {
15 ($name:literal, $value:expr) => {{
16 unsafe { asm!(concat!("msr ", $name, ", {}"), in(reg) $value, options(nostack)); }
18 }};
19}
20
21pub fn counter_frequency() -> u64 {
24 read_register!("CNTFRQ_EL0")
25}
26
27pub fn physical_counter() -> u64 {
29 synchronize();
30 read_register!("CNTPCT_EL0")
31}
32
33pub fn virtual_counter() -> u64 {
35 synchronize();
36 read_register!("CNTVCT_EL0")
37}
38
39#[derive(Clone, Copy, Debug, Eq, PartialEq)]
41pub enum TimerKind {
42 Physical,
44 Virtual,
46 HypervisorPhysical,
48}
49
50bitflags::bitflags! {
51 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
53 pub struct TimerControl: u64 {
54 const ENABLE = 1;
56 const MASKED = 1 << 1;
58 const PENDING = 1 << 2;
60 }
61}
62
63#[derive(Debug)]
66pub struct Timer {
67 kind: TimerKind,
68 _not_send_sync: PhantomData<*mut ()>,
69}
70
71impl Timer {
72 pub unsafe fn current(kind: TimerKind) -> Self {
79 Self {
80 kind,
81 _not_send_sync: PhantomData,
82 }
83 }
84
85 pub fn counter(&self) -> u64 {
87 match self.kind {
88 TimerKind::Virtual => virtual_counter(),
89 TimerKind::Physical | TimerKind::HypervisorPhysical => physical_counter(),
90 }
91 }
92
93 pub fn compare(&self) -> u64 {
95 match self.kind {
96 TimerKind::Physical => read_register!("CNTP_CVAL_EL0"),
97 TimerKind::Virtual => read_register!("CNTV_CVAL_EL0"),
98 TimerKind::HypervisorPhysical => read_register!("CNTHP_CVAL_EL2"),
99 }
100 }
101
102 pub fn set_compare(&mut self, ticks: u64) {
105 match self.kind {
106 TimerKind::Physical => write_register!("CNTP_CVAL_EL0", ticks),
107 TimerKind::Virtual => write_register!("CNTV_CVAL_EL0", ticks),
108 TimerKind::HypervisorPhysical => write_register!("CNTHP_CVAL_EL2", ticks),
109 }
110 synchronize();
111 }
112
113 pub fn control(&self) -> TimerControl {
115 let value = match self.kind {
116 TimerKind::Physical => read_register!("CNTP_CTL_EL0"),
117 TimerKind::Virtual => read_register!("CNTV_CTL_EL0"),
118 TimerKind::HypervisorPhysical => read_register!("CNTHP_CTL_EL2"),
119 };
120 TimerControl::from_bits_truncate(value)
121 }
122
123 pub fn set_control(&mut self, control: TimerControl) {
127 let value = (control & (TimerControl::ENABLE | TimerControl::MASKED)).bits();
128 match self.kind {
129 TimerKind::Physical => write_register!("CNTP_CTL_EL0", value),
130 TimerKind::Virtual => write_register!("CNTV_CTL_EL0", value),
131 TimerKind::HypervisorPhysical => write_register!("CNTHP_CTL_EL2", value),
132 }
133 synchronize();
134 }
135}
136
137fn synchronize() {
138 unsafe {
140 asm!("isb", options(nostack));
141 }
142}