]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: TDX: Make pmu_intel.c ignore guest TD case
authorIsaku Yamahata <isaku.yamahata@intel.com>
Wed, 30 Oct 2024 19:00:33 +0000 (12:00 -0700)
committerPaolo Bonzini <pbonzini@redhat.com>
Fri, 14 Mar 2025 18:20:51 +0000 (14:20 -0400)
TDX KVM doesn't support PMU yet, it's future work of TDX KVM support as
another patch series. For now, handle TDX by updating vcpu_to_lbr_desc()
and vcpu_to_lbr_records() to return NULL.

Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
Co-developed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
Signed-off-by: Tony Lindgren <tony.lindgren@linux.intel.com>
Signed-off-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
---
 - Add pragma poison for to_vmx() (Paolo)
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/vmx/pmu_intel.c
arch/x86/kvm/vmx/pmu_intel.h [new file with mode: 0644]
arch/x86/kvm/vmx/vmx.h

index 77012b2eca0e9a5a8671fa43a59906a4cd7f07c5..8a94b52c5731d5ec9b8e096d9492a1209bd4807e 100644 (file)
@@ -19,6 +19,7 @@
 #include "lapic.h"
 #include "nested.h"
 #include "pmu.h"
+#include "tdx.h"
 
 /*
  * Perf's "BASE" is wildly misleading, architectural PMUs use bits 31:16 of ECX
 
 #define MSR_PMC_FULL_WIDTH_BIT      (MSR_IA32_PMC0 - MSR_IA32_PERFCTR0)
 
+static struct lbr_desc *vcpu_to_lbr_desc(struct kvm_vcpu *vcpu)
+{
+       if (is_td_vcpu(vcpu))
+               return NULL;
+
+       return &to_vmx(vcpu)->lbr_desc;
+}
+
+static struct x86_pmu_lbr *vcpu_to_lbr_records(struct kvm_vcpu *vcpu)
+{
+       if (is_td_vcpu(vcpu))
+               return NULL;
+
+       return &to_vmx(vcpu)->lbr_desc.records;
+}
+
+#pragma GCC poison to_vmx
+
 static void reprogram_fixed_counters(struct kvm_pmu *pmu, u64 data)
 {
        struct kvm_pmc *pmc;
@@ -129,6 +148,22 @@ static inline struct kvm_pmc *get_fw_gp_pmc(struct kvm_pmu *pmu, u32 msr)
        return get_gp_pmc(pmu, msr, MSR_IA32_PMC0);
 }
 
+static bool intel_pmu_lbr_is_compatible(struct kvm_vcpu *vcpu)
+{
+       if (is_td_vcpu(vcpu))
+               return false;
+
+       return cpuid_model_is_consistent(vcpu);
+}
+
+bool intel_pmu_lbr_is_enabled(struct kvm_vcpu *vcpu)
+{
+       if (is_td_vcpu(vcpu))
+               return false;
+
+       return !!vcpu_to_lbr_records(vcpu)->nr;
+}
+
 static bool intel_pmu_is_valid_lbr_msr(struct kvm_vcpu *vcpu, u32 index)
 {
        struct x86_pmu_lbr *records = vcpu_to_lbr_records(vcpu);
@@ -194,6 +229,9 @@ static inline void intel_pmu_release_guest_lbr_event(struct kvm_vcpu *vcpu)
 {
        struct lbr_desc *lbr_desc = vcpu_to_lbr_desc(vcpu);
 
+       if (!lbr_desc)
+               return;
+
        if (lbr_desc->event) {
                perf_event_release_kernel(lbr_desc->event);
                lbr_desc->event = NULL;
@@ -235,6 +273,9 @@ int intel_pmu_create_guest_lbr_event(struct kvm_vcpu *vcpu)
                                        PERF_SAMPLE_BRANCH_USER,
        };
 
+       if (WARN_ON_ONCE(!lbr_desc))
+               return 0;
+
        if (unlikely(lbr_desc->event)) {
                __set_bit(INTEL_PMC_IDX_FIXED_VLBR, pmu->pmc_in_use);
                return 0;
@@ -466,6 +507,9 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
        u64 perf_capabilities;
        u64 counter_rsvd;
 
+       if (!lbr_desc)
+               return;
+
        memset(&lbr_desc->records, 0, sizeof(lbr_desc->records));
 
        /*
@@ -542,7 +586,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
                INTEL_PMC_MAX_GENERIC, pmu->nr_arch_fixed_counters);
 
        perf_capabilities = vcpu_get_perf_capabilities(vcpu);
-       if (cpuid_model_is_consistent(vcpu) &&
+       if (intel_pmu_lbr_is_compatible(vcpu) &&
            (perf_capabilities & PMU_CAP_LBR_FMT))
                memcpy(&lbr_desc->records, &vmx_lbr_caps, sizeof(vmx_lbr_caps));
        else
@@ -570,6 +614,9 @@ static void intel_pmu_init(struct kvm_vcpu *vcpu)
        struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
        struct lbr_desc *lbr_desc = vcpu_to_lbr_desc(vcpu);
 
+       if (!lbr_desc)
+               return;
+
        for (i = 0; i < KVM_MAX_NR_INTEL_GP_COUNTERS; i++) {
                pmu->gp_counters[i].type = KVM_PMC_GP;
                pmu->gp_counters[i].vcpu = vcpu;
@@ -677,6 +724,9 @@ void vmx_passthrough_lbr_msrs(struct kvm_vcpu *vcpu)
        struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
        struct lbr_desc *lbr_desc = vcpu_to_lbr_desc(vcpu);
 
+       if (WARN_ON_ONCE(!lbr_desc))
+               return;
+
        if (!lbr_desc->event) {
                vmx_disable_lbr_msrs_passthrough(vcpu);
                if (vmcs_read64(GUEST_IA32_DEBUGCTL) & DEBUGCTLMSR_LBR)
diff --git a/arch/x86/kvm/vmx/pmu_intel.h b/arch/x86/kvm/vmx/pmu_intel.h
new file mode 100644 (file)
index 0000000..5620d08
--- /dev/null
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __KVM_X86_VMX_PMU_INTEL_H
+#define  __KVM_X86_VMX_PMU_INTEL_H
+
+#include <linux/kvm_host.h>
+
+bool intel_pmu_lbr_is_enabled(struct kvm_vcpu *vcpu);
+int intel_pmu_create_guest_lbr_event(struct kvm_vcpu *vcpu);
+
+struct lbr_desc {
+       /* Basic info about guest LBR records. */
+       struct x86_pmu_lbr records;
+
+       /*
+        * Emulate LBR feature via passthrough LBR registers when the
+        * per-vcpu guest LBR event is scheduled on the current pcpu.
+        *
+        * The records may be inaccurate if the host reclaims the LBR.
+        */
+       struct perf_event *event;
+
+       /* True if LBRs are marked as not intercepted in the MSR bitmap */
+       bool msr_passthrough;
+};
+
+extern struct x86_pmu_lbr vmx_lbr_caps;
+
+#endif /* __KVM_X86_VMX_PMU_INTEL_H */
index ec8483311d00c4c766609e42e14bc7481b00163b..a4ee44ffaede3574669ca86f68119634c83ee11f 100644 (file)
@@ -11,6 +11,7 @@
 
 #include "capabilities.h"
 #include "../kvm_cache_regs.h"
