* [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
* 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
* [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