[PATCH v2 14/16] KVM: x86/pmu: Ignore AnyThread bit if CPUID.0AH:EDX[15] is set

From: Zide Chen

Date: Thu Aug 27 2026 - 18:54:09 EST


Intel PerfMon v5 introduces the ANYTHREAD_DEPRECATION capability
(CPUID.0AH:EDX[15]) to indicate that AnyThread counting is deprecated
and that writes to the AnyThread bit in IA32_PERFEVTSELx are ignored.

When ANYTHREAD_DEPRECATION is present in the guest CPUID, emulate the
architectural behavior and silently ignore writes to the AnyThread bit
instead of injecting #GP.

Continue to inject #GP when ANYTHREAD_DEPRECATION is not present in the
guest CPUID, e.g. for PerfMon v3/v4 guests or when the capability is
not configured for a PerfMon v5+ guest.

Advertise CPUID.0AH:EDX[15] only for PMU version 5+ guests, since the
bit doesn't exist below version 5.

Signed-off-by: Zide Chen <zide.chen@xxxxxxxxx>
---
v2:
- Advertise anythread_deprecated only if kvm_pmu_cap.version >= 5.
- Add the missing AnyThr bit handling for IA32_FIXED_CTR_CTRL.
- Update the comments to be clearer.
---
arch/x86/kvm/cpuid.c | 2 +-
arch/x86/kvm/vmx/pmu_intel.c | 19 +++++++++++++++++++
2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 63201d4ea4a1..ef208906b3ee 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -1542,7 +1542,7 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
KVM_MAX_NR_FIXED_COUNTERS);
edx.split.bit_width_fixed = kvm_pmu_cap.bit_width_fixed;

- if (kvm_pmu_cap.version)
+ if (kvm_pmu_cap.version >= 5)
edx.split.anythread_deprecated = 1;

entry->eax = eax.full;
diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c
index c7472778137a..599c69dfa6e3 100644
--- a/arch/x86/kvm/vmx/pmu_intel.c
+++ b/arch/x86/kvm/vmx/pmu_intel.c
@@ -446,6 +446,12 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
if (data & pmu->fixed_ctr_ctrl_rsvd)
return 1;

+ /*
+ * This is to emulate ANYTHREAD_DEPRECATION. Guests without
+ * support for it would have had the write rejected by
+ * pmu->fixed_ctr_ctrl_rsvd above.
+ */
+ data &= ~intel_pmu_fixed_ctrl_bits(pmu, INTEL_FIXED_0_ANYTHREAD);
if (pmu->fixed_ctr_ctrl != data)
reprogram_fixed_counters(pmu, data);
break;
@@ -494,6 +500,8 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
if (data & eventsel_rsvd)
return 1;

+ /* See above comments for MSR_CORE_PERF_FIXED_CTR_CTRL. */
+ data &= ~ARCH_PERFMON_EVENTSEL_ANY;
if (data != pmc->eventsel) {
pmc->eventsel = data;
pmc->eventsel_hw = data;
@@ -603,6 +611,17 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
pmu->pmc_exists64 = (BIT_ULL(nr_gp_counters) - 1) &
kvm_pmu_cap.cntr_mask64;

+ /*
+ * AnyThread counting is not supported by KVM due to cross-VM
+ * information leakage concerns on SMT cores. Therefore, AnyThread
+ * remains unavailable for PerfMon v3/v4 guests, where AnyThread
+ * deprecation is not enumerated.
+ */
+ if (pmu->version >= 5 && edx.split.anythread_deprecated) {
+ pmu->eventsel_rsvd &= ~ARCH_PERFMON_EVENTSEL_ANY;
+ fixed_enable_bits |= INTEL_FIXED_0_ANYTHREAD;
+ }
+
entry = kvm_find_cpuid_entry_index(vcpu, 7, 0);
if (entry &&
(boot_cpu_has(X86_FEATURE_HLE) || boot_cpu_has(X86_FEATURE_RTM)) &&
--
2.55.0