Kernel KVM virtualization development
 help / color / mirror / Atom feed
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


  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