Skip to content

Commit

Permalink
Merge branch kvm-arm64/coresight-6.14 into kvmarm-master/next
Browse files Browse the repository at this point in the history
* kvm-arm64/coresight-6.14:
  : .
  : Trace filtering update from James Clark. From the cover letter:
  :
  : "The guest filtering rules from the Perf session are now honored for both
  : nVHE and VHE modes. This is done by either writing to TRFCR_EL12 at the
  : start of the Perf session and doing nothing else further, or caching the
  : guest value and writing it at guest switch for nVHE. In pKVM, trace is
  : now be disabled for both protected and unprotected guests."
  : .
  KVM: arm64: Fix selftests after sysreg field name update
  coresight: Pass guest TRFCR value to KVM
  KVM: arm64: Support trace filtering for guests
  KVM: arm64: coresight: Give TRBE enabled state to KVM
  coresight: trbe: Remove redundant disable call
  arm64/sysreg/tools: Move TRFCR definitions to sysreg
  tools: arm64: Update sysreg.h header files

Signed-off-by: Marc Zyngier <maz@kernel.org>
  • Loading branch information
Marc Zyngier committed Jan 17, 2025
2 parents 5e68d2e + 9fb4267 commit 946904e
Show file tree
Hide file tree
Showing 14 changed files with 599 additions and 80 deletions.
11 changes: 11 additions & 0 deletions arch/arm64/include/asm/kvm_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,8 @@ struct kvm_host_data {
#define KVM_HOST_DATA_FLAG_HAS_TRBE 1
#define KVM_HOST_DATA_FLAG_HOST_SVE_ENABLED 2
#define KVM_HOST_DATA_FLAG_HOST_SME_ENABLED 3
#define KVM_HOST_DATA_FLAG_TRBE_ENABLED 4
#define KVM_HOST_DATA_FLAG_EL1_TRACING_CONFIGURED 5
unsigned long flags;

struct kvm_cpu_context host_ctxt;
Expand Down Expand Up @@ -662,6 +664,9 @@ struct kvm_host_data {
u64 mdcr_el2;
} host_debug_state;

/* Guest trace filter value */
u64 trfcr_while_in_guest;

/* Number of programmable event counters (PMCR_EL0.N) for this CPU */
unsigned int nr_event_counters;

Expand Down Expand Up @@ -1389,13 +1394,19 @@ static inline bool kvm_pmu_counter_deferred(struct perf_event_attr *attr)
void kvm_set_pmu_events(u64 set, struct perf_event_attr *attr);
void kvm_clr_pmu_events(u64 clr);
bool kvm_set_pmuserenr(u64 val);
void kvm_enable_trbe(void);
void kvm_disable_trbe(void);
void kvm_tracing_set_el1_configuration(u64 trfcr_while_in_guest);
#else
static inline void kvm_set_pmu_events(u64 set, struct perf_event_attr *attr) {}
static inline void kvm_clr_pmu_events(u64 clr) {}
static inline bool kvm_set_pmuserenr(u64 val)
{
return false;
}
static inline void kvm_enable_trbe(void) {}
static inline void kvm_disable_trbe(void) {}
static inline void kvm_tracing_set_el1_configuration(u64 trfcr_while_in_guest) {}
#endif

void kvm_vcpu_load_vhe(struct kvm_vcpu *vcpu);
Expand Down
12 changes: 0 additions & 12 deletions arch/arm64/include/asm/sysreg.h
Original file line number Diff line number Diff line change
Expand Up @@ -283,8 +283,6 @@
#define SYS_RGSR_EL1 sys_reg(3, 0, 1, 0, 5)
#define SYS_GCR_EL1 sys_reg(3, 0, 1, 0, 6)

#define SYS_TRFCR_EL1 sys_reg(3, 0, 1, 2, 1)

#define SYS_TCR_EL1 sys_reg(3, 0, 2, 0, 2)

#define SYS_APIAKEYLO_EL1 sys_reg(3, 0, 2, 1, 0)
Expand Down Expand Up @@ -523,7 +521,6 @@
#define SYS_VTTBR_EL2 sys_reg(3, 4, 2, 1, 0)
#define SYS_VTCR_EL2 sys_reg(3, 4, 2, 1, 2)

#define SYS_TRFCR_EL2 sys_reg(3, 4, 1, 2, 1)
#define SYS_VNCR_EL2 sys_reg(3, 4, 2, 2, 0)
#define SYS_HAFGRTR_EL2 sys_reg(3, 4, 3, 1, 6)
#define SYS_SPSR_EL2 sys_reg(3, 4, 4, 0, 0)
Expand Down Expand Up @@ -987,15 +984,6 @@
/* Safe value for MPIDR_EL1: Bit31:RES1, Bit30:U:0, Bit24:MT:0 */
#define SYS_MPIDR_SAFE_VAL (BIT(31))

#define TRFCR_ELx_TS_SHIFT 5
#define TRFCR_ELx_TS_MASK ((0x3UL) << TRFCR_ELx_TS_SHIFT)
#define TRFCR_ELx_TS_VIRTUAL ((0x1UL) << TRFCR_ELx_TS_SHIFT)
#define TRFCR_ELx_TS_GUEST_PHYSICAL ((0x2UL) << TRFCR_ELx_TS_SHIFT)
#define TRFCR_ELx_TS_PHYSICAL ((0x3UL) << TRFCR_ELx_TS_SHIFT)
#define TRFCR_EL2_CX BIT(3)
#define TRFCR_ELx_ExTRE BIT(1)
#define TRFCR_ELx_E0TRE BIT(0)

/* GIC Hypervisor interface registers */
/* ICH_MISR_EL2 bit definitions */
#define ICH_MISR_EOI (1 << 0)
Expand Down
50 changes: 47 additions & 3 deletions arch/arm64/kvm/debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,15 @@ void kvm_init_host_debug_data(void)
!(read_sysreg_s(SYS_PMBIDR_EL1) & PMBIDR_EL1_P))
host_data_set_flag(HAS_SPE);

