1use super::Rec;
2use crate::pmu::*;
3
4use core::array::from_fn;
5use lazy_static::lazy_static;
6use spin::mutex::Mutex;
7
8use aarch64_cpu::registers::*;
9use armv9a::regs::pmu::*;
10use armv9a::{MDCR_EL2, PMCR_EL0};
11
12use crate::config::NUM_OF_CPU;
13use crate::cpu::get_cpu_id;
14use crate::rmi::error::Error;
15use crate::rmi::rec::run::Run;
16
17#[repr(C)]
18#[derive(Default, Debug)]
19pub struct PmuRegister {
20 pub pmcr_el0: u64,
21 pub pmccfiltr_el0: u64,
22 pub pmccntr_el0: u64,
23 pub pmcntenset_el0: u64,
24 pub pmcntenclr_el0: u64,
25 pub pmintenset_el1: u64,
26 pub pmintenclr_el1: u64,
27 pub pmovsset_el0: u64,
28 pub pmovsclr_el0: u64,
29 pub pmselr_el0: u64,
30 pub pmuserenr_el0: u64,
31 pub pmxevcntr_el0: u64,
32 pub pmxevtyper_el0: u64,
33 pub pmevcntr_el0: [u64; MAX_EVCNT],
34 pub pmevtyper_el0: [u64; MAX_EVCNT],
35}
36
37lazy_static! {
38 static ref NS_PMU: [Mutex<PmuRegister>; NUM_OF_CPU] =
39 from_fn(|_| Mutex::new(PmuRegister::default()));
40}
41
42const CLEAR_MASK: u64 = 0x1_FFFF_FFFF;
43
44pub fn init_pmu(rec: &mut Rec<'_>) {
45 let (pmu_enabled, pmu_num_ctrs) = rec.pmu_config().expect("REASON");
46 #[cfg(not(any(miri, test, fuzzing)))]
47 let mdcr_el2 = MDCR_EL2.get();
48 #[cfg(any(miri, test, fuzzing))]
49 let mdcr_el2 = 0;
50 let mask: u64 = MDCR_EL2::TPM::SET.value
51 | MDCR_EL2::TPMCR::SET.value
52 | (MDCR_EL2::HPMN.mask << MDCR_EL2::HPMN.shift);
53 rec.context.mdcr_el2 = if pmu_enabled {
54 (mdcr_el2 & !mask) | MDCR_EL2::HPMN.val(pmu_num_ctrs as u64).value
55 } else {
56 mdcr_el2 | (MDCR_EL2::TPM::SET + MDCR_EL2::TPMCR::SET).value
57 };
58 let rec_pmu = &mut rec.context.pmu;
59 rec_pmu.pmcr_el0 = if pmu_enabled {
60 (PMCR_EL0::LC::SET + PMCR_EL0::DP::SET + PMCR_EL0::C::SET + PMCR_EL0::P::SET).into()
61 } else {
62 (PMCR_EL0::LC::SET + PMCR_EL0::DP::SET).into()
63 };
64}
65
66fn restore_pmu(pmu: &PmuRegister, num_cntrs: usize) {
67 PMCR_EL0.set(pmu.pmcr_el0);
68 PMCCFILTR_EL0.set(pmu.pmccfiltr_el0);
69 PMCCNTR_EL0.set(pmu.pmccntr_el0);
70 PMCNTENSET_EL0.set(pmu.pmcntenset_el0);
71 PMCNTENCLR_EL0.set(pmu.pmcntenclr_el0 ^ CLEAR_MASK);
72 PMINTENSET_EL1.set(pmu.pmintenset_el1);
73 PMINTENCLR_EL1.set(pmu.pmintenclr_el1 ^ CLEAR_MASK);
74 PMOVSSET_EL0.set(pmu.pmovsset_el0);
75 PMOVSCLR_EL0.set(pmu.pmovsclr_el0 ^ CLEAR_MASK);
76 PMSELR_EL0.set(pmu.pmselr_el0);
77 PMUSERENR_EL0.set(pmu.pmuserenr_el0);
78 PMXEVCNTR_EL0.set(pmu.pmxevcntr_el0);
79 PMXEVTYPER_EL0.set(pmu.pmxevtyper_el0);
80 set_pmev_regs(num_cntrs, &pmu.pmevcntr_el0, &pmu.pmevtyper_el0);
81}
82
83pub fn restore_state(rec: &Rec<'_>) {
84 let (enabled, num_cntrs) = rec.pmu_config().expect("REASON");
85
86 if !enabled {
87 return;
88 }
89 MDCR_EL2.set(rec.context.mdcr_el2);
90 let rec_pmu = &rec.context.pmu;
91 restore_pmu(rec_pmu, num_cntrs);
92}
93
94fn save_pmu(pmu: &mut PmuRegister, num_cntrs: usize) {
95 pmu.pmcr_el0 = PMCR_EL0.get();
96 pmu.pmccfiltr_el0 = PMCCFILTR_EL0.get();
97 pmu.pmccntr_el0 = PMCCNTR_EL0.get();
98 pmu.pmcntenset_el0 = PMCNTENSET_EL0.get();
99 pmu.pmcntenclr_el0 = PMCNTENCLR_EL0.get();
100 pmu.pmintenset_el1 = PMINTENSET_EL1.get();
101 pmu.pmintenclr_el1 = PMINTENCLR_EL1.get();
102 pmu.pmovsset_el0 = PMOVSSET_EL0.get();
103 pmu.pmovsclr_el0 = PMOVSCLR_EL0.get();
104 pmu.pmselr_el0 = PMSELR_EL0.get();
105 pmu.pmuserenr_el0 = PMUSERENR_EL0.get();
106 pmu.pmxevcntr_el0 = PMXEVCNTR_EL0.get();
107 pmu.pmxevtyper_el0 = PMXEVTYPER_EL0.get();
108 get_pmev_regs(num_cntrs, &mut pmu.pmevcntr_el0, &mut pmu.pmevtyper_el0);
109}
110
111pub fn save_state(rec: &mut Rec<'_>) {
112 let (enabled, num_cntrs) = rec.pmu_config().expect("REASON");
113
114 if !enabled {
115 return;
116 }
117 let rec_pmu = &mut rec.context.pmu;
118 save_pmu(rec_pmu, num_cntrs);
119}
120
121pub fn save_host_state(rec: &Rec<'_>) {
122 let (enabled, _) = rec.pmu_config().expect("REASON");
123 if !enabled {
124 return;
125 }
126 let mut ns_pmu = NS_PMU[get_cpu_id()].lock();
127 save_pmu(&mut ns_pmu, pmu_num_ctrs() as usize);
130}
131
132pub fn restore_host_state(rec: &Rec<'_>) {
133 let (enabled, _) = rec.pmu_config().expect("REASON");
134 if !enabled {
135 return;
136 }
137 let ns_pmu = NS_PMU[get_cpu_id()].lock();
138 restore_pmu(&ns_pmu, pmu_num_ctrs() as usize);
141}
142
143pub fn pmu_overflow_active() -> bool {
144 (PMOVSSET_EL0.get() & PMINTENSET_EL1.get() & PMCNTENSET_EL0.get()) != 0
145 && PMCR_EL0.read(PMCR_EL0::E) != 0
146}
147
148#[cfg(not(any(miri, test, fuzzing)))]
149pub fn send_state_to_host(_rec: &Rec<'_>, run: &mut Run) -> Result<(), Error> {
150 run.set_pmu_overflow(pmu_overflow_active());
151 Ok(())
152}
153
154#[cfg(any(miri, test, fuzzing))]
155pub fn send_state_to_host(_rec: &Rec<'_>, run: &mut Run) -> Result<(), Error> {
156 run.set_pmu_overflow(false);
157 Ok(())
158}