From: Zide Chen <zide.chen@intel.com>
To: Sean Christopherson <seanjc@google.com>,
Paolo Bonzini <pbonzini@redhat.com>,
Peter Zijlstra <peterz@infradead.org>
Cc: kvm@vger.kernel.org, Andi Kleen <ak@linux.intel.com>,
Jim Mattson <jmattson@google.com>,
Stephane Eranian <eranian@google.com>,
linux-kernel@vger.kernel.org, Mingwei Zhang <mizhang@google.com>,
Zide Chen <zide.chen@intel.com>,
Das Sandipan <Sandipan.Das@amd.com>,
Shukla Manali <Manali.Shukla@amd.com>,
Dapeng Mi <dapeng1.mi@linux.intel.com>,
Xudong Hao <xudong.hao@intel.com>
Subject: [PATCH 13/23] KVM: x86/pmu: Set up the PERFMON_MASK VMCS field
Date: Fri, 21 Aug 2026 15:19:52 -0700 [thread overview]
Message-ID: <20260821222002.54907-14-zide.chen@intel.com> (raw)
In-Reply-To: <20260821222002.54907-1-zide.chen@intel.com>
Program the VMCS PERFMON_MASK field when PerfMon masking is enabled.
The field uses the same bit definitions as IA32_PERF_GLOBAL_STATUS and
can therefore be derived from ~pmu->global_status_rsvd.
Expose IA32_PERF_CAPABILITIES.PERF_METRICS_AVAILABLE[15] only when
PERFMON_MASK[48] is available to the guest.
When PerfMon masking is enabled, guest RDMSR/WRMSR accesses to PMU
global MSRs are filtered by the mask, writes outside the mask cause
an #GP(0), and RDPMC returns only guest-owned counter values.
Intentionally defer enabling PerfMon masking in VM-execution control
until the remaining PerfMon masking support is in place, so that
intermediate commits remain functional during bisection.
Signed-off-by: Zide Chen <zide.chen@intel.com>
---
arch/x86/include/asm/kvm_host.h | 1 +
arch/x86/include/asm/vmx.h | 2 ++
arch/x86/kvm/pmu.c | 4 ++--
arch/x86/kvm/pmu.h | 6 ++++++
arch/x86/kvm/vmx/pmu_intel.c | 26 ++++++++++++++++++++++++++
arch/x86/kvm/vmx/vmx.c | 6 +++++-
6 files changed, 42 insertions(+), 3 deletions(-)
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 262553f95793..467090bf0ab2 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -582,6 +582,7 @@ struct kvm_pmu {
u64 eventsel_rsvd;
u64 raw_event_mask;
u64 perf_metrics;
+ u64 perfmon_mask;
struct kvm_pmc gp_counters[KVM_MAX_NR_GP_COUNTERS];
struct kvm_pmc fixed_counters[KVM_MAX_NR_FIXED_COUNTERS];
diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h
index 3f1b3096ff04..1cb092d86955 100644
--- a/arch/x86/include/asm/vmx.h
+++ b/arch/x86/include/asm/vmx.h
@@ -275,6 +275,8 @@ enum vmcs_field {
SHARED_EPT_POINTER = 0x0000203C,
PID_POINTER_TABLE = 0x00002042,
PID_POINTER_TABLE_HIGH = 0x00002043,
+ PERFMON_MASK = 0x00002054,
+ PERFMON_MASK_HIGH = 0x00002055,
GUEST_PHYSICAL_ADDRESS = 0x00002400,
GUEST_PHYSICAL_ADDRESS_HIGH = 0x00002401,
VMCS_LINK_POINTER = 0x00002800,
diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index 92ff685d11b3..f944a15160cb 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -1393,7 +1393,7 @@ void kvm_mediated_pmu_load(struct kvm_vcpu *vcpu)
perf_pmu_partition_preload();
- perf_load_guest_context(false);
+ perf_load_guest_context(kvm_vcpu_has_perfmon_mask(vcpu));
/*
* Explicitly clear PERF_GLOBAL_CTRL, as "loading" the guest's context
@@ -1466,5 +1466,5 @@ void kvm_mediated_pmu_put(struct kvm_vcpu *vcpu)
perf_put_guest_lvtpc();
- perf_put_guest_context(false);
+ perf_put_guest_context(kvm_vcpu_has_perfmon_mask(vcpu));
}
diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h
index 2dc12e3f3af0..057e3258e473 100644
--- a/arch/x86/kvm/pmu.h
+++ b/arch/x86/kvm/pmu.h
@@ -89,6 +89,12 @@ static inline bool kvm_vcpu_has_mediated_pmu(struct kvm_vcpu *vcpu)
return enable_mediated_pmu && vcpu_to_pmu(vcpu)->version;
}
+static inline bool kvm_vcpu_has_perfmon_mask(struct kvm_vcpu *vcpu)
+{
+ return kvm_vcpu_has_mediated_pmu(vcpu) &&
+ vcpu_to_pmu(vcpu)->perfmon_mask;
+}
+
static inline unsigned long kvm_gp_pmc_mask(struct kvm_pmu *pmu)
{
return pmu->pmc_exists64 &
diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c
index 62e542eac05e..19ccc7cd319c 100644
--- a/arch/x86/kvm/vmx/pmu_intel.c
+++ b/arch/x86/kvm/vmx/pmu_intel.c
@@ -703,6 +703,21 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
pmu->pebs_enable_rsvd = ~kvm_gp_pmc_mask(pmu);
}
}
+
+ if (kvm_vcpu_has_mediated_pmu(vcpu) && perfmon_mask) {
+ pmu->perfmon_mask = ~pmu->global_status_rsvd;
+
+ /*
+ * The PerfMon mask for a particular guest must be a subset
+ * of the module-wide mask. This masks out the global bits
+ * (e.g. GLOBAL_STATUS_COND_CHG) that must be handled by the
+ * host and were removed from global_status_rsvd without
+ * checking perfmon_mask, and defends in depth against any
+ * other bits inadvertently granted to the guest.
+ */
+ pmu->perfmon_mask &= perfmon_mask;
+ vmcs_write64(PERFMON_MASK, pmu->perfmon_mask);
+ }
}
static void intel_pmu_init(struct kvm_vcpu *vcpu)
@@ -739,6 +754,7 @@ static void intel_pmu_reset(struct kvm_vcpu *vcpu)
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
pmu->perf_metrics = 0;
+ pmu->perfmon_mask = 0;
intel_pmu_release_guest_lbr_event(vcpu);
}
@@ -1021,6 +1037,16 @@ void intel_pmu_perfmon_mask_setup(void)
perfmon_mask);
perfmon_mask = 0;
}
+
+ /*
+ * perfmon_mask represents the maximum resources that any guest may
+ * have. KVM chooses to expose fewer hardware resources to guests.
+ */
+ if (perfmon_mask) {
+ kvm_pmu_cap.cntr_mask64 &= perfmon_mask;
+ kvm_pmu_cap.fixed_cntr_mask64 &=
+ (perfmon_mask >> INTEL_PMC_IDX_FIXED);
+ }
}
struct kvm_pmu_ops intel_pmu_ops __initdata = {
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index cdd141d22efa..1b42c9d6f168 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -4294,6 +4294,9 @@ static void vmx_recalc_pmu_msr_intercepts(struct kvm_vcpu *vcpu)
if (!cpu_has_save_perf_global_ctrl()) {
vm_exit_controls_bits &= ~VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL;
+ /* Module parameter validation should already prevent this. */
+ WARN_ON_ONCE(kvm_vcpu_has_perfmon_mask(vcpu));
+
if (has_mediated_pmu)
vmx_add_autostore_msr(vmx, MSR_CORE_PERF_GLOBAL_CTRL);
else
@@ -8133,7 +8136,8 @@ static __init u64 vmx_get_perf_capabilities(void)
perf_cap &= ~PERF_CAP_PEBS_BASELINE;
}
- if (enable_mediated_pmu)
+ if (enable_mediated_pmu &&
+ (!perfmon_mask || (perfmon_mask & GLOBAL_STATUS_PERF_METRICS_OVF)))
perf_cap |= kvm_host.perf_capabilities & PERF_CAP_PERF_METRICS;
return perf_cap;
--
2.55.0
next prev parent reply other threads:[~2026-08-21 22:31 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-21 22:19 [PATCH 00/23] perf/KVM: Support PMU partitioning for x86 platforms Zide Chen
2026-08-21 22:19 ` [PATCH 01/23] perf/x86/intel: Guard counter masks against zero counters Zide Chen
2026-08-21 22:19 ` [PATCH 02/23] perf, perf/x86: Pass partition mask from KVM to perf/x86 Zide Chen
2026-08-21 22:19 ` [PATCH 03/23] perf/x86: Add GUEST_PMU states for PMU partitioning Zide Chen
2026-08-21 22:19 ` [PATCH 04/23] perf/x86: Split host/guest PMI handling under " Zide Chen
2026-08-21 22:19 ` [PATCH 05/23] perf/x86: Allow exclude_host events to run in non-root mode Zide Chen
2026-08-21 22:19 ` [PATCH 06/23] perf/x86: Restrict !exclude_guest events to host-owned counters Zide Chen
2026-08-21 22:19 ` [PATCH 07/23] perf/x86: Apply PMU partition mask on static constraints Zide Chen
2026-08-21 22:19 ` [PATCH 08/23] perf/x86: Export available PMU counters to sysfs Zide Chen
2026-08-21 22:19 ` [PATCH 09/23] perf: Skip exclude_guest events on PMU partitioned counters Zide Chen
2026-08-21 22:19 ` [PATCH 10/23] perf: Reschedule events across PMU partition transitions Zide Chen
2026-08-21 22:19 ` [PATCH 11/23] perf, perf/x86: Allow host !exclude_guest events in PMU partitioning Zide Chen
2026-08-21 22:19 ` [PATCH 12/23] KVM: x86/pmu: Add the perfmon_mask module parameter Zide Chen
2026-08-21 22:19 ` Zide Chen [this message]
2026-08-21 22:19 ` [PATCH 14/23] KVM: x86/pmu, perf/x86: Update effective PMU partition mask Zide Chen
2026-08-21 22:19 ` [PATCH 15/23] KVM: x86/pmu: Relax MSR intercept policy under PerfMon masking Zide Chen
2026-08-21 22:19 ` [PATCH 16/23] KVM: x86/pmu: Handle FIXED_CTR_CTRL " Zide Chen
2026-08-21 22:19 ` [PATCH 17/23] KVM: x86/pmu: Handle GLOBAL_CTRL " Zide Chen
2026-08-21 22:19 ` [PATCH 18/23] KVM: x86/pmu: Handle GLOBAL_STATUS MSRs " Zide Chen
2026-08-21 22:19 ` [PATCH 19/23] KVM: x86/pmu: Always intercept GLOBAL_INUSE " Zide Chen
2026-08-21 22:19 ` [PATCH 20/23] KVM: x86/pmu: Request guest PMI for guest-induced PMIs Zide Chen
2026-08-21 22:20 ` [PATCH 21/23] KVM: x86/pmu: Enable PerfMon masking Zide Chen
2026-08-21 22:20 ` [PATCH 22/23] KVM: selftests: Fix PERF_METRICS test by checking FC3 availability Zide Chen
2026-08-21 22:20 ` [PATCH 23/23] KVM: selftests: Allow no general purpose counters on the host Zide Chen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260821222002.54907-14-zide.chen@intel.com \
--to=zide.chen@intel.com \
--cc=Manali.Shukla@amd.com \
--cc=Sandipan.Das@amd.com \
--cc=ak@linux.intel.com \
--cc=dapeng1.mi@linux.intel.com \
--cc=eranian@google.com \
--cc=jmattson@google.com \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mizhang@google.com \
--cc=pbonzini@redhat.com \
--cc=peterz@infradead.org \
--cc=seanjc@google.com \
--cc=xudong.hao@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox