summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVishal Annapurve <vannapurve@google.com>2026-05-22 15:15:34 +0000
committerSean Christopherson <seanjc@google.com>2026-05-26 15:13:54 -0700
commit986833d381d2c48bdfa52652006f445570aea0e4 (patch)
tree3762fb5e9a3b91f17512ceb5797b30777fda047f
parent0de1020f7bbb3e1c9cd5b6f3eb4bdd661b1ff735 (diff)
downloadlinux-986833d381d2c48bdfa52652006f445570aea0e4.tar.gz
linux-986833d381d2c48bdfa52652006f445570aea0e4.zip
KVM: x86: Treat KVM's virtual PMU as disabled for TDX VMs
Introduce a "protected PMU" concept, and use it to disable KVM's virtual PMU for TDX VMs, as the PMU state for TDX VMs is virtualized by the TDX Module[1], i.e. _can't_ emulated/virtualized by KVM, and KVM doesn't yet support enabling/exposing PMU functionality for/to TDX VMs. For now, simply treat the PMU as disabled, as it's not clear what all needs to be changed, e.g. KVM needs to do at least: 1) Configure TD_PARAMS to allow guests to use performance monitoring. 2) Restrict the TD to a subset of the PEBS counters if supported. 3) Limit the TD to setup a certain perfmon events using basic/enhanced event filtering. Explicitly disallow enabling the PMU via KVM_CAP_PMU_CAPABILITY for VMs with a protected PMU to prevent userspace from circumventing KVM's protections. Link: https://cdrdv2.intel.com/v1/dl/getContent/733575 Section 15.2[1] Suggested-by: Sean Christopherson <seanjc@google.com> Signed-off-by: Vishal Annapurve <vannapurve@google.com> Link: https://patch.msgid.link/20260522151534.652522-1-vannapurve@google.com [sean: massage shortlog and changelog] Signed-off-by: Sean Christopherson <seanjc@google.com>
-rw-r--r--arch/x86/include/asm/kvm_host.h1
-rw-r--r--arch/x86/kvm/vmx/tdx.c6
-rw-r--r--arch/x86/kvm/x86.c6
3 files changed, 12 insertions, 1 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 7114707b9856..beb83eea65ef 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1442,6 +1442,7 @@ struct kvm_arch {
bool has_private_mem;
bool has_protected_state;
bool has_protected_eoi;
+ bool has_protected_pmu;
bool pre_fault_allowed;
struct hlist_head *mmu_page_hash;
struct list_head active_mmu_pages;
diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index b8c3d3d8bbfe..5fb3f606501b 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -639,6 +639,12 @@ int tdx_vm_init(struct kvm *kvm)
kvm->arch.disabled_quirks |= KVM_X86_QUIRK_IGNORE_GUEST_PAT;
/*
+ * PMU support is provided by the TDX-Module (if enabled for the VM).
+ * From KVM's perspective, the VM doesn't have a virtual PMU.
+ */
+ kvm->arch.has_protected_pmu = true;
+
+ /*
* Because guest TD is protected, VMM can't parse the instruction in TD.
* Instead, guest uses MMIO hypercall. For unmodified device driver,
* #VE needs to be injected for MMIO and #VE handler in TD converts MMIO
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 93958df30230..c560c52b95f0 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -6920,6 +6920,10 @@ disable_exits_unlock:
if (!enable_pmu || (cap->args[0] & ~KVM_CAP_PMU_VALID_MASK))
break;
+ if (kvm->arch.has_protected_pmu &&
+ cap->args[0] != KVM_PMU_CAP_DISABLE)
+ break;
+
mutex_lock(&kvm->lock);
if (!kvm->created_vcpus && !kvm->arch.created_mediated_pmu) {
kvm->arch.enable_pmu = !(cap->args[0] & KVM_PMU_CAP_DISABLE);
@@ -13362,7 +13366,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
kvm->arch.default_tsc_khz = max_tsc_khz ? : tsc_khz;
kvm->arch.apic_bus_cycle_ns = APIC_BUS_CYCLE_NS_DEFAULT;
kvm->arch.guest_can_read_msr_platform_info = true;
- kvm->arch.enable_pmu = enable_pmu;
+ kvm->arch.enable_pmu = enable_pmu && !kvm->arch.has_protected_pmu;
#if IS_ENABLED(CONFIG_HYPERV)
spin_lock_init(&kvm->arch.hv_root_tdp_lock);