return pmreg_access(env, ri, isread);
}
+/*
+ * Bits in MDCR_EL2 and MDCR_EL3 which pmu_counter_enabled() looks at.
+ * We use these to decide whether we need to wrap a write to MDCR_EL2
+ * or MDCR_EL3 in pmu_op_start()/pmu_op_finish() calls.
+ */
+#define MDCR_EL2_PMU_ENABLE_BITS (MDCR_HPME | MDCR_HPMD | MDCR_HPMN)
+#define MDCR_EL3_PMU_ENABLE_BITS (MDCR_SPME)
+
/* Returns true if the counter (pass 31 for PMCCNTR) should count events using
* the current EL, security state, and register configuration.
*/
static void pmcntenset_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
+ pmu_op_start(env);
value &= pmu_counter_mask(env);
env->cp15.c9_pmcnten |= value;
+ pmu_op_finish(env);
}
static void pmcntenclr_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
+ pmu_op_start(env);
value &= pmu_counter_mask(env);
env->cp15.c9_pmcnten &= ~value;
+ pmu_op_finish(env);
}
static void pmovsr_write(CPUARMState *env, const ARMCPRegInfo *ri,
static void sdcr_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
+ /*
+ * Some MDCR_EL3 bits affect whether PMU counters are running:
+ * if we are trying to change any of those then we must
+ * bracket this update with PMU start/finish calls.
+ */
+ bool pmu_op = (env->cp15.mdcr_el3 ^ value) & MDCR_EL3_PMU_ENABLE_BITS;
+
+ if (pmu_op) {
+ pmu_op_start(env);
+ }
env->cp15.mdcr_el3 = value & SDCR_VALID_MASK;
+ if (pmu_op) {
+ pmu_op_finish(env);
+ }
+}
+
+static void mdcr_el2_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ /*
+ * Some MDCR_EL2 bits affect whether PMU counters are running:
+ * if we are trying to change any of those then we must
+ * bracket this update with PMU start/finish calls.
+ */
+ bool pmu_op = (env->cp15.mdcr_el2 ^ value) & MDCR_EL2_PMU_ENABLE_BITS;
+
+ if (pmu_op) {
+ pmu_op_start(env);
+ }
+ env->cp15.mdcr_el2 = value;
+ if (pmu_op) {
+ pmu_op_finish(env);
+ }
}
static const ARMCPRegInfo v8_cp_reginfo[] = {
ARMCPRegInfo mdcr_el2 = {
.name = "MDCR_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 1,
+ .writefn = mdcr_el2_write,
.access = PL2_RW, .resetvalue = pmu_num_counters(env),
.fieldoffset = offsetof(CPUARMState, cp15.mdcr_el2),
};