if (cpuid_feature_extract_unsigned_field(dfr0, ID_AA64DFR0_EL1_TraceBuffer_SHIFT) &&
!(read_sysreg_s(SYS_TRBIDR_EL1) & TRBIDR_EL1_P))
host_data_set_flag(HAS_TRBE);
if (cpuid_feature_extract_unsigned_field(dfr0, ID_AA64DFR0_EL1_TraceFilt_SHIFT)) {
/* Force disable trace in protected mode in case of no TRBE */
if (is_protected_kvm_enabled())
host_data_set_flag(EL1_TRACING_CONFIGURED);

if (cpuid_feature_extract_unsigned_field(dfr0, ID_AA64DFR0_EL1_TraceBuffer_SHIFT) &&
!(read_sysreg_s(SYS_TRBIDR_EL1) & TRBIDR_EL1_P))
host_data_set_flag(HAS_TRBE);
}
}

/*
Expand Down Expand Up @@ -219,3 +225,41 @@ void kvm_debug_handle_oslar(struct kvm_vcpu *vcpu, u64 val)
kvm_arch_vcpu_load(vcpu, smp_processor_id());
preempt_enable();
}

void kvm_enable_trbe(void)
{
if (has_vhe() || is_protected_kvm_enabled() ||
WARN_ON_ONCE(preemptible()))
return;

host_data_set_flag(TRBE_ENABLED);
}
EXPORT_SYMBOL_GPL(kvm_enable_trbe);

void kvm_disable_trbe(void)
{
if (has_vhe() || is_protected_kvm_enabled() ||
WARN_ON_ONCE(preemptible()))
return;

host_data_clear_flag(TRBE_ENABLED);
}
EXPORT_SYMBOL_GPL(kvm_disable_trbe);

void kvm_tracing_set_el1_configuration(u64 trfcr_while_in_guest)
{
if (is_protected_kvm_enabled() || WARN_ON_ONCE(preemptible()))
return;

if (has_vhe()) {
write_sysreg_s(trfcr_while_in_guest, SYS_TRFCR_EL12);
return;
}

*host_data_ptr(trfcr_while_in_guest) = trfcr_while_in_guest;
if (read_sysreg_s(SYS_TRFCR_EL1) != trfcr_while_in_guest)
host_data_set_flag(EL1_TRACING_CONFIGURED);
else
host_data_clear_flag(EL1_TRACING_CONFIGURED);
}
EXPORT_SYMBOL_GPL(kvm_tracing_set_el1_configuration);
63 changes: 38 additions & 25 deletions arch/arm64/kvm/hyp/nvhe/debug-sr.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,42 +51,55 @@ static void __debug_restore_spe(u64 pmscr_el1)
write_sysreg_el1(pmscr_el1, SYS_PMSCR);
}

static void __debug_save_trace(u64 *trfcr_el1)
static void __trace_do_switch(u64 *saved_trfcr, u64 new_trfcr)
{
*trfcr_el1 = 0;
*saved_trfcr = read_sysreg_el1(SYS_TRFCR);
write_sysreg_el1(new_trfcr, SYS_TRFCR);
}

/* Check if the TRBE is enabled */
if (!(read_sysreg_s(SYS_TRBLIMITR_EL1) & TRBLIMITR_EL1_E))
return;
/*
* Prohibit trace generation while we are in guest.
* Since access to TRFCR_EL1 is trapped, the guest can't
* modify the filtering set by the host.
*/
*trfcr_el1 = read_sysreg_el1(SYS_TRFCR);
write_sysreg_el1(0, SYS_TRFCR);
isb();
/* Drain the trace buffer to memory */
tsb_csync();
static bool __trace_needs_drain(void)
{
if (is_protected_kvm_enabled() && host_data_test_flag(HAS_TRBE))
return read_sysreg_s(SYS_TRBLIMITR_EL1) & TRBLIMITR_EL1_E;

return host_data_test_flag(TRBE_ENABLED);
}

