Skip to main content

islet_rmm/rec/
pmu.rs

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    // Event counter and cycle counter can be reset by P and C bits in PMCR_EL0
128    // thus save and restore all counters.
129    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    // Event counter and cycle counter can be reset by P and C bits in PMCR_EL0
139    // thus save and restore all counters.
140    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}