+#include "pmu_intel.h"
 #include "vmcs.h"
 #include "vmx_ops.h"
 #include "../cpuid.h"
@@ -90,24 +91,6 @@ union vmx_exit_reason {
        u32 full;
 };
 
-struct lbr_desc {
-       /* Basic info about guest LBR records. */
-       struct x86_pmu_lbr records;
-
-       /*
-        * Emulate LBR feature via passthrough LBR registers when the
-        * per-vcpu guest LBR event is scheduled on the current pcpu.
-        *
-        * The records may be inaccurate if the host reclaims the LBR.
-        */
-       struct perf_event *event;
-
-       /* True if LBRs are marked as not intercepted in the MSR bitmap */
-       bool msr_passthrough;
-};
-
-extern struct x86_pmu_lbr vmx_lbr_caps;
-
 /*
  * The nested_vmx structure is part of vcpu_vmx, and holds information we need
  * for correct emulation of VMX (i.e., nested VMX) on this vcpu.
@@ -662,21 +645,6 @@ static __always_inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu)
        return container_of(vcpu, struct vcpu_vmx, vcpu);
 }
 
-static inline struct lbr_desc *vcpu_to_lbr_desc(struct kvm_vcpu *vcpu)
-{
-       return &to_vmx(vcpu)->lbr_desc;
-}
-
-static inline struct x86_pmu_lbr *vcpu_to_lbr_records(struct kvm_vcpu *vcpu)
-{
-       return &vcpu_to_lbr_desc(vcpu)->records;
-}
-
-static inline bool intel_pmu_lbr_is_enabled(struct kvm_vcpu *vcpu)
-{
-       return !!vcpu_to_lbr_records(vcpu)->nr;
-}
-
 void intel_pmu_cross_mapped_check(struct kvm_pmu *pmu);
 int intel_pmu_create_guest_lbr_event(struct kvm_vcpu *vcpu);
 void vmx_passthrough_lbr_msrs(struct kvm_vcpu *vcpu);