[PATCH 20/23] KVM: x86/pmu: Request guest PMI for guest-induced PMIs

Zide Chen <[email protected]>
Newsgroups org.kernel.vger.kvm,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
When PMU partitioning is enabled, guest-induced PMIs that occur in
guest mode may be delivered to the host perf PMI handler, resulting
in a VM-Exit.

intel_mediated_pmu_put() reads the hardware GLOBAL_STATUS MSR into
pmu->global_status and masks it to the subset owned by the guest.
Request a guest PMI when the saved status indicates a pending guest
PMI, i.e. when

- an overflow status bit (47:0) is set for a counter whose PMI-enable
  bit is enabled; or
- a miscellaneous status bit without a corresponding PMI-enable control
  is set.

Signed-off-by: Zide Chen <[email protected]>
---
 arch/x86/kvm/pmu.c           |  3 ++-
 arch/x86/kvm/pmu.h           |  1 +
 arch/x86/kvm/vmx/pmu_intel.c | 42 ++++++++++++++++++++++++++++++++++++
 3 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index 23177c38f286..f99ddd6549f7 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -1112,7 +1112,7 @@ void kvm_pmu_destroy(struct kvm_vcpu *vcpu)
 	kvm_pmu_reset(vcpu);
 }
 
-static bool pmc_is_pmi_enabled(struct kvm_pmc *pmc)
+bool pmc_is_pmi_enabled(struct kvm_pmc *pmc)
 {
 	u8 fixed_ctr_ctrl;
 
@@ -1123,6 +1123,7 @@ static bool pmc_is_pmi_enabled(struct kvm_pmc *pmc)
 					  pmc->idx - KVM_FIXED_PMC_BASE_IDX);
 	return fixed_ctr_ctrl & INTEL_FIXED_0_ENABLE_PMI;
 }
+EXPORT_SYMBOL_FOR_KVM_INTERNAL(pmc_is_pmi_enabled);
 
 static void kvm_pmu_incr_counter(struct kvm_pmc *pmc)
 {
diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h
index 30e456302c65..4228eb49c6bf 100644
--- a/arch/x86/kvm/pmu.h
+++ b/arch/x86/kvm/pmu.h
@@ -336,6 +336,7 @@ static inline bool kvm_vcpu_has_perf_metrics(struct kvm_vcpu *vcpu)
 	return kvm_vcpu_get_perf_caps(vcpu) & PERF_CAP_PERF_METRICS;
 }
 
+bool pmc_is_pmi_enabled(struct kvm_pmc *pmc);
 void kvm_pmu_deliver_pmi(struct kvm_vcpu *vcpu);
 int kvm_pmu_rdpmc(struct kvm_vcpu *vcpu, unsigned pmc, u64 *data);
 int kvm_pmu_check_rdpmc_early(struct kvm_vcpu *vcpu, unsigned int idx);
diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c
index e43380f79c72..7fab735252d7 100644
--- a/arch/x86/kvm/vmx/pmu_intel.c
+++ b/arch/x86/kvm/vmx/pmu_intel.c
@@ -985,6 +985,46 @@ static void intel_mediated_pmu_load(struct kvm_vcpu *vcpu, u64 host_global_ctrl)
 	       pmu->fixed_ctr_ctrl_hw | intel_fixed_ctrl_host_bits(pmu));
 }
 
+static void intel_perfmon_mask_request_pmi(struct kvm_vcpu *vcpu)
+{
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+	struct kvm_pmc *pmc;
+	int i;
+
+	if (!kvm_vcpu_has_perfmon_mask(vcpu) || !pmu->global_status)
+		return;
+
+	/*
+	 * pmu->global_status should never carry a bit that isn't
+	 * guest-owned per pmu->perfmon_mask; such a bit would mean a
+	 * host-owned resource is being (mis)reported to the guest.
+	 */
+	WARN_ON_ONCE(pmu->global_status & ~pmu->perfmon_mask);
+
+	/*
+	 * Bit 48 is currently the only miscellaneous status bit (63:48) that
+	 * can be guest-owned; it indicates that a PMI is triggered, regardless
+	 * of fixed counter 3's PMI-enable state.
+	 */
+	if (pmu->global_status & GLOBAL_STATUS_PERF_METRICS_OVF) {
+		kvm_make_request(KVM_REQ_PMI, vcpu);
+		return;
+	}
+
+	/*
+	 * Match bare-metal behavior for counter bits (47:0): request a guest
+	 * PMI if any overflowed counter actually has its PMI-enable bit set.
+	 */
+	for_each_set_bit(i, (unsigned long *)&pmu->global_status,
+			 GLOBAL_STATUS_PERF_METRICS_OVF_BIT) {
+		pmc = kvm_pmc_idx_to_pmc(pmu, i);
+		if (pmc && pmc_is_pmi_enabled(pmc)) {
+			kvm_make_request(KVM_REQ_PMI, vcpu);
+			break;
+		}
+	}
+}
+
 static void intel_mediated_pmu_put(struct kvm_vcpu *vcpu)
 {
 	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
@@ -1029,6 +1069,8 @@ static void intel_mediated_pmu_put(struct kvm_vcpu *vcpu)
 		if (pmu->perf_metrics)
 			wrmsrq(MSR_PERF_METRICS, 0);
 	}
+
+	intel_perfmon_mask_request_pmi(vcpu);
 }
 
 static bool intel_pmu_validate_perfmon_mask(void)
-- 
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.