target/arm: Correctly initialize MDCR_EL2.HPMN

When working with performance monitoring counters, we look at
MDCR_EL2.HPMN as part of the check whether a counter is enabled. This
check fails, because MDCR_EL2.HPMN is reset to 0, meaning that no
counters are "enabled" for < EL2.
That's in violation of the Arm specification, which states that

> On a Warm reset, this field [MDCR_EL2.HPMN] resets to the value in
> PMCR_EL0.N

That's also what a comment in the code acknowledges, but the necessary
adjustment seems to have been forgotten when support for more counters
was added.
This change fixes the issue by setting the reset value to PMCR.N, which
is four.

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Daniel Müller 2021-02-10 09:41:22 -08:00 committed by Peter Maydell
parent 4565d82616
commit d3c1183ffe

View File

@ -38,6 +38,7 @@
#endif #endif
#define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */ #define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */
#define PMCR_NUM_COUNTERS 4 /* QEMU IMPDEF choice */
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
@ -5735,13 +5736,11 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
.writefn = gt_hyp_ctl_write, .raw_writefn = raw_write }, .writefn = gt_hyp_ctl_write, .raw_writefn = raw_write },
#endif #endif
/* The only field of MDCR_EL2 that has a defined architectural reset value /* The only field of MDCR_EL2 that has a defined architectural reset value
* is MDCR_EL2.HPMN which should reset to the value of PMCR_EL0.N; but we * is MDCR_EL2.HPMN which should reset to the value of PMCR_EL0.N.
* don't implement any PMU event counters, so using zero as a reset
* value for MDCR_EL2 is okay
*/ */
{ .name = "MDCR_EL2", .state = ARM_CP_STATE_BOTH, { .name = "MDCR_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 1, .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 1,
.access = PL2_RW, .resetvalue = 0, .access = PL2_RW, .resetvalue = PMCR_NUM_COUNTERS,
.fieldoffset = offsetof(CPUARMState, cp15.mdcr_el2), }, .fieldoffset = offsetof(CPUARMState, cp15.mdcr_el2), },
{ .name = "HPFAR", .state = ARM_CP_STATE_AA32, { .name = "HPFAR", .state = ARM_CP_STATE_AA32,
.cp = 15, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 4, .cp = 15, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 4,
@ -6672,7 +6671,7 @@ static void define_pmu_regs(ARMCPU *cpu)
* field as main ID register, and we implement four counters in * field as main ID register, and we implement four counters in
* addition to the cycle count register. * addition to the cycle count register.
*/ */
unsigned int i, pmcrn = 4; unsigned int i, pmcrn = PMCR_NUM_COUNTERS;
ARMCPRegInfo pmcr = { ARMCPRegInfo pmcr = {
.name = "PMCR", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 0, .name = "PMCR", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 0,
.access = PL0_RW, .access = PL0_RW,