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(-)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index a8846689512b..9109d10c656e 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -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); diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c index e99df2c3f62a..9acec1b67d5f 100644 --- a/arch/arm64/kvm/debug.c +++ b/arch/arm64/kvm/debug.c @@ -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); diff --git a/arch/arm64/kvm/hyp/nvhe/debug-sr.c b/arch/arm64/kvm/hyp/nvhe/debug-sr.c index 17c23e52f5f4..47602c4d160a 100644 --- a/arch/arm64/kvm/hyp/nvhe/debug-sr.c +++ b/arch/arm64/kvm/hyp/nvhe/debug-sr.c @@ -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)