]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
KVM: x86/pmu: Disable RDPMC interception for compatible mediated vPMU
authorDapeng Mi <dapeng1.mi@linux.intel.com>
Sat, 6 Dec 2025 00:16:56 +0000 (16:16 -0800)
committerSean Christopherson <seanjc@google.com>
Thu, 8 Jan 2026 19:52:06 +0000 (11:52 -0800)
Disable RDPMC interception for vCPUs with a mediated vPMU that is
compatible with the host PMU, i.e. that doesn't require KVM emulation of
RDPMC to honor the guest's vCPU model.  With a mediated vPMU, all guest
state accessible via RDPMC is loaded into hardware while the guest is
running.

Adust RDPMC interception only for non-TDX guests, as the TDX module is
responsible for managing RDPMC intercepts based on the TD configuration.

Co-developed-by: Mingwei Zhang <mizhang@google.com>
Signed-off-by: Mingwei Zhang <mizhang@google.com>
Co-developed-by: Sandipan Das <sandipan.das@amd.com>
Signed-off-by: Sandipan Das <sandipan.das@amd.com>
Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
Tested-by: Xudong Hao <xudong.hao@intel.com>
Co-developed-by: Sean Christopherson <seanjc@google.com>
Tested-by: Manali Shukla <manali.shukla@amd.com>
Link: https://patch.msgid.link/20251206001720.468579-21-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
arch/x86/kvm/pmu.c
arch/x86/kvm/pmu.h
arch/x86/kvm/svm/svm.c
arch/x86/kvm/vmx/vmx.c
arch/x86/kvm/x86.c

index 0b67920fa0697976c7a3f7acbb4e79cbbb46bd02..fcecb4c21599cd6ee80b57fc9fdc0b75724eaa99 100644 (file)
@@ -714,6 +714,32 @@ int kvm_pmu_rdpmc(struct kvm_vcpu *vcpu, unsigned idx, u64 *data)
        return 0;
 }
 
+bool kvm_need_rdpmc_intercept(struct kvm_vcpu *vcpu)
+{
+       struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+
+       if (!kvm_vcpu_has_mediated_pmu(vcpu))
+               return true;
+
+       /*
+        * VMware allows access to these Pseduo-PMCs even when read via RDPMC
+        * in Ring3 when CR4.PCE=0.
+        */
+       if (enable_vmware_backdoor)
+               return true;
+
+       /*
+        * Note!  Check *host* PMU capabilities, not KVM's PMU capabilities, as
+        * KVM's capabilities are constrained based on KVM support, i.e. KVM's
+        * capabilities themselves may be a subset of hardware capabilities.
+        */
+       return pmu->nr_arch_gp_counters != kvm_host_pmu.num_counters_gp ||
+              pmu->nr_arch_fixed_counters != kvm_host_pmu.num_counters_fixed ||
+              pmu->counter_bitmask[KVM_PMC_GP] != (BIT_ULL(kvm_host_pmu.bit_width_gp) - 1) ||
+              pmu->counter_bitmask[KVM_PMC_FIXED] != (BIT_ULL(kvm_host_pmu.bit_width_fixed) - 1);
+}
+EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_need_rdpmc_intercept);
+
 void kvm_pmu_deliver_pmi(struct kvm_vcpu *vcpu)
 {
        if (lapic_in_kernel(vcpu)) {
index 9849c2bb720dfdd53063d0bf82cc3050ddef2e9e..506c203587eac4619b4eb2d0716e78e802c995d6 100644 (file)
@@ -238,6 +238,7 @@ void kvm_pmu_instruction_retired(struct kvm_vcpu *vcpu);
 void kvm_pmu_branch_retired(struct kvm_vcpu *vcpu);
 
 bool is_vmware_backdoor_pmc(u32 pmc_idx);
+bool kvm_need_rdpmc_intercept(struct kvm_vcpu *vcpu);
 
 extern struct kvm_pmu_ops intel_pmu_ops;
 extern struct kvm_pmu_ops amd_pmu_ops;
index f56c2d895011c92431e637253259797dba0dcbbe..ef43360b9282c50c61b448cd9fa730f7fd876eb8 100644 (file)
@@ -1011,6 +1011,11 @@ static void svm_recalc_instruction_intercepts(struct kvm_vcpu *vcpu)
                        svm->vmcb->control.virt_ext |= VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK;
                }
        }
+
+       if (kvm_need_rdpmc_intercept(vcpu))
+               svm_set_intercept(svm, INTERCEPT_RDPMC);
+       else
+               svm_clr_intercept(svm, INTERCEPT_RDPMC);
 }
 
 static void svm_recalc_intercepts(struct kvm_vcpu *vcpu)
index fdd18ad1ede3759742659ccff472102bd52ae7f4..9f71ba99cf700c881b30915c729ede09f75390aa 100644 (file)
@@ -4300,8 +4300,15 @@ static void vmx_recalc_msr_intercepts(struct kvm_vcpu *vcpu)
         */
 }
 
+static void vmx_recalc_instruction_intercepts(struct kvm_vcpu *vcpu)
+{
+       exec_controls_changebit(to_vmx(vcpu), CPU_BASED_RDPMC_EXITING,
+                               kvm_need_rdpmc_intercept(vcpu));
+}
+
 void vmx_recalc_intercepts(struct kvm_vcpu *vcpu)
 {
+       vmx_recalc_instruction_intercepts(vcpu);
        vmx_recalc_msr_intercepts(vcpu);
 }
 
index 1623afddff3b6105c6c65585f7386f686feca91f..76e86eb358dff0b32234940b4e2a6051e0288ed3 100644 (file)
@@ -3945,6 +3945,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 
                vcpu->arch.perf_capabilities = data;
                kvm_pmu_refresh(vcpu);
+               kvm_make_request(KVM_REQ_RECALC_INTERCEPTS, vcpu);
                break;
        case MSR_IA32_PRED_CMD: {
                u64 reserved_bits = ~(PRED_CMD_IBPB | PRED_CMD_SBPB);