static void __debug_restore_trace(u64 trfcr_el1)
static bool __trace_needs_switch(void)
{
if (!trfcr_el1)
return;
return host_data_test_flag(TRBE_ENABLED) ||
host_data_test_flag(EL1_TRACING_CONFIGURED);
}

static void __trace_switch_to_guest(void)
{
/* Unsupported with TRBE so disable */
if (host_data_test_flag(TRBE_ENABLED))
*host_data_ptr(trfcr_while_in_guest) = 0;

__trace_do_switch(host_data_ptr(host_debug_state.trfcr_el1),
*host_data_ptr(trfcr_while_in_guest));

/* Restore trace filter controls */
write_sysreg_el1(trfcr_el1, SYS_TRFCR);
if (__trace_needs_drain()) {
isb();
tsb_csync();
}
}

static void __trace_switch_to_host(void)
{
__trace_do_switch(host_data_ptr(trfcr_while_in_guest),
*host_data_ptr(host_debug_state.trfcr_el1));
}

void __debug_save_host_buffers_nvhe(struct kvm_vcpu *vcpu)
{
/* Disable and flush SPE data generation */
if (host_data_test_flag(HAS_SPE))
__debug_save_spe(host_data_ptr(host_debug_state.pmscr_el1));
/* Disable and flush Self-Hosted Trace generation */
if (host_data_test_flag(HAS_TRBE))
__debug_save_trace(host_data_ptr(host_debug_state.trfcr_el1));

if (__trace_needs_switch())
__trace_switch_to_guest();
}

void __debug_switch_to_guest(struct kvm_vcpu *vcpu)
Expand All @@ -98,8 +111,8 @@ void __debug_restore_host_buffers_nvhe(struct kvm_vcpu *vcpu)
{
if (host_data_test_flag(HAS_SPE))
__debug_restore_spe(*host_data_ptr(host_debug_state.pmscr_el1));
if (host_data_test_flag(HAS_TRBE))
__debug_restore_trace(*host_data_ptr(host_debug_state.trfcr_el1));
if (__trace_needs_switch())
__trace_switch_to_host();
}

void __debug_switch_to_host(struct kvm_vcpu *vcpu)
Expand Down
36 changes: 36 additions & 0 deletions arch/arm64/tools/sysreg
Original file line number Diff line number Diff line change
Expand Up @@ -1999,6 +1999,22 @@ Field 17:16 ZEN
Res0 15:0
EndSysreg

SysregFields TRFCR_ELx
Res0 63:7
UnsignedEnum 6:5 TS
0b0001 VIRTUAL
0b0010 GUEST_PHYSICAL
0b0011 PHYSICAL
EndEnum
Res0 4:2
Field 1 ExTRE
Field 0 E0TRE
EndSysregFields

Sysreg TRFCR_EL1 3 0 1 2 1
Fields TRFCR_ELx
EndSysreg

Sysreg SMPRI_EL1 3 0 1 2 4
Res0 63:4
Field 3:0 PRIORITY
Expand Down Expand Up @@ -2548,6 +2564,22 @@ Field 1 ICIALLU
Field 0 ICIALLUIS
EndSysreg

Sysreg TRFCR_EL2 3 4 1 2 1
Res0 63:7
UnsignedEnum 6:5 TS
0b0000 USE_TRFCR_EL1_TS
0b0001 VIRTUAL
0b0010 GUEST_PHYSICAL
0b0011 PHYSICAL
EndEnum
Res0 4
Field 3 CX
Res0 2
Field 1 E2TRE
Field 0 E0HTRE
EndSysreg


Sysreg HDFGRTR_EL2 3 4 3 1 4
Field 63 PMBIDR_EL1
Field 62 nPMSNEVFR_EL1
Expand Down Expand Up @@ -2958,6 +2990,10 @@ Sysreg ZCR_EL12 3 5 1 2 0
Mapping ZCR_EL1
EndSysreg

Sysreg TRFCR_EL12 3 5 1 2 1
Fields TRFCR_ELx
EndSysreg

