Skip to content

Commit a665e3b

Browse files
james-c-linaroMarc Zyngier
authored andcommitted
KVM: arm64: coresight: Give TRBE enabled state to KVM
Currently in nVHE, KVM has to check if TRBE is enabled on every guest switch even if it was never used. Because it's a debug feature and is more likely to not be used than used, give KVM the TRBE buffer status to allow a much simpler and faster do-nothing path in the hyp. Protected mode now disables trace regardless of TRBE (because trfcr_while_in_guest is always 0), which was not previously done. However, it continues to flush whenever the buffer is enabled regardless of the filter status. This avoids the hypothetical case of a host that had disabled the filter but not flushed which would arise if only doing the flush when the filter was enabled. Signed-off-by: James Clark <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Marc Zyngier <[email protected]>
1 parent a2b579c commit a665e3b

File tree

4 files changed

+79
-28
lines changed

4 files changed

+79
-28
lines changed

arch/arm64/include/asm/kvm_host.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,8 @@ struct kvm_host_data {
614614
#define KVM_HOST_DATA_FLAG_HAS_TRBE 1
615615
#define KVM_HOST_DATA_FLAG_HOST_SVE_ENABLED 2
616616
#define KVM_HOST_DATA_FLAG_HOST_SME_ENABLED 3
617+
#define KVM_HOST_DATA_FLAG_TRBE_ENABLED 4
618+
#define KVM_HOST_DATA_FLAG_EL1_TRACING_CONFIGURED 5
617619
unsigned long flags;
618620

619621
struct kvm_cpu_context host_ctxt;
@@ -659,6 +661,9 @@ struct kvm_host_data {
659661
u64 mdcr_el2;
660662
} host_debug_state;
661663

664+
/* Guest trace filter value */
665+
u64 trfcr_while_in_guest;
666+
662667
/* Number of programmable event counters (PMCR_EL0.N) for this CPU */
663668
unsigned int nr_event_counters;
664669

@@ -1381,13 +1386,17 @@ static inline bool kvm_pmu_counter_deferred(struct perf_event_attr *attr)
13811386
void kvm_set_pmu_events(u64 set, struct perf_event_attr *attr);
13821387
void kvm_clr_pmu_events(u64 clr);
13831388
bool kvm_set_pmuserenr(u64 val);
1389+
void kvm_enable_trbe(void);
1390+
void kvm_disable_trbe(void);
13841391
#else
13851392
static inline void kvm_set_pmu_events(u64 set, struct perf_event_attr *attr) {}
13861393
static inline void kvm_clr_pmu_events(u64 clr) {}
13871394
static inline bool kvm_set_pmuserenr(u64 val)
13881395
{
13891396
return false;
13901397
}
1398+
static inline void kvm_enable_trbe(void) {}
1399+
static inline void kvm_disable_trbe(void) {}
13911400
#endif
13921401

13931402
void kvm_vcpu_load_vhe(struct kvm_vcpu *vcpu);

arch/arm64/kvm/debug.c

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,15 @@ void kvm_init_host_debug_data(void)
8181
!(read_sysreg_s(SYS_PMBIDR_EL1) & PMBIDR_EL1_P))
8282
host_data_set_flag(HAS_SPE);
8383

84-
if (cpuid_feature_extract_unsigned_field(dfr0, ID_AA64DFR0_EL1_TraceBuffer_SHIFT) &&
85-
!(read_sysreg_s(SYS_TRBIDR_EL1) & TRBIDR_EL1_P))
86-
host_data_set_flag(HAS_TRBE);
84+
if (cpuid_feature_extract_unsigned_field(dfr0, ID_AA64DFR0_EL1_TraceFilt_SHIFT)) {
85+
/* Force disable trace in protected mode in case of no TRBE */
86+
if (is_protected_kvm_enabled())
87+
host_data_set_flag(EL1_TRACING_CONFIGURED);
88+
89+
if (cpuid_feature_extract_unsigned_field(dfr0, ID_AA64DFR0_EL1_TraceBuffer_SHIFT) &&
90+
!(read_sysreg_s(SYS_TRBIDR_EL1) & TRBIDR_EL1_P))
91+
host_data_set_flag(HAS_TRBE);
92+
}
8793
}
8894

