]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
KVM: arm64: Only apply PMCR_EL0.P to the guest range of counters
authorOliver Upton <oliver.upton@linux.dev>
Tue, 17 Dec 2024 17:56:11 +0000 (09:56 -0800)
committerOliver Upton <oliver.upton@linux.dev>
Wed, 18 Dec 2024 21:22:25 +0000 (13:22 -0800)
An important distinction from other registers affected by HPMN is that
PMCR_EL0 only affects the guest range of counters, regardless of the EL
from which it is accessed. Ensure that PMCR_EL0.P is always applied to
'guest' counters by manually computing the mask rather than deriving it
from the current context.

Reviewed-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20241217175611.3658290-1-oliver.upton@linux.dev
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
arch/arm64/kvm/pmu-emul.c

index c6423782a8aa827b4c6ce60e7602cc422e1bd6b0..6c5950b9ceac884e30fae742b6c20b1c1a2b22f5 100644 (file)
@@ -617,8 +617,14 @@ 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) {
-               unsigned long mask = kvm_pmu_accessible_counter_mask(vcpu);
-               mask &= ~BIT(ARMV8_PMU_CYCLE_IDX);
+               /*
+                * 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);
+
                for_each_set_bit(i, &mask, 32)
                        kvm_pmu_set_pmc_value(kvm_vcpu_idx_to_pmc(vcpu, i), 0, true);
        }