Sysreg SMCR_EL12 3 5 1 2 6
Mapping SMCR_EL1
EndSysreg
Expand Down
49 changes: 42 additions & 7 deletions drivers/hwtracing/coresight/coresight-etm4x-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <linux/acpi.h>
#include <linux/bitops.h>
#include <linux/kernel.h>
#include <linux/kvm_host.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/types.h>
Expand Down Expand Up @@ -268,10 +269,28 @@ struct etm4_enable_arg {
*/
static void etm4x_prohibit_trace(struct etmv4_drvdata *drvdata)
{
u64 trfcr;

/* If the CPU doesn't support FEAT_TRF, nothing to do */
if (!drvdata->trfcr)
return;
cpu_prohibit_trace();

trfcr = drvdata->trfcr & ~(TRFCR_ELx_ExTRE | TRFCR_ELx_E0TRE);

write_trfcr(trfcr);
kvm_tracing_set_el1_configuration(trfcr);
}

static u64 etm4x_get_kern_user_filter(struct etmv4_drvdata *drvdata)
{
u64 trfcr = drvdata->trfcr;

if (drvdata->config.mode & ETM_MODE_EXCL_KERN)
trfcr &= ~TRFCR_ELx_ExTRE;
if (drvdata->config.mode & ETM_MODE_EXCL_USER)
trfcr &= ~TRFCR_ELx_E0TRE;

return trfcr;
}

/*
Expand All @@ -286,18 +305,28 @@ static void etm4x_prohibit_trace(struct etmv4_drvdata *drvdata)
*/
static void etm4x_allow_trace(struct etmv4_drvdata *drvdata)
{
u64 trfcr = drvdata->trfcr;
u64 trfcr, guest_trfcr;

/* If the CPU doesn't support FEAT_TRF, nothing to do */
if (!trfcr)
if (!drvdata->trfcr)
return;

if (drvdata->config.mode & ETM_MODE_EXCL_KERN)
trfcr &= ~TRFCR_ELx_ExTRE;
if (drvdata->config.mode & ETM_MODE_EXCL_USER)
trfcr &= ~TRFCR_ELx_E0TRE;
if (drvdata->config.mode & ETM_MODE_EXCL_HOST)
trfcr = drvdata->trfcr & ~(TRFCR_ELx_ExTRE | TRFCR_ELx_E0TRE);
else
trfcr = etm4x_get_kern_user_filter(drvdata);

write_trfcr(trfcr);

/* Set filters for guests and pass to KVM */
if (drvdata->config.mode & ETM_MODE_EXCL_GUEST)
guest_trfcr = drvdata->trfcr & ~(TRFCR_ELx_ExTRE | TRFCR_ELx_E0TRE);
else
guest_trfcr = etm4x_get_kern_user_filter(drvdata);

/* TRFCR_EL1 doesn't have CX so mask it out. */
guest_trfcr &= ~TRFCR_EL2_CX;
kvm_tracing_set_el1_configuration(guest_trfcr);
}

#ifdef CONFIG_ETM4X_IMPDEF_FEATURE
Expand Down Expand Up @@ -655,6 +684,12 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
if (attr->exclude_user)
config->mode = ETM_MODE_EXCL_USER;

if (attr->exclude_host)
config->mode |= ETM_MODE_EXCL_HOST;

if (attr->exclude_guest)
config->mode |= ETM_MODE_EXCL_GUEST;

/* Always start from the default config */
etm4_set_default_config(config);

Expand Down
2 changes: 1 addition & 1 deletion drivers/hwtracing/coresight/coresight-etm4x.h
Original file line number Diff line number Diff line change
Expand Up @@ -817,7 +817,7 @@ enum etm_impdef_type {
* @s_ex_level: Secure ELs where tracing is supported.
*/
struct etmv4_config {
u32 mode;
u64 mode;
u32 pe_sel;
u32 cfg;
u32 eventctrl0;
Expand Down
3 changes: 3 additions & 0 deletions drivers/hwtracing/coresight/coresight-priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ extern const struct device_type coresight_dev_type[];

#define ETM_MODE_EXCL_KERN BIT(30)
#define ETM_MODE_EXCL_USER BIT(31)
#define ETM_MODE_EXCL_HOST BIT(32)
#define ETM_MODE_EXCL_GUEST BIT(33)

struct cs_pair_attribute {
struct device_attribute attr;
u32 lo_off;
Expand Down
9 changes: 0 additions & 9 deletions drivers/hwtracing/coresight/coresight-self-hosted-trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,4 @@ static inline void write_trfcr(u64 val)
isb();
}

static inline u64 cpu_prohibit_trace(void)
{
u64 trfcr = read_trfcr();

/* Prohibit tracing at EL0 & the kernel EL */
write_trfcr(trfcr & ~(TRFCR_ELx_ExTRE | TRFCR_ELx_E0TRE));
/* Return the original value of the TRFCR */
return trfcr;
}
#endif /* __CORESIGHT_SELF_HOSTED_TRACE_H */
Loading

0 comments on commit 946904e

Please sign in to comment.