8995
/*
@@ -219,3 +225,23 @@ void kvm_debug_handle_oslar(struct kvm_vcpu *vcpu, u64 val)
219225
kvm_arch_vcpu_load(vcpu, smp_processor_id());
220226
preempt_enable();
221227
}
228+
229+
void kvm_enable_trbe(void)
230+
{
231+
if (has_vhe() || is_protected_kvm_enabled() ||
232+
WARN_ON_ONCE(preemptible()))
233+
return;
234+
235+
host_data_set_flag(TRBE_ENABLED);
236+
}
237+
EXPORT_SYMBOL_GPL(kvm_enable_trbe);
238+
239+
void kvm_disable_trbe(void)
240+
{
241+
if (has_vhe() || is_protected_kvm_enabled() ||
242+
WARN_ON_ONCE(preemptible()))
243+
return;
244+
245+
host_data_clear_flag(TRBE_ENABLED);
246+
}
247+
EXPORT_SYMBOL_GPL(kvm_disable_trbe);

arch/arm64/kvm/hyp/nvhe/debug-sr.c

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -51,42 +51,55 @@ static void __debug_restore_spe(u64 pmscr_el1)
5151
write_sysreg_el1(pmscr_el1, SYS_PMSCR);
5252
}
5353

54-
static void __debug_save_trace(u64 *trfcr_el1)
54+
static void __trace_do_switch(u64 *saved_trfcr, u64 new_trfcr)
5555
{
56-
*trfcr_el1 = 0;
56+
*saved_trfcr = read_sysreg_el1(SYS_TRFCR);
57+
write_sysreg_el1(new_trfcr, SYS_TRFCR);
58+
}
5759

58-
/* Check if the TRBE is enabled */
59-
if (!(read_sysreg_s(SYS_TRBLIMITR_EL1) & TRBLIMITR_EL1_E))
60-
return;
61-
/*
62-
* Prohibit trace generation while we are in guest.
63-
* Since access to TRFCR_EL1 is trapped, the guest can't
64-
* modify the filtering set by the host.
65-
*/
66-
*trfcr_el1 = read_sysreg_el1(SYS_TRFCR);
67-
write_sysreg_el1(0, SYS_TRFCR);
68-
isb();
69-
/* Drain the trace buffer to memory */
70-
tsb_csync();
60+
static bool __trace_needs_drain(void)
61+
{
62+
if (is_protected_kvm_enabled() && host_data_test_flag(HAS_TRBE))
63+
return read_sysreg_s(SYS_TRBLIMITR_EL1) & TRBLIMITR_EL1_E;
64+
65+
return host_data_test_flag(TRBE_ENABLED);
7166
}
7267

73-
static void __debug_restore_trace(u64 trfcr_el1)
68+
static bool __trace_needs_switch(void)
7469
{
75-
if (!trfcr_el1)
76-
return;
70+
return host_data_test_flag(TRBE_ENABLED) ||
71+
host_data_test_flag(EL1_TRACING_CONFIGURED);
72+
}
73+
74+
static void __trace_switch_to_guest(void)
75+
{
76+
/* Unsupported with TRBE so disable */
77+
if (host_data_test_flag(TRBE_ENABLED))
78+
*host_data_ptr(trfcr_while_in_guest) = 0;
79+
80+
__trace_do_switch(host_data_ptr(host_debug_state.trfcr_el1),
81+
*host_data_ptr(trfcr_while_in_guest));
7782

78-
/* Restore trace filter controls */
79-
write_sysreg_el1(trfcr_el1, SYS_TRFCR);
83+
if (__trace_needs_drain()) {
84+
isb();
85+
tsb_csync();
86+
}
87+
}
88+
89+
static void __trace_switch_to_host(void)
90+
{
91+
__trace_do_switch(host_data_ptr(trfcr_while_in_guest),
92+
*host_data_ptr(host_debug_state.trfcr_el1));
8093
}
8194

8295
void __debug_save_host_buffers_nvhe(struct kvm_vcpu *vcpu)
8396
{
8497
/* Disable and flush SPE data generation */
8598
if (host_data_test_flag(HAS_SPE))
8699
__debug_save_spe(host_data_ptr(host_debug_state.pmscr_el1));
87-
/* Disable and flush Self-Hosted Trace generation */
88-
if (host_data_test_flag(HAS_TRBE))
89-
__debug_save_trace(host_data_ptr(host_debug_state.trfcr_el1));
100+
101+
if (__trace_needs_switch())
102+
__trace_switch_to_guest();
90103
}
91104

92105
void __debug_switch_to_guest(struct kvm_vcpu *vcpu)
@@ -98,8 +111,8 @@ void __debug_restore_host_buffers_nvhe(struct kvm_vcpu *vcpu)
98111
{
99112
if (host_data_test_flag(HAS_SPE))
100113
__debug_restore_spe(*host_data_ptr(host_debug_state.pmscr_el1));
101-
if (host_data_test_flag(HAS_TRBE))
102-
__debug_restore_trace(*host_data_ptr(host_debug_state.trfcr_el1));
114+
if (__trace_needs_switch())
115+
__trace_switch_to_host();
103116
}
104117

105118
void __debug_switch_to_host(struct kvm_vcpu *vcpu)

drivers/hwtracing/coresight/coresight-trbe.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include <asm/barrier.h>
1919
#include <asm/cpufeature.h>
20+
#include <linux/kvm_host.h>
2021
#include <linux/vmalloc.h>
2122

2223
#include "coresight-self-hosted-trace.h"
@@ -221,6 +222,7 @@ static inline void set_trbe_enabled(struct trbe_cpudata *cpudata, u64 trblimitr)
221222
*/
222223
trblimitr |= TRBLIMITR_EL1_E;
223224
write_sysreg_s(trblimitr, SYS_TRBLIMITR_EL1);
225+
kvm_enable_trbe();
224226

225227
/* Synchronize the TRBE enable event */
226228
isb();
@@ -239,6 +241,7 @@ static inline void set_trbe_disabled(struct trbe_cpudata *cpudata)
239241
*/
240242
trblimitr &= ~TRBLIMITR_EL1_E;
241243
write_sysreg_s(trblimitr, SYS_TRBLIMITR_EL1);
244+
kvm_disable_trbe();
242245

243246
if (trbe_needs_drain_after_disable(cpudata))
244247
trbe_drain_buffer();

0 commit comments

Comments
 (0)