diff options
| author | Marc Zyngier <maz@kernel.org> | 2025-02-17 10:24:43 +0000 |
|---|---|---|
| committer | Marc Zyngier <maz@kernel.org> | 2025-04-11 12:59:10 +0100 |
| commit | 022435334393d56f4d6bc398cf16430067807b0a (patch) | |
| tree | 5024fda3788909e90a8cd78596198f8a9130ae3b | |
| parent | c8823e51b534d490ec27d372596eb35d2bb7193c (diff) | |
KVM: arm64: Contextualise the handling of PMCR_EL0.P writes
Contrary to what the comment says in kvm_pmu_handle_pmcr(),
writing PMCR_EL0.P==1 has the following effects:
<quote>
The event counters affected by this field are:
* All event counters in the first range.
* If any of the following are true, all event counters in the second
range:
- EL2 is disabled or not implemented in the current Security state.
- The PE is executing at EL2 or EL3.
</quote>
where the "first range" represent the counters in the [0..HPMN-1]
range, and the "second range" the counters in the [HPMN..MAX] range.
It so appears that writing P from EL2 should nuke all counters,
and not just the "guest" view. Just do that, and nuke the misleading
comment.
Reported-by: Joey Gouly <joey.gouly@arm.com>
Reviewed-by: Oliver Upton <oliver.upton@linux.dev>
Signed-off-by: Marc Zyngier <maz@kernel.org>
| -rw-r--r-- | arch/arm64/kvm/pmu-emul.c | 8 |
1 files changed, 3 insertions, 5 deletions
diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c index 2df54508f5ae..2336d9c8bd5e 100644 --- a/arch/arm64/kvm/pmu-emul.c +++ b/arch/arm64/kvm/pmu-emul.c @@ -608,14 +608,12 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val) kvm_pmu_set_counter_value(vcpu, ARMV8_PMU_CYCLE_IDX, 0); if (val & ARMV8_PMU_PMCR_P) { - /* - * Unlike other PMU sysregs, the controls in PMCR_EL0 always apply - * to the 'guest' range of counters and never the 'hyp' range. - */ unsigned long mask = kvm_pmu_implemented_counter_mask(vcpu) & - ~kvm_pmu_hyp_counter_mask(vcpu) & ~BIT(ARMV8_PMU_CYCLE_IDX); + if (!vcpu_is_el2(vcpu)) + mask &= ~kvm_pmu_hyp_counter_mask(vcpu); + for_each_set_bit(i, &mask, 32) kvm_pmu_set_pmc_value(kvm_vcpu_idx_to_pmc(vcpu, i), 0, true); } |
