feat(pmu): add PMU support for Realms
This patch adds support for using PMU in Realms.
It adds 'bool pmu_enabled' and 'unsigned int pmu_num_cnts'
variables in 'struct rd' and 'struct rec.realm_info'.
Signed-off-by: AlexeiFedorov <Alexei.Fedorov@arm.com>
Change-Id: I13aad600a0215ba66d25be12ede5f4b86e6b018a
diff --git a/runtime/core/run.c b/runtime/core/run.c
index f136947..64f4b93 100644
--- a/runtime/core/run.c
+++ b/runtime/core/run.c
@@ -11,6 +11,7 @@
#include <cpuid.h>
#include <exit.h>
#include <fpu_helpers.h>
+#include <pmu.h>
#include <rec.h>
#include <run.h>
#include <smc-rmi.h>
@@ -19,7 +20,8 @@
static struct ns_state g_ns_data[MAX_CPUS];
static uint8_t g_sve_data[MAX_CPUS][sizeof(struct sve_state)]
- __attribute__((aligned(sizeof(__uint128_t))));
+ __aligned(sizeof(__uint128_t));
+static struct pmu_state g_pmu_data[MAX_CPUS];
/*
* Initialize the aux data and any buffer pointers to the aux granule memory for
@@ -29,10 +31,12 @@
void *rec_aux,
unsigned int num_rec_aux)
{
- aux_data->attest_heap_buf = (uint8_t *)rec_aux;
-
/* Ensure we have enough aux granules for use by REC */
- assert(num_rec_aux >= REC_HEAP_PAGES);
+ assert(num_rec_aux >= REC_NUM_PAGES);
+
+ aux_data->attest_heap_buf = (uint8_t *)rec_aux;
+ aux_data->pmu = (struct pmu_state *)((uint8_t *)rec_aux +
+ REC_HEAP_SIZE);
}
/*
@@ -69,7 +73,6 @@
sysregs->elr_el1 = read_elr_el12();
sysregs->spsr_el1 = read_spsr_el12();
sysregs->pmcr_el0 = read_pmcr_el0();
- sysregs->pmuserenr_el0 = read_pmuserenr_el0();
sysregs->tpidrro_el0 = read_tpidrro_el0();
sysregs->tpidr_el0 = read_tpidr_el0();
sysregs->csselr_el1 = read_csselr_el1();
@@ -105,7 +108,7 @@
sysregs->cntv_cval_el0 = read_cntv_cval_el02();
}
-static void save_realm_state(struct rec *rec)
+static void save_realm_state(struct rec *rec, struct rmi_rec_exit *rec_exit)
{
save_sysreg_state(&rec->sysregs);
@@ -113,6 +116,15 @@
rec->pstate = read_spsr_el2();
gic_save_state(&rec->sysregs.gicstate);
+
+ if (rec->realm_info.pmu_enabled) {
+ /* Expose PMU Realm state to NS */
+ pmu_update_rec_exit(rec_exit);
+
+ /* Save PMU context */
+ pmu_save_state(rec->aux_data.pmu,
+ rec->realm_info.pmu_num_cnts);
+ }
}
static void restore_sysreg_state(struct sysreg_state *sysregs)
@@ -122,7 +134,6 @@
write_elr_el12(sysregs->elr_el1);
write_spsr_el12(sysregs->spsr_el1);
write_pmcr_el0(sysregs->pmcr_el0);
- write_pmuserenr_el0(sysregs->pmuserenr_el0);
write_tpidrro_el0(sysregs->tpidrro_el0);
write_tpidr_el0(sysregs->tpidr_el0);
write_csselr_el1(sysregs->csselr_el1);
@@ -166,6 +177,12 @@
write_cntv_ctl_el02(sysregs->cntv_ctl_el0);
}
+static void configure_realm_stage2(struct rec *rec)
+{
+ write_vtcr_el2(rec->common_sysregs.vtcr_el2);
+ write_vttbr_el2(rec->common_sysregs.vttbr_el2);
+}
+
static void restore_realm_state(struct rec *rec)
{
/*
@@ -177,21 +194,29 @@
isb();
restore_sysreg_state(&rec->sysregs);
+
write_elr_el2(rec->pc);
write_spsr_el2(rec->pstate);
write_hcr_el2(rec->sysregs.hcr_el2);
+ /* Control trapping of accesses to PMU registers */
+ write_mdcr_el2(rec->common_sysregs.mdcr_el2);
+
gic_restore_state(&rec->sysregs.gicstate);
+
+ configure_realm_stage2(rec);
+
+ if (rec->realm_info.pmu_enabled) {
+ /* Restore PMU context */
+ pmu_restore_state(rec->aux_data.pmu,
+ rec->realm_info.pmu_num_cnts);
+ }
}
-static void configure_realm_stage2(struct rec *rec)
+static void save_ns_state(struct rec *rec)
{
- write_vtcr_el2(rec->common_sysregs.vtcr_el2);
- write_vttbr_el2(rec->common_sysregs.vttbr_el2);
-}
+ struct ns_state *ns_state = rec->ns;
-static void save_ns_state(struct ns_state *ns_state)
-{
save_sysreg_state(&ns_state->sysregs);
/*
@@ -202,10 +227,17 @@
ns_state->sysregs.cnthctl_el2 = read_cnthctl_el2();
ns_state->icc_sre_el2 = read_icc_sre_el2();
+
+ if (rec->realm_info.pmu_enabled) {
+ /* Save PMU context */
+ pmu_save_state(ns_state->pmu, rec->realm_info.pmu_num_cnts);
+ }
}
-static void restore_ns_state(struct ns_state *ns_state)
+static void restore_ns_state(struct rec *rec)
{
+ struct ns_state *ns_state = rec->ns;
+
restore_sysreg_state(&ns_state->sysregs);
/*
@@ -216,6 +248,12 @@
write_cnthctl_el2(ns_state->sysregs.cnthctl_el2);
write_icc_sre_el2(ns_state->icc_sre_el2);
+
+ if (rec->realm_info.pmu_enabled) {
+ /* Restore PMU state */
+ pmu_restore_state(ns_state->pmu,
+ rec->realm_info.pmu_num_cnts);
+ }
}
static void activate_events(struct rec *rec)
@@ -243,14 +281,18 @@
void *rec_aux;
unsigned int cpuid = my_cpuid();
- assert(rec->ns == NULL);
-
assert(cpuid < MAX_CPUS);
+ assert(rec->ns == NULL);
+ assert(rec->fpu_ctx.used == false);
+
ns_state = &g_ns_data[cpuid];
- /* ensure SVE/FPU context is cleared */
+ /* Ensure SVE/FPU and PMU context is cleared */
assert(ns_state->sve == NULL);
assert(ns_state->fpu == NULL);
+ assert(ns_state->pmu == NULL);
+
+ rec->ns = ns_state;
/* Map auxiliary granules */
rec_aux = map_rec_aux(rec->g_aux, rec->num_rec_aux);
@@ -270,7 +312,7 @@
*/
if (!rec->alloc_info.ctx_initialised) {
(void)attestation_heap_ctx_init(rec->aux_data.attest_heap_buf,
- REC_HEAP_PAGES * SZ_4K);
+ REC_HEAP_SIZE);
rec->alloc_info.ctx_initialised = true;
}
@@ -280,15 +322,11 @@
ns_state->fpu = (struct fpu_state *)&g_sve_data[cpuid];
}
- save_ns_state(ns_state);
+ ns_state->pmu = &g_pmu_data[cpuid];
+
+ save_ns_state(rec);
restore_realm_state(rec);
- /* Prepare for lazy save/restore of FPU/SIMD registers. */
- rec->ns = ns_state;
- assert(rec->fpu_ctx.used == false);
-
- configure_realm_stage2(rec);
-
do {
/*
* We must check the status of the arch timers in every
@@ -335,22 +373,23 @@
rec->fpu_ctx.used = false;
}
+ report_timer_state_to_ns(rec_exit);
+
+ save_realm_state(rec, rec_exit);
+ restore_ns_state(rec);
+
/*
- * Clear FPU/SVE context while exiting
+ * Clear FPU/SVE and PMU context while exiting
*/
ns_state->sve = NULL;
ns_state->fpu = NULL;
+ ns_state->pmu = NULL;
/*
* Clear NS pointer since that struct is local to this function.
*/
rec->ns = NULL;
- report_timer_state_to_ns(rec_exit);
-
- save_realm_state(rec);
- restore_ns_state(ns_state);
-
/* Undo the heap association */
attestation_heap_ctx_unassign_pe();
/* Unmap auxiliary granules */