On Tue, Dec 09, 2025 at 08:51:15PM +0000, Colton Lewis wrote:
The KVM API for event filtering says that counters do not count when blocked by the event filter. To enforce that, the event filter must be rechecked on every load since it might have changed since the last time the guest wrote a value. If the event is filtered, exclude counting at all exception levels before writing the hardware.
Signed-off-by: Colton Lewis coltonlewis@google.com
arch/arm64/kvm/pmu-direct.c | 44 +++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+)
diff --git a/arch/arm64/kvm/pmu-direct.c b/arch/arm64/kvm/pmu-direct.c index 71977d24f489a..8d0d6d1a0d851 100644 --- a/arch/arm64/kvm/pmu-direct.c +++ b/arch/arm64/kvm/pmu-direct.c @@ -221,6 +221,49 @@ u8 kvm_pmu_hpmn(struct kvm_vcpu *vcpu) return nr_host_cnt_max; } +/**
- kvm_pmu_apply_event_filter()
- @vcpu: Pointer to vcpu struct
- To uphold the guarantee of the KVM PMU event filter, we must ensure
- no counter counts if the event is filtered. Accomplish this by
- filtering all exception levels if the event is filtered.
- */
+static void kvm_pmu_apply_event_filter(struct kvm_vcpu *vcpu) +{
- struct arm_pmu *pmu = vcpu->kvm->arch.arm_pmu;
- u64 evtyper_set = ARMV8_PMU_EXCLUDE_EL0 |
ARMV8_PMU_EXCLUDE_EL1;- u64 evtyper_clr = ARMV8_PMU_INCLUDE_EL2;
- u8 i;
- u64 val;
- u64 evsel;
- if (!pmu)
return;- for (i = 0; i < pmu->hpmn_max; i++) {
val = __vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i);evsel = val & kvm_pmu_event_mask(vcpu->kvm);if (vcpu->kvm->arch.pmu_filter &&!test_bit(evsel, vcpu->kvm->arch.pmu_filter))val |= evtyper_set;val &= ~evtyper_clr;write_pmevtypern(i, val);- }
- val = __vcpu_sys_reg(vcpu, PMCCFILTR_EL0);
- if (vcpu->kvm->arch.pmu_filter &&
!test_bit(ARMV8_PMUV3_PERFCTR_CPU_CYCLES, vcpu->kvm->arch.pmu_filter))val |= evtyper_set;- val &= ~evtyper_clr;
- write_pmccfiltr(val);
+}
This doesn't work for nested. I agree that the hardware value of PMEVTYPERn_EL0 needs to be under KVM control, but depending on whether or not we're in a hyp context the meaning of the EL1 filtering bit changes. Have a look at kvm_pmu_create_perf_event().
Thanks, Oliver