1use super::Rec;
2use crate::asm::isb;
3use crate::rmi::error::Error;
4use crate::rmi::rec::run::Run;
5
6use aarch64_cpu::registers::*;
7
8#[cfg(feature = "ns_state_save")]
9mod ns_timer {
10 use super::*;
11 use crate::config::NUM_OF_CPU;
12 use crate::cpu::get_cpu_id;
13 use crate::rec::context::TimerRegister;
14 use core::array::from_fn;
15 use lazy_static::lazy_static;
16 use spin::mutex::Mutex;
17
18 lazy_static! {
19 static ref NS_TIMER: [Mutex<TimerRegister>; NUM_OF_CPU] =
20 from_fn(|_| Mutex::new(TimerRegister::default()));
21 }
22
23 pub(super) fn restore() {
24 let ns_timer = NS_TIMER[get_cpu_id()].lock();
25 CNTVOFF_EL2.set(ns_timer.cntvoff_el2);
26 CNTPOFF_EL2.set(ns_timer.cntpoff_el2);
27 CNTV_CVAL_EL0.set(ns_timer.cntv_cval_el0);
28 CNTV_CTL_EL0.set(ns_timer.cntv_ctl_el0);
29 CNTP_CVAL_EL0.set(ns_timer.cntp_cval_el0);
30 CNTP_CTL_EL0.set(ns_timer.cntp_ctl_el0);
31 CNTHCTL_EL2.set(ns_timer.cnthctl_el2);
32 }
33
34 pub(super) fn save() {
35 let mut timer = NS_TIMER[get_cpu_id()].lock();
36 timer.cntvoff_el2 = CNTVOFF_EL2.get();
37 timer.cntv_cval_el0 = CNTV_CVAL_EL0.get();
38 timer.cntv_ctl_el0 = CNTV_CTL_EL0.get();
39 timer.cntpoff_el2 = CNTPOFF_EL2.get();
40 timer.cntp_cval_el0 = CNTP_CVAL_EL0.get();
41 timer.cntp_ctl_el0 = CNTP_CTL_EL0.get();
42 timer.cnthctl_el2 = CNTHCTL_EL2.get();
43 }
44}
45
46pub fn init_timer(rec: &mut Rec<'_>) {
47 let timer = &mut rec.context.timer;
48 timer.cnthctl_el2 = (CNTHCTL_EL2::EL1PCEN::SET + CNTHCTL_EL2::EL1PCTEN::SET).into();
49}
50
51pub fn set_cnthctl(rec: &mut Rec<'_>, val: u64) {
52 let timer = &mut rec.context.timer;
53 timer.cnthctl_el2 = val;
54}
55
56#[cfg(not(fuzzing))]
57pub fn restore_state(rec: &Rec<'_>) {
58 let timer = &rec.context.timer;
59
60 CNTVOFF_EL2.set(timer.cntvoff_el2);
61 CNTPOFF_EL2.set(timer.cntpoff_el2);
62 CNTV_CVAL_EL0.set(timer.cntv_cval_el0);
63 CNTV_CTL_EL0.set(timer.cntv_ctl_el0);
64 CNTP_CVAL_EL0.set(timer.cntp_cval_el0);
65 CNTP_CTL_EL0.set(timer.cntp_ctl_el0);
66 CNTHCTL_EL2.set(timer.cnthctl_el2);
67}
68
69#[cfg(not(fuzzing))]
70pub fn save_state(rec: &mut Rec<'_>) {
71 let timer = &mut rec.context.timer;
72
73 timer.cntvoff_el2 = CNTVOFF_EL2.get();
74 timer.cntv_cval_el0 = CNTV_CVAL_EL0.get();
75 timer.cntv_ctl_el0 = CNTV_CTL_EL0.get();
76 timer.cntpoff_el2 = CNTPOFF_EL2.get();
77 timer.cntp_cval_el0 = CNTP_CVAL_EL0.get();
78 timer.cntp_ctl_el0 = CNTP_CTL_EL0.get();
79 timer.cnthctl_el2 = CNTHCTL_EL2.get();
80}
81
82pub fn send_state_to_host(rec: &Rec<'_>, run: &mut Run) -> Result<(), Error> {
83 let timer = &rec.context.timer;
84
85 run.set_cntv_ctl(timer.cntv_ctl_el0);
86 run.set_cntv_cval(timer.cntv_cval_el0 - timer.cntvoff_el2);
87 run.set_cntp_ctl(timer.cntp_ctl_el0);
88 run.set_cntp_cval(timer.cntp_cval_el0 - timer.cntpoff_el2);
89 Ok(())
90}
91
92pub fn save_host_state(_rec: &Rec<'_>) {
93 #[cfg(feature = "ns_state_save")]
94 ns_timer::save();
95}
96
97pub fn restore_host_state(_rec: &Rec<'_>) {
98 #[cfg(feature = "ns_state_save")]
99 ns_timer::restore();
100}
101
102pub fn update_timer_assertion(rec: &mut Rec<'_>) {
108 const CNTHCTL_EL2_CNTVMASK: u64 = 0x1 << 18;
109 const CNTHCTL_EL2_CNTPMASK: u64 = 0x1 << 19;
110 let timer = &mut rec.context.timer;
111
112 let cnthctl_old = timer.cnthctl_el2;
114
115 if CNTV_CTL_EL0.matches_all(
117 CNTV_CTL_EL0::ISTATUS::SET + CNTV_CTL_EL0::IMASK::CLEAR + CNTV_CTL_EL0::ENABLE::SET,
118 ) {
119 timer.cnthctl_el2 |= CNTHCTL_EL2_CNTVMASK;
120 } else {
121 timer.cnthctl_el2 &= !CNTHCTL_EL2_CNTVMASK; }
123
124 if CNTP_CTL_EL0.matches_all(
126 CNTP_CTL_EL0::ISTATUS::SET + CNTP_CTL_EL0::IMASK::CLEAR + CNTP_CTL_EL0::ENABLE::SET,
127 ) {
128 timer.cnthctl_el2 |= CNTHCTL_EL2_CNTPMASK;
129 } else {
130 timer.cnthctl_el2 &= !CNTHCTL_EL2_CNTPMASK; }
132
133 if cnthctl_old != timer.cnthctl_el2 {
135 CNTHCTL_EL2.set(timer.cnthctl_el2);
136 isb();
137 }
138}