diff --git a/arch/x86/kernel/hw_breakpoint.c b/arch/x86/kernel/hw_breakpoint.c
index f846c15f21ca..0473a5c95856 100644
--- a/arch/x86/kernel/hw_breakpoint.c
+++ b/arch/x86/kernel/hw_breakpoint.c
@@ -102,6 +102,9 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
lockdep_assert_irqs_disabled();
+ if (perf_guest_in_guest())
+ return -EBUSY;
+
for (i = 0; i < HBP_NUM; i++) {
struct perf_event **slot = this_cpu_ptr(&bp_per_reg[i]);
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 5842552294c1..194e69270460 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -1677,8 +1677,8 @@ struct perf_guest_info_callbacks {
unsigned int (*state)(void);
unsigned long (*get_ip)(void);
unsigned int (*handle_intel_pt_intr)(void);
-
void (*handle_mediated_pmi)(void);
+ bool (*in_guest)(void);
};
#ifdef CONFIG_GUEST_PERF_EVENTS@@ -1689,6 +1689,7 @@ 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_guest_handle_mediated_pmi, *perf_guest_cbs->handle_mediated_pmi);
+DECLARE_STATIC_CALL(__perf_guest_in_guest, *perf_guest_cbs->in_guest);
static inline unsigned int perf_guest_state(void)
{@@ -1710,6 +1711,11 @@ static inline void perf_guest_handle_mediated_pmi(void)
static_call(__perf_guest_handle_mediated_pmi)();
}
+static inline bool perf_guest_in_guest(void)
+{
+ return static_call(__perf_guest_in_guest)();
+}
+
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);
@@ -1718,6 +1724,7 @@ extern void perf_unregister_guest_info_callbacks(struct perf_guest_info_callback
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 bool perf_guest_in_guest(void) { return false; }
#endif /* !CONFIG_GUEST_PERF_EVENTS */
diff --git a/kernel/events/core.c b/kernel/events/core.c
index a6c8e38a3110..c5dead7c5f71 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -7749,6 +7749,7 @@ 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_guest_handle_mediated_pmi, *perf_guest_cbs->handle_mediated_pmi);
+DEFINE_STATIC_CALL_RET0(__perf_guest_in_guest, *perf_guest_cbs->in_guest);
void perf_register_guest_info_callbacks(struct perf_guest_info_callbacks *cbs)
{@@ -7767,6 +7768,9 @@ void perf_register_guest_info_callbacks(struct perf_guest_info_callbacks *cbs)
if (cbs->handle_mediated_pmi)
static_call_update(__perf_guest_handle_mediated_pmi,
cbs->handle_mediated_pmi);
+
+ if (cbs->in_guest)
+ static_call_update(__perf_guest_in_guest, cbs->in_guest);
}
EXPORT_SYMBOL_GPL(perf_register_guest_info_callbacks);
@@ -7780,6 +7784,7 @@ void perf_unregister_guest_info_callbacks(struct perf_guest_info_callbacks *cbs)
static_call_update(__perf_guest_get_ip, (void *)&__static_call_return0);
static_call_update(__perf_guest_handle_intel_pt_intr, (void *)&__static_call_return0);
static_call_update(__perf_guest_handle_mediated_pmi, (void *)&__static_call_return0);
+ static_call_update(__perf_guest_in_guest, (void *)&__static_call_return0);
synchronize_rcu();
}
EXPORT_SYMBOL_GPL(perf_unregister_guest_info_callbacks);
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 65eb26a0520d..7779d500fe77 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -6476,11 +6476,23 @@ static unsigned long kvm_guest_get_ip(void)
return kvm_arch_vcpu_get_ip(vcpu);
}
+static bool kvm_guest_in_guest(void)
+{
+ struct kvm_vcpu *vcpu = kvm_get_running_vcpu();
+
+ if (!vcpu)
+ return false;
+
+ return READ_ONCE(vcpu->mode) == IN_GUEST_MODE ||
+ READ_ONCE(vcpu->mode) == EXITING_GUEST_MODE;
+}
+
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_mediated_pmi = NULL,
+ .in_guest = kvm_guest_in_guest,
};
void __kvm_register_perf_callbacks(unsigned int (*pt_intr_handler)(void),