[PATCH 16/23] KVM: x86/pmu: Handle FIXED_CTR_CTRL under PerfMon masking

Zide Chen <[email protected]>
Newsgroups org.kernel.vger.kvm,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
PerfMon masking affects reads from and writes to this MSR. The effective
mask is defined as bits 4n+3:4n and bits 4n+35:4n+32 being set if and
only if bit 32+n of the PerfMon mask is set (for 0 <= n <= 7).

KVM doesn't support some fixed-counter features, and
pmu->fixed_ctr_ctrl_rsvd is a subset of the effective mask above, so the
existing gating in intel_pmu_set_msr() is sufficient even under PerfMon
masking.

Upon guest PMU context load, OR the guest-owned bits with whatever the
hardware currently holds for every fixed-counter index the guest does
not own, before writing the result to the MSR.

During PMU context put, host-owned fixed counters may still be scheduled
for system-wide host events, so the host-owned bits should remain
unchanged.

Signed-off-by: Zide Chen <[email protected]>
---
 arch/x86/kvm/vmx/pmu_intel.c | 40 +++++++++++++++++++++++++++++++++---
 1 file changed, 37 insertions(+), 3 deletions(-)

diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c
index 19ccc7cd319c..9236bfa15c41 100644
--- a/arch/x86/kvm/vmx/pmu_intel.c
+++ b/arch/x86/kvm/vmx/pmu_intel.c
@@ -920,6 +920,33 @@ static void intel_pmu_write_global_ctrl(u64 global_ctrl)
 	vmcs_write64(GUEST_IA32_PERF_GLOBAL_CTRL, global_ctrl);
 }
 
+static u64 intel_fixed_ctrl_host_bits(struct kvm_pmu *pmu)
+{
+	unsigned long fixed_mask;
+	u64 fixed_ctl;
+	int i;
+
+	if (!kvm_vcpu_has_perfmon_mask(pmu_to_vcpu(pmu)))
+		return 0;
+
+	fixed_mask = kvm_fixed_pmc_mask(pmu);
+
+	rdmsrq(MSR_CORE_PERF_FIXED_CTR_CTRL, fixed_ctl);
+
+	/*
+	 * Use the full per-counter nibbles (bits 4n+3:4n and 4n+35:4n+32) to
+	 * strip all bits belonging to guest-owned counters.
+	 *
+	 * pmu->fixed_ctr_ctrl_rsvd can't be used here since it can't gate bits
+	 * that are not supported by KVM.
+	 */
+	kvm_for_each_fixed_counter(i, fixed_mask)
+		fixed_ctl &= ~intel_fixed_bits_by_idx(i, GENMASK_ULL(3, 0) |
+						      GENMASK_ULL(35, 32));
+
+	return fixed_ctl;
+}
+
 static void intel_mediated_pmu_load(struct kvm_vcpu *vcpu)
 {
 	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
@@ -935,7 +962,8 @@ static void intel_mediated_pmu_load(struct kvm_vcpu *vcpu)
 	if (pmu->global_status & toggle)
 		wrmsrq(MSR_CORE_PERF_GLOBAL_STATUS_SET, pmu->global_status & toggle);
 
-	wrmsrq(MSR_CORE_PERF_FIXED_CTR_CTRL, pmu->fixed_ctr_ctrl_hw);
+	wrmsrq(MSR_CORE_PERF_FIXED_CTR_CTRL,
+	       pmu->fixed_ctr_ctrl_hw | intel_fixed_ctrl_host_bits(pmu));
 }
 
 static void intel_mediated_pmu_put(struct kvm_vcpu *vcpu)
@@ -953,9 +981,15 @@ static void intel_mediated_pmu_put(struct kvm_vcpu *vcpu)
 	 * Clear hardware FIXED_CTR_CTRL MSR to avoid information leakage and
 	 * also to avoid accidentally enabling fixed counters (based on guest
 	 * state) while running in the host, e.g. when setting global ctrl.
+	 *
+	 * Keep the host-owned counters unchanged.
 	 */
-	if (pmu->fixed_ctr_ctrl_hw)
-		wrmsrq(MSR_CORE_PERF_FIXED_CTR_CTRL, 0);
+	if (pmu->fixed_ctr_ctrl_hw) {
+		u64 fixed_ctl = intel_fixed_ctrl_host_bits(pmu);
+
+		fixed_ctl &= ~pmu->fixed_ctr_ctrl_hw;
+		wrmsrq(MSR_CORE_PERF_FIXED_CTR_CTRL, fixed_ctl);
+	}
 
 	if (kvm_vcpu_has_perf_metrics(vcpu)) {
 		pmu->perf_metrics = rdpmc(INTEL_PMC_FIXED_RDPMC_METRICS);
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.