kvm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH RFC 0/3] KVM: x86/pmu: Add Intel Guest Branch Trace Store Support
@ 2022-09-26 14:29 Like Xu
  2022-09-26 14:29 ` [PATCH RFC 1/3] KVM + perf: Rename *_intel_pt_intr() for generic usage Like Xu
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Like Xu @ 2022-09-26 14:29 UTC (permalink / raw)
  To: Sean Christopherson, Peter Zijlstra
  Cc: Kan Liang, Adrian Hunter, Andi Kleen, Jim Mattson, Paolo Bonzini,
	linux-perf-users, linux-kernel, x86, kvm

When we have support for guest pebs, debug store support is implicitly
supported (if there are no hardware surprises). The debug store based
guest bts feature will also come sooner or later, in a very small effort.

One of reasons for adding the RFC tag is that there are currently two paths
for perf to inject interrupts into KVM, and if BTS is added, another one
will be added. This may not end if more perf/kvm interactions are added.

In this patch set I merged Intel BTS with Intel PT's interrupt callbacks as
a first step, but better code could perhaps be tried in the future in two ways:

- Merge KVM's intel_pt codebase into the vPMU framework,  as the previous
  merging effort of guest intel pt is not fully discussed. vPMU will support as
  much as possible the time-sharing multiplexing of host and guest for PMU
  resources (including intel_pt) instead of static partion;
- There is one more, PMI interrupts after forcing KVM to exit, re-traveled
  host idt and assigned to the host handler, then called back to kvm, then
  injected to guest, if there is hardware support and KVM clear judgment,
  interrupts from guest can be injected directly into guest without going
  through the perf subsystem, which will save a lot of overhead.

I'm willing to share more to attract more developers, but the opinions
of the key players are probably more important to the future codebase.

Back to this BTS feature, if there are no blocked comments on this patchset,
more document, selftest and kvm-unit-test will follow obviously.

Like Xu (3):
  KVM + perf: Rename *_intel_pt_intr() for generic usage
  KVM + perf: Passing vector into generic perf_handle_guest_intr()
  KVM: x86/pmu: Add Intel Guest Branch Trace Store Support

 arch/x86/events/intel/bts.c     |  3 +++
 arch/x86/events/intel/core.c    |  2 +-
 arch/x86/include/asm/kvm_host.h |  8 +++++-
 arch/x86/kvm/pmu.h              |  3 +++
 arch/x86/kvm/vmx/capabilities.h |  7 ++++++
 arch/x86/kvm/vmx/vmx.c          | 43 +++++++++++++++++++++++++++------
 arch/x86/kvm/x86.c              |  2 +-
 include/linux/kvm_host.h        |  2 +-
 include/linux/perf_event.h      | 12 +++++----
 kernel/events/core.c            |  9 +++----
 virt/kvm/kvm_main.c             |  6 ++---
 11 files changed, 72 insertions(+), 25 deletions(-)

-- 
2.37.3


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH RFC 1/3] KVM + perf: Rename *_intel_pt_intr() for generic usage
  2022-09-26 14:29 [PATCH RFC 0/3] KVM: x86/pmu: Add Intel Guest Branch Trace Store Support Like Xu
@ 2022-09-26 14:29 ` Like Xu
  2022-10-03 19:39   ` Sean Christopherson
  2022-09-26 14:29 ` [PATCH RFC 2/3] KVM + perf: Passing vector into generic perf_handle_guest_intr() Like Xu
  2022-09-26 14:29 ` [PATCH RFC 3/3] KVM: x86/pmu: Add Intel Guest Branch Trace Store Support Like Xu
  2 siblings, 1 reply; 5+ messages in thread
From: Like Xu @ 2022-09-26 14:29 UTC (permalink / raw)
  To: Sean Christopherson, Peter Zijlstra
  Cc: Kan Liang, Adrian Hunter, Andi Kleen, Jim Mattson, Paolo Bonzini,
	linux-perf-users, linux-kernel, x86, kvm

From: Like Xu <likexu@tencent.com>

The perf_guest_info_callbacks is common to KVM, while intel_pt is not,
not even common to x86. In the VMX context, it makes sense to hook
up the intel_pt specific hook, and given the uniqueness of this usage,
calling the  generic callback in the explicit location of the perf context
is not functionally broken.

Rename a bunch of intel_pt_intr() functions to the generic guest_intr().
No functional change intended.

Signed-off-by: Like Xu <likexu@tencent.com>
---
 arch/x86/events/intel/core.c    |  2 +-
 arch/x86/include/asm/kvm_host.h |  2 +-
 arch/x86/kvm/vmx/vmx.c          |  6 +++---
 arch/x86/kvm/x86.c              |  2 +-
 include/linux/perf_event.h      | 12 +++++++-----
 kernel/events/core.c            |  9 ++++-----
 virt/kvm/kvm_main.c             |  6 +++---
 7 files changed, 20 insertions(+), 19 deletions(-)

diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c
index 65906241207e..48e313265a15 100644
--- a/arch/x86/events/intel/core.c
+++ b/arch/x86/events/intel/core.c
@@ -2962,7 +2962,7 @@ static int handle_pmi_common(struct pt_regs *regs, u64 status)
 	 */
 	if (__test_and_clear_bit(GLOBAL_STATUS_TRACE_TOPAPMI_BIT, (unsigned long *)&status)) {
 		handled++;
-		if (!perf_guest_handle_intel_pt_intr())
+		if (!perf_handle_guest_intr())
 			intel_pt_interrupt();
 	}
 
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index f1d3ae0b57bb..8cf472a4ca06 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1666,7 +1666,7 @@ struct kvm_x86_init_ops {
 	int (*disabled_by_bios)(void);
 	int (*check_processor_compatibility)(void);
 	int (*hardware_setup)(void);
-	unsigned int (*handle_intel_pt_intr)(void);
+	unsigned int (*handle_intr)(void);
 
 	struct kvm_x86_ops *runtime_ops;
 	struct kvm_pmu_ops *pmu_ops;
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index c9b49a09e6b5..a1856b11467d 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -8374,9 +8374,9 @@ static __init int hardware_setup(void)
 	if (!enable_ept || !enable_pmu || !cpu_has_vmx_intel_pt())
 		pt_mode = PT_MODE_SYSTEM;
 	if (pt_mode == PT_MODE_HOST_GUEST)
-		vmx_init_ops.handle_intel_pt_intr = vmx_handle_intel_pt_intr;
+		vmx_init_ops.handle_intr = vmx_handle_intel_pt_intr;
 	else
-		vmx_init_ops.handle_intel_pt_intr = NULL;
+		vmx_init_ops.handle_intr = NULL;
 
 	setup_default_sgx_lepubkeyhash();
 
@@ -8405,7 +8405,7 @@ static struct kvm_x86_init_ops vmx_init_ops __initdata = {
 	.disabled_by_bios = vmx_disabled_by_bios,
 	.check_processor_compatibility = vmx_check_processor_compat,
 	.hardware_setup = hardware_setup,
-	.handle_intel_pt_intr = NULL,
+	.handle_intr = NULL,
 
 	.runtime_ops = &vmx_x86_ops,
 	.pmu_ops = &intel_pmu_ops,
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 6a0e5107de5c..6eff470d3f7d 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -11990,7 +11990,7 @@ int kvm_arch_hardware_setup(void *opaque)
 
 	kvm_ops_update(ops);
 
-	kvm_register_perf_callbacks(ops->handle_intel_pt_intr);
+	kvm_register_perf_callbacks(ops->handle_intr);
 
 	if (!kvm_cpu_cap_has(X86_FEATURE_XSAVES))
 		kvm_caps.supported_xss = 0;
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index ee8b9ecdc03b..6149a977bbd0 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -32,7 +32,7 @@
 struct perf_guest_info_callbacks {
 	unsigned int			(*state)(void);
 	unsigned long			(*get_ip)(void);
-	unsigned int			(*handle_intel_pt_intr)(void);
+	unsigned int			(*handle_intr)(void);
 };
 
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
@@ -1267,7 +1267,7 @@ extern struct perf_guest_info_callbacks __rcu *perf_guest_cbs;
 
 DECLARE_STATIC_CALL(__perf_guest_state, *perf_guest_cbs->state);
 DECLARE_STATIC_CALL(__perf_guest_get_ip, *perf_guest_cbs->get_ip);
-DECLARE_STATIC_CALL(__perf_guest_handle_intel_pt_intr, *perf_guest_cbs->handle_intel_pt_intr);
+DECLARE_STATIC_CALL(__perf_handle_guest_intr, *perf_guest_cbs->handle_intr);
 
 static inline unsigned int perf_guest_state(void)
 {
@@ -1277,16 +1277,18 @@ static inline unsigned long perf_guest_get_ip(void)
 {
 	return static_call(__perf_guest_get_ip)();
 }
-static inline unsigned int perf_guest_handle_intel_pt_intr(void)
+
+static inline unsigned int perf_handle_guest_intr(void)
 {
-	return static_call(__perf_guest_handle_intel_pt_intr)();
+	return static_call(__perf_handle_guest_intr)();
 }
+
 extern void perf_register_guest_info_callbacks(struct perf_guest_info_callbacks *cbs);
 extern void perf_unregister_guest_info_callbacks(struct perf_guest_info_callbacks *cbs);
 #else
 static inline unsigned int perf_guest_state(void)		 { return 0; }
 static inline unsigned long perf_guest_get_ip(void)		 { return 0; }
-static inline unsigned int perf_guest_handle_intel_pt_intr(void) { return 0; }
+static inline unsigned int perf_handle_guest_intr(void) { return 0; }
 #endif /* CONFIG_GUEST_PERF_EVENTS */
 
 extern void perf_event_exec(void);
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 2621fd24ad26..bb1d1925f153 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -6510,7 +6510,7 @@ struct perf_guest_info_callbacks __rcu *perf_guest_cbs;
 
 DEFINE_STATIC_CALL_RET0(__perf_guest_state, *perf_guest_cbs->state);
 DEFINE_STATIC_CALL_RET0(__perf_guest_get_ip, *perf_guest_cbs->get_ip);
-DEFINE_STATIC_CALL_RET0(__perf_guest_handle_intel_pt_intr, *perf_guest_cbs->handle_intel_pt_intr);
+DEFINE_STATIC_CALL_RET0(__perf_handle_guest_intr, *perf_guest_cbs->handle_intr);
 
 void perf_register_guest_info_callbacks(struct perf_guest_info_callbacks *cbs)
 {
@@ -6522,9 +6522,8 @@ void perf_register_guest_info_callbacks(struct perf_guest_info_callbacks *cbs)
 	static_call_update(__perf_guest_get_ip, cbs->get_ip);
 
 	/* Implementing ->handle_intel_pt_intr is optional. */
-	if (cbs->handle_intel_pt_intr)
-		static_call_update(__perf_guest_handle_intel_pt_intr,
-				   cbs->handle_intel_pt_intr);
+	if (cbs->handle_intr)
+		static_call_update(__perf_handle_guest_intr, cbs->handle_intr);
 }
 EXPORT_SYMBOL_GPL(perf_register_guest_info_callbacks);
 
@@ -6536,7 +6535,7 @@ void perf_unregister_guest_info_callbacks(struct perf_guest_info_callbacks *cbs)
 	rcu_assign_pointer(perf_guest_cbs, NULL);
 	static_call_update(__perf_guest_state, (void *)&__static_call_return0);
 	static_call_update(__perf_guest_get_ip, (void *)&__static_call_return0);
-	static_call_update(__perf_guest_handle_intel_pt_intr,
+	static_call_update(__perf_handle_guest_intr,
 			   (void *)&__static_call_return0);
 	synchronize_rcu();
 }
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 584a5bab3af3..8190af3a12fa 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -5785,12 +5785,12 @@ static unsigned long kvm_guest_get_ip(void)
 static struct perf_guest_info_callbacks kvm_guest_cbs = {
 	.state			= kvm_guest_state,
 	.get_ip			= kvm_guest_get_ip,
-	.handle_intel_pt_intr	= NULL,
+	.handle_intr	= NULL,
 };
 
-void kvm_register_perf_callbacks(unsigned int (*pt_intr_handler)(void))
+void kvm_register_perf_callbacks(unsigned int (*handler)(void))
 {
-	kvm_guest_cbs.handle_intel_pt_intr = pt_intr_handler;
+	kvm_guest_cbs.handle_intr = handler;
 	perf_register_guest_info_callbacks(&kvm_guest_cbs);
 }
 void kvm_unregister_perf_callbacks(void)
-- 
2.37.3


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH RFC 2/3] KVM + perf: Passing vector into generic perf_handle_guest_intr()
  2022-09-26 14:29 [PATCH RFC 0/3] KVM: x86/pmu: Add Intel Guest Branch Trace Store Support Like Xu
  2022-09-26 14:29 ` [PATCH RFC 1/3] KVM + perf: Rename *_intel_pt_intr() for generic usage Like Xu
@ 2022-09-26 14:29 ` Like Xu
  2022-09-26 14:29 ` [PATCH RFC 3/3] KVM: x86/pmu: Add Intel Guest Branch Trace Store Support Like Xu
  2 siblings, 0 replies; 5+ messages in thread
From: Like Xu @ 2022-09-26 14:29 UTC (permalink / raw)
  To: Sean Christopherson, Peter Zijlstra
  Cc: Kan Liang, Adrian Hunter, Andi Kleen, Jim Mattson, Paolo Bonzini,
	linux-perf-users, linux-kernel, x86, kvm

From: Like Xu <likexu@tencent.com>

To reuse the interrupt callback function registered by KVM in perf, add
incoming parameter to distinguish the context of the caller, which is
currently only supported in the case of GUEST_INTEL_PT.

No functional change intended.

Signed-off-by: Like Xu <likexu@tencent.com>
---
 arch/x86/events/intel/bts.c     | 1 +
 arch/x86/events/intel/core.c    | 2 +-
 arch/x86/include/asm/kvm_host.h | 7 ++++++-
 arch/x86/kvm/vmx/vmx.c          | 7 +++++--
 include/linux/kvm_host.h        | 2 +-
 include/linux/perf_event.h      | 8 ++++----
 virt/kvm/kvm_main.c             | 2 +-
 7 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/arch/x86/events/intel/bts.c b/arch/x86/events/intel/bts.c
index 974e917e65b2..ffdcde5b97b1 100644
--- a/arch/x86/events/intel/bts.c
+++ b/arch/x86/events/intel/bts.c
@@ -14,6 +14,7 @@
 #include <linux/debugfs.h>
 #include <linux/device.h>
 #include <linux/coredump.h>
+#include <linux/kvm_host.h>
 
 #include <linux/sizes.h>
 #include <asm/perf_event.h>
diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c
index 48e313265a15..a7b5237d5a4e 100644
--- a/arch/x86/events/intel/core.c
+++ b/arch/x86/events/intel/core.c
@@ -2962,7 +2962,7 @@ static int handle_pmi_common(struct pt_regs *regs, u64 status)
 	 */
 	if (__test_and_clear_bit(GLOBAL_STATUS_TRACE_TOPAPMI_BIT, (unsigned long *)&status)) {
 		handled++;
-		if (!perf_handle_guest_intr())
+		if (!perf_handle_guest_intr(GUEST_INTEL_PT))
 			intel_pt_interrupt();
 	}
 
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 8cf472a4ca06..166a77a61f2d 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1661,12 +1661,17 @@ struct kvm_x86_nested_ops {
 	uint16_t (*get_evmcs_version)(struct kvm_vcpu *vcpu);
 };
 
+enum {
+	GUEST_INTEL_PT = 0,
+	GUEST_INVALID
+};
+
 struct kvm_x86_init_ops {
 	int (*cpu_has_kvm_support)(void);
 	int (*disabled_by_bios)(void);
 	int (*check_processor_compatibility)(void);
 	int (*hardware_setup)(void);
-	unsigned int (*handle_intr)(void);
+	unsigned int (*handle_intr)(unsigned int vector);
 
 	struct kvm_x86_ops *runtime_ops;
 	struct kvm_pmu_ops *pmu_ops;
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index a1856b11467d..3622323d57c2 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -8146,7 +8146,7 @@ static struct kvm_x86_ops vmx_x86_ops __initdata = {
 	.vcpu_deliver_sipi_vector = kvm_vcpu_deliver_sipi_vector,
 };
 
-static unsigned int vmx_handle_intel_pt_intr(void)
+static unsigned int vmx_handle_guest_intr(unsigned int vector)
 {
 	struct kvm_vcpu *vcpu = kvm_get_running_vcpu();
 
@@ -8154,6 +8154,9 @@ static unsigned int vmx_handle_intel_pt_intr(void)
 	if (!vcpu || !kvm_handling_nmi_from_guest(vcpu))
 		return 0;
 
+	if (vector >= GUEST_INVALID)
+		return 0;
+
 	kvm_make_request(KVM_REQ_PMI, vcpu);
 	__set_bit(MSR_CORE_PERF_GLOBAL_OVF_CTRL_TRACE_TOPA_PMI_BIT,
 		  (unsigned long *)&vcpu->arch.pmu.global_status);
@@ -8374,7 +8377,7 @@ static __init int hardware_setup(void)
 	if (!enable_ept || !enable_pmu || !cpu_has_vmx_intel_pt())
 		pt_mode = PT_MODE_SYSTEM;
 	if (pt_mode == PT_MODE_HOST_GUEST)
-		vmx_init_ops.handle_intr = vmx_handle_intel_pt_intr;
+		vmx_init_ops.handle_intr = vmx_handle_guest_intr;
 	else
 		vmx_init_ops.handle_intr = NULL;
 
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index f4519d3689e1..91f3752906c5 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -1555,7 +1555,7 @@ static inline bool kvm_arch_intc_initialized(struct kvm *kvm)
 #ifdef CONFIG_GUEST_PERF_EVENTS
 unsigned long kvm_arch_vcpu_get_ip(struct kvm_vcpu *vcpu);
 
-void kvm_register_perf_callbacks(unsigned int (*pt_intr_handler)(void));
+void kvm_register_perf_callbacks(unsigned int (*handler)(unsigned int flag));
 void kvm_unregister_perf_callbacks(void);
 #else
 static inline void kvm_register_perf_callbacks(void *ign) {}
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 6149a977bbd0..a8937d06ff7c 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -32,7 +32,7 @@
 struct perf_guest_info_callbacks {
 	unsigned int			(*state)(void);
 	unsigned long			(*get_ip)(void);
-	unsigned int			(*handle_intr)(void);
+	unsigned int			(*handle_intr)(unsigned int flag);
 };
 
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
@@ -1278,9 +1278,9 @@ static inline unsigned long perf_guest_get_ip(void)
 	return static_call(__perf_guest_get_ip)();
 }
 
-static inline unsigned int perf_handle_guest_intr(void)
+static inline unsigned int perf_handle_guest_intr(unsigned int vector)
 {
-	return static_call(__perf_handle_guest_intr)();
+	return static_call(__perf_handle_guest_intr)(vector);
 }
 
 extern void perf_register_guest_info_callbacks(struct perf_guest_info_callbacks *cbs);
@@ -1288,7 +1288,7 @@ extern void perf_unregister_guest_info_callbacks(struct perf_guest_info_callback
 #else
 static inline unsigned int perf_guest_state(void)		 { return 0; }
 static inline unsigned long perf_guest_get_ip(void)		 { return 0; }
-static inline unsigned int perf_handle_guest_intr(void) { return 0; }
+static inline unsigned int perf_handle_guest_intr(unsigned int vector) { return 0; }
 #endif /* CONFIG_GUEST_PERF_EVENTS */
 
 extern void perf_event_exec(void);
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 8190af3a12fa..cc46f13bd133 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -5788,7 +5788,7 @@ static struct perf_guest_info_callbacks kvm_guest_cbs = {
 	.handle_intr	= NULL,
 };
 
-void kvm_register_perf_callbacks(unsigned int (*handler)(void))
+void kvm_register_perf_callbacks(unsigned int (*handler)(unsigned int vector))
 {
 	kvm_guest_cbs.handle_intr = handler;
 	perf_register_guest_info_callbacks(&kvm_guest_cbs);
-- 
2.37.3


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH RFC 3/3] KVM: x86/pmu: Add Intel Guest Branch Trace Store Support
  2022-09-26 14:29 [PATCH RFC 0/3] KVM: x86/pmu: Add Intel Guest Branch Trace Store Support Like Xu
  2022-09-26 14:29 ` [PATCH RFC 1/3] KVM + perf: Rename *_intel_pt_intr() for generic usage Like Xu
  2022-09-26 14:29 ` [PATCH RFC 2/3] KVM + perf: Passing vector into generic perf_handle_guest_intr() Like Xu
@ 2022-09-26 14:29 ` Like Xu
  2 siblings, 0 replies; 5+ messages in thread
From: Like Xu @ 2022-09-26 14:29 UTC (permalink / raw)
  To: Sean Christopherson, Peter Zijlstra
  Cc: Kan Liang, Adrian Hunter, Andi Kleen, Jim Mattson, Paolo Bonzini,
	linux-perf-users, linux-kernel, x86, kvm

From: Like Xu <likexu@tencent.com>

The processor supports the Branch Trace Store facility (BTS) if it has DS
buffer and the MISC_ENABLE_BTS_UNAVAIL (RO) bit is cleared. The processor
can supports the CPL-qualified branch trace mechanism (DSCPL) if
CPUID.01H:ECX[bit 4] = 1.

To support guest BTS, we need expose three IA32_DEBUGCTL bits to the guest:
The TR bit makes processor to send the branch record out on the system bus
as a branch trace message (BTM) when it detects a taken branch, interrupt,
or exception. The BTS bit makes processor to log BTMs to a memory-resident
BTS buffer that is part of the DS save area. The BTINT bit makes processor
generates an interrupt when the BTS buffer is full.

A simple perf test case could be:
	perf record --per-thread -e intel_bts// ./workload
and a valid sample looks like:
	branches:            401243 cmp_end+0x0 (./workload)
			=> ffffffffb6e01410 asm_exc_nmi+0x0 ([kernel.kallsyms])

Signed-off-by: Like Xu <likexu@tencent.com>
---
 arch/x86/events/intel/bts.c     |  2 ++
 arch/x86/include/asm/kvm_host.h |  1 +
 arch/x86/kvm/pmu.h              |  3 +++
 arch/x86/kvm/vmx/capabilities.h |  7 +++++++
 arch/x86/kvm/vmx/vmx.c          | 32 ++++++++++++++++++++++++++++----
 5 files changed, 41 insertions(+), 4 deletions(-)

diff --git a/arch/x86/events/intel/bts.c b/arch/x86/events/intel/bts.c
index ffdcde5b97b1..32a7bfe24deb 100644
--- a/arch/x86/events/intel/bts.c
+++ b/arch/x86/events/intel/bts.c
@@ -463,6 +463,8 @@ int intel_bts_interrupt(void)
 	 */
 	if (ds && (ds->bts_index >= ds->bts_interrupt_threshold))
 		handled = 1;
+	else if (perf_guest_state() && perf_handle_guest_intr(GUEST_INTEL_BTS))
+		return 1;
 
 	/*
 	 * this is wrapped in intel_bts_enable_local/intel_bts_disable_local,
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 166a77a61f2d..3b0116340399 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1663,6 +1663,7 @@ struct kvm_x86_nested_ops {
 
 enum {
 	GUEST_INTEL_PT = 0,
+	GUEST_INTEL_BTS,
 	GUEST_INVALID
 };
 
diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h
index 889d064d5ddd..bd3eb5339376 100644
--- a/arch/x86/kvm/pmu.h
+++ b/arch/x86/kvm/pmu.h
@@ -11,6 +11,9 @@
 #define MSR_IA32_MISC_ENABLE_PMU_RO_MASK (MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL |	\
 					  MSR_IA32_MISC_ENABLE_BTS_UNAVAIL)
 
+#define DEBUGCTLMSR_BTS_MASK		(DEBUGCTLMSR_TR | DEBUGCTLMSR_BTS | DEBUGCTLMSR_BTINT)
+#define DEBUGCTLMSR_DSCPL_MASK		(DEBUGCTLMSR_BTS_OFF_OS | DEBUGCTLMSR_BTS_OFF_USR)
+
 /* retrieve the 4 bits for EN and PMI out of IA32_FIXED_CTR_CTRL */
 #define fixed_ctrl_field(ctrl_reg, idx) (((ctrl_reg) >> ((idx)*4)) & 0xf)
 
diff --git a/arch/x86/kvm/vmx/capabilities.h b/arch/x86/kvm/vmx/capabilities.h
index 4dc4bbe18821..cd3b97528ab0 100644
--- a/arch/x86/kvm/vmx/capabilities.h
+++ b/arch/x86/kvm/vmx/capabilities.h
@@ -435,6 +435,13 @@ static inline u64 vmx_supported_debugctl(void)
 	if (vmx_get_perf_capabilities() & PMU_CAP_LBR_FMT)
 		debugctl |= DEBUGCTLMSR_LBR_MASK;
 
+	if (vmx_pebs_supported() && boot_cpu_has(X86_FEATURE_BTS)) {
+		debugctl |= DEBUGCTLMSR_BTS_MASK;
+		/* CPL-Qualified Branch Trace Mechanism */
+		if (boot_cpu_has(X86_FEATURE_DSCPL))
+			debugctl |= DEBUGCTLMSR_DSCPL_MASK;
+	}
+
 	return debugctl;
 }
 
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 3622323d57c2..cd396ca3c001 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -2016,6 +2016,13 @@ static u64 vcpu_supported_debugctl(struct kvm_vcpu *vcpu)
 	if (!guest_cpuid_has(vcpu, X86_FEATURE_BUS_LOCK_DETECT))
 		debugctl &= ~DEBUGCTLMSR_BUS_LOCK_DETECT;
 
+	if (!guest_cpuid_has(vcpu, X86_FEATURE_DS) ||
+	    (vcpu->arch.ia32_misc_enable_msr & MSR_IA32_MISC_ENABLE_BTS_UNAVAIL)) {
+		debugctl &= ~(DEBUGCTLMSR_BTS_MASK | DEBUGCTLMSR_DSCPL_MASK);
+	} else if (!guest_cpuid_has(vcpu, X86_FEATURE_DSCPL)) {
+		debugctl &= ~DEBUGCTLMSR_DSCPL_MASK;
+	}
+
 	return debugctl;
 }
 
@@ -7691,6 +7698,8 @@ static __init void vmx_set_cpu_caps(void)
 	if (vmx_pebs_supported()) {
 		kvm_cpu_cap_check_and_set(X86_FEATURE_DS);
 		kvm_cpu_cap_check_and_set(X86_FEATURE_DTES64);
+		if (kvm_cpu_cap_has(X86_FEATURE_DS))
+			kvm_cpu_cap_check_and_set(X86_FEATURE_DSCPL);
 	}
 
 	if (!enable_pmu)
@@ -8149,6 +8158,7 @@ static struct kvm_x86_ops vmx_x86_ops __initdata = {
 static unsigned int vmx_handle_guest_intr(unsigned int vector)
 {
 	struct kvm_vcpu *vcpu = kvm_get_running_vcpu();
+	u64 data;
 
 	/* '0' on failure so that the !PT case can use a RET0 static call. */
 	if (!vcpu || !kvm_handling_nmi_from_guest(vcpu))
@@ -8157,10 +8167,24 @@ static unsigned int vmx_handle_guest_intr(unsigned int vector)
 	if (vector >= GUEST_INVALID)
 		return 0;
 
-	kvm_make_request(KVM_REQ_PMI, vcpu);
-	__set_bit(MSR_CORE_PERF_GLOBAL_OVF_CTRL_TRACE_TOPA_PMI_BIT,
-		  (unsigned long *)&vcpu->arch.pmu.global_status);
-	return 1;
+	switch (vector) {
+	case GUEST_INTEL_PT:
+		__set_bit(MSR_CORE_PERF_GLOBAL_OVF_CTRL_TRACE_TOPA_PMI_BIT,
+			  (unsigned long *)&vcpu->arch.pmu.global_status);
+		kvm_make_request(KVM_REQ_PMI, vcpu);
+		return 1;
+	case GUEST_INTEL_BTS:
+		data = vmcs_read64(GUEST_IA32_DEBUGCTL);
+		if ((data & DEBUGCTLMSR_BTS_MASK) == DEBUGCTLMSR_BTS_MASK) {
+			kvm_make_request(KVM_REQ_PMI, vcpu);
+			return 1;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
 }
 
 static __init void vmx_setup_user_return_msrs(void)
-- 
2.37.3


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH RFC 1/3] KVM + perf: Rename *_intel_pt_intr() for generic usage
  2022-09-26 14:29 ` [PATCH RFC 1/3] KVM + perf: Rename *_intel_pt_intr() for generic usage Like Xu
@ 2022-10-03 19:39   ` Sean Christopherson
  0 siblings, 0 replies; 5+ messages in thread
From: Sean Christopherson @ 2022-10-03 19:39 UTC (permalink / raw)
  To: Like Xu
  Cc: Peter Zijlstra, Kan Liang, Adrian Hunter, Andi Kleen,
	Jim Mattson, Paolo Bonzini, linux-perf-users, linux-kernel, x86,
	kvm

On Mon, Sep 26, 2022, Like Xu wrote:
> From: Like Xu <likexu@tencent.com>
> 
> The perf_guest_info_callbacks is common to KVM, while intel_pt is not,
> not even common to x86. In the VMX context, it makes sense to hook
> up the intel_pt specific hook, and given the uniqueness of this usage,
> calling the  generic callback in the explicit location of the perf context
> is not functionally broken.

But it's extremely misleading.  If I were a developer writing the perf hooks for
a different architecture, I would expect perf_handle_guest_intr() to be called on
_every_ perf interrupt that occurred in the guest.

Genericizing the hook also complicates wiring up the hook and consuming the interrupt
type.  E.g. patch 3 is buggy; it wires up the VMX handler if and only if PT is in
PT_MODE_HOST_GUEST, and then takes a dependency on that buggy behavior by not
checking if Intel PT is supported in the now-generic vmx_handle_guest_intr().

This also doesn't really clean up the API from a non-x86 perspective, it just doesn't
make it any worse, i.e. other architectures are still exposed to an x86-specific hook.

Unless we anticipate ARM or RISC-V (which IIRC is gaining PMU support "soon") needing
to hook into "special" perf interrupts, it might be better to figure out a way to make
the hooks themselves more extensible for per-arch behavior.  E.g similar to
kvm_vcpu and kvm_vcpu_arch, add an embedded arch (or vice versa) struct in
perf_guest_info_callbacks plus a perf-internal arch hook to update static calls,
and use that to wire up handle_intel_pt_int for x86.  It'll require more work up
front, but in theory it will require less maintenance in the long run.

> Rename a bunch of intel_pt_intr() functions to the generic guest_intr().
> No functional change intended.

This changelog never says _why_.  Looking forward, the reason for the rename is
to piggyback the hook for BTS.


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2022-10-03 19:39 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-26 14:29 [PATCH RFC 0/3] KVM: x86/pmu: Add Intel Guest Branch Trace Store Support Like Xu
2022-09-26 14:29 ` [PATCH RFC 1/3] KVM + perf: Rename *_intel_pt_intr() for generic usage Like Xu
2022-10-03 19:39   ` Sean Christopherson
2022-09-26 14:29 ` [PATCH RFC 2/3] KVM + perf: Passing vector into generic perf_handle_guest_intr() Like Xu
2022-09-26 14:29 ` [PATCH RFC 3/3] KVM: x86/pmu: Add Intel Guest Branch Trace Store Support Like Xu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).