@@ -949,6 +949,8 @@ struct kvm_vcpu_arch {
#define HOST_STATE_TRBE_EN __kvm_single_flag(state, BIT(1))
/* Hyp modified TRFCR */
#define HOST_STATE_RESTORE_TRFCR __kvm_single_flag(state, BIT(2))
+/* Host wants a different trace filters for the guest */
+#define HOST_STATE_SWAP_TRFCR __kvm_single_flag(state, BIT(3))
/* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
#define vcpu_sve_pffr(vcpu) (kern_hyp_va((vcpu)->arch.sve_state) + \
@@ -1392,6 +1394,7 @@ void kvm_clr_pmu_events(u64 clr);
bool kvm_set_pmuserenr(u64 val);
void kvm_set_pmblimitr(u64 pmblimitr);
void kvm_set_trblimitr(u64 trblimitr);
+void kvm_set_trfcr(u64 host_trfcr, u64 guest_trfcr);
#else
static inline void kvm_set_pmu_events(u64 set, struct perf_event_attr *attr) {}
static inline void kvm_clr_pmu_events(u64 clr) {}
@@ -1401,6 +1404,7 @@ static inline bool kvm_set_pmuserenr(u64 val)
}
static inline void kvm_set_pmblimitr(u64 pmblimitr) {}
static inline void kvm_set_trblimitr(u64 trblimitr) {}
+static inline void kvm_set_trfcr(u64 host_trfcr, u64 guest_trfcr) {}
#endif
void kvm_vcpu_load_vhe(struct kvm_vcpu *vcpu);
@@ -380,3 +380,19 @@ void kvm_set_trblimitr(u64 trblimitr)
host_data_clear_flag(HOST_STATE_TRBE_EN);
}
EXPORT_SYMBOL_GPL(kvm_set_trblimitr);
+
+void kvm_set_trfcr(u64 host_trfcr, u64 guest_trfcr)
+{
+ if (kvm_arm_skip_trace_state())
+ return;
+
+ if (has_vhe())
+ write_sysreg_s(guest_trfcr, SYS_TRFCR_EL12);
+ else
+ if (host_trfcr != guest_trfcr) {
+ *host_data_ptr(host_debug_state.trfcr_el1) = guest_trfcr;
+ host_data_set_flag(HOST_STATE_SWAP_TRFCR);
+ } else
+ host_data_clear_flag(HOST_STATE_SWAP_TRFCR);
+}
+EXPORT_SYMBOL_GPL(kvm_set_trfcr);
@@ -100,6 +100,15 @@ static void __debug_save_trace(void)
host_data_set_flag(HOST_STATE_RESTORE_TRFCR);
}
+static void __debug_swap_trace(void)
+{
+ u64 trfcr = read_sysreg_el1(SYS_TRFCR);
+
+ write_sysreg_el1(*host_data_ptr(host_debug_state.trfcr_el1), SYS_TRFCR);
+ *host_data_ptr(host_debug_state.trfcr_el1) = trfcr;
+ host_data_set_flag(HOST_STATE_RESTORE_TRFCR);
+}
+
static void __debug_restore_trace(void)
{
u64 trfcr_el1;
@@ -124,10 +133,14 @@ void __debug_save_host_buffers_nvhe(void)
if (!host_data_get_flag(HOST_FEAT_HAS_TRF))
return;
- /* Disable and flush Self-Hosted Trace generation */
+ /*
+ * Disable and flush Self-Hosted Trace generation for pKVM and TRBE,
+ * or swap if host requires different guest filters.
+ */
if (__debug_should_save_trace())
__debug_save_trace();
-
+ else if (host_data_get_flag(HOST_STATE_SWAP_TRFCR))
+ __debug_swap_trace();
}
void __debug_switch_to_guest(struct kvm_vcpu *vcpu)
This implements exclude/include guest rules of the active tracing session. Only do it if a different value is required for the guest, otherwise the filters remain untouched. In VHE we can just directly write the value. Signed-off-by: James Clark <james.clark@linaro.org> --- arch/arm64/include/asm/kvm_host.h | 4 ++++ arch/arm64/kvm/debug.c | 16 ++++++++++++++++ arch/arm64/kvm/hyp/nvhe/debug-sr.c | 17 +++++++++++++++-- 3 files changed, 35 insertions(+), 2 deletions(-)