UPSTREAM: coresight: etm4x: Use Trace Filtering controls dynamically
The Trace Filtering support (FEAT_TRF) ensures that the ETM can be prohibited from generating any trace for a given EL. This is much stricter knob, than the TRCVICTLR exception level masks, which doesn't prevent the ETM from generating Context packets for an "excluded" EL. At the moment, we do a onetime enable trace at user and kernel and leave it untouched for the kernel life time. This implies that the ETM could potentially generate trace packets containing the kernel addresses, and thus leaking the kernel virtual address in the trace. This patch makes the switch dynamic, by honoring the filters set by the user and enforcing them in the TRFCR controls. We also rename the cpu_enable_tracing() appropriately to cpu_detect_trace_filtering() and the drvdata member trfc => trfcr to indicate the "value" of the TRFCR_EL1. Bug: 213931796 Cc: Mathieu Poirier <mathieu.poirier@linaro.org> Cc: Al Grant <al.grant@arm.com> Cc: Mike Leach <mike.leach@linaro.org> Cc: Leo Yan <leo.yan@linaro.org> Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com> Reviewed-by: Anshuman Khandual <anshuman.khandual@arm.com> Link: https://lore.kernel.org/r/20210914102641.1852544-3-suzuki.poulose@arm.com Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org> (cherry picked from commit 5f6fd1aa8cc147b111af1a833574487a87237dc0) Signed-off-by: Qais Yousef <qais.yousef@arm.com> Change-Id: If6ae831b3d1f5334648eb3d02262812527e2bb9d
This commit is contained in:

committed by
Todd Kjos

parent
2bb8b3c907
commit
71aebf8793
@@ -237,6 +237,45 @@ struct etm4_enable_arg {
|
|||||||
int rc;
|
int rc;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* etm4x_prohibit_trace - Prohibit the CPU from tracing at all ELs.
|
||||||
|
* When the CPU supports FEAT_TRF, we could move the ETM to a trace
|
||||||
|
* prohibited state by filtering the Exception levels via TRFCR_EL1.
|
||||||
|
*/
|
||||||
|
static void etm4x_prohibit_trace(struct etmv4_drvdata *drvdata)
|
||||||
|
{
|
||||||
|
/* If the CPU doesn't support FEAT_TRF, nothing to do */
|
||||||
|
if (!drvdata->trfcr)
|
||||||
|
return;
|
||||||
|
cpu_prohibit_trace();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* etm4x_allow_trace - Allow CPU tracing in the respective ELs,
|
||||||
|
* as configured by the drvdata->config.mode for the current
|
||||||
|
* session. Even though we have TRCVICTLR bits to filter the
|
||||||
|
* trace in the ELs, it doesn't prevent the ETM from generating
|
||||||
|
* a packet (e.g, TraceInfo) that might contain the addresses from
|
||||||
|
* the excluded levels. Thus we use the additional controls provided
|
||||||
|
* via the Trace Filtering controls (FEAT_TRF) to make sure no trace
|
||||||
|
* is generated for the excluded ELs.
|
||||||
|
*/
|
||||||
|
static void etm4x_allow_trace(struct etmv4_drvdata *drvdata)
|
||||||
|
{
|
||||||
|
u64 trfcr = drvdata->trfcr;
|
||||||
|
|
||||||
|
/* If the CPU doesn't support FEAT_TRF, nothing to do */
|
||||||
|
if (!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;
|
||||||
|
|
||||||
|
write_trfcr(trfcr);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_ETM4X_IMPDEF_FEATURE
|
#ifdef CONFIG_ETM4X_IMPDEF_FEATURE
|
||||||
|
|
||||||
#define HISI_HIP08_AMBA_ID 0x000b6d01
|
#define HISI_HIP08_AMBA_ID 0x000b6d01
|
||||||
@@ -441,6 +480,7 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
|
|||||||
if (etm4x_is_ete(drvdata))
|
if (etm4x_is_ete(drvdata))
|
||||||
etm4x_relaxed_write32(csa, TRCRSR_TA, TRCRSR);
|
etm4x_relaxed_write32(csa, TRCRSR_TA, TRCRSR);
|
||||||
|
|
||||||
|
etm4x_allow_trace(drvdata);
|
||||||
/* Enable the trace unit */
|
/* Enable the trace unit */
|
||||||
etm4x_relaxed_write32(csa, 1, TRCPRGCTLR);
|
etm4x_relaxed_write32(csa, 1, TRCPRGCTLR);
|
||||||
|
|
||||||
@@ -724,7 +764,6 @@ static int etm4_enable(struct coresight_device *csdev,
|
|||||||
static void etm4_disable_hw(void *info)
|
static void etm4_disable_hw(void *info)
|
||||||
{
|
{
|
||||||
u32 control;
|
u32 control;
|
||||||
u64 trfcr;
|
|
||||||
struct etmv4_drvdata *drvdata = info;
|
struct etmv4_drvdata *drvdata = info;
|
||||||
struct etmv4_config *config = &drvdata->config;
|
struct etmv4_config *config = &drvdata->config;
|
||||||
struct coresight_device *csdev = drvdata->csdev;
|
struct coresight_device *csdev = drvdata->csdev;
|
||||||
@@ -751,12 +790,7 @@ static void etm4_disable_hw(void *info)
|
|||||||
* If the CPU supports v8.4 Trace filter Control,
|
* If the CPU supports v8.4 Trace filter Control,
|
||||||
* set the ETM to trace prohibited region.
|
* set the ETM to trace prohibited region.
|
||||||
*/
|
*/
|
||||||
if (drvdata->trfc) {
|
etm4x_prohibit_trace(drvdata);
|
||||||
trfcr = read_sysreg_s(SYS_TRFCR_EL1);
|
|
||||||
write_sysreg_s(trfcr & ~(TRFCR_ELx_ExTRE | TRFCR_ELx_E0TRE),
|
|
||||||
SYS_TRFCR_EL1);
|
|
||||||
isb();
|
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
* Make sure everything completes before disabling, as recommended
|
* Make sure everything completes before disabling, as recommended
|
||||||
* by section 7.3.77 ("TRCVICTLR, ViewInst Main Control Register,
|
* by section 7.3.77 ("TRCVICTLR, ViewInst Main Control Register,
|
||||||
@@ -772,9 +806,6 @@ static void etm4_disable_hw(void *info)
|
|||||||
if (coresight_timeout(csa, TRCSTATR, TRCSTATR_PMSTABLE_BIT, 1))
|
if (coresight_timeout(csa, TRCSTATR, TRCSTATR_PMSTABLE_BIT, 1))
|
||||||
dev_err(etm_dev,
|
dev_err(etm_dev,
|
||||||
"timeout while waiting for PM stable Trace Status\n");
|
"timeout while waiting for PM stable Trace Status\n");
|
||||||
if (drvdata->trfc)
|
|
||||||
write_sysreg_s(trfcr, SYS_TRFCR_EL1);
|
|
||||||
|
|
||||||
/* read the status of the single shot comparators */
|
/* read the status of the single shot comparators */
|
||||||
for (i = 0; i < drvdata->nr_ss_cmp; i++) {
|
for (i = 0; i < drvdata->nr_ss_cmp; i++) {
|
||||||
config->ss_status[i] =
|
config->ss_status[i] =
|
||||||
@@ -969,15 +1000,15 @@ static bool etm4_init_csdev_access(struct etmv4_drvdata *drvdata,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cpu_enable_tracing(struct etmv4_drvdata *drvdata)
|
static void cpu_detect_trace_filtering(struct etmv4_drvdata *drvdata)
|
||||||
{
|
{
|
||||||
u64 dfr0 = read_sysreg(id_aa64dfr0_el1);
|
u64 dfr0 = read_sysreg(id_aa64dfr0_el1);
|
||||||
u64 trfcr;
|
u64 trfcr;
|
||||||
|
|
||||||
|
drvdata->trfcr = 0;
|
||||||
if (!cpuid_feature_extract_unsigned_field(dfr0, ID_AA64DFR0_TRACE_FILT_SHIFT))
|
if (!cpuid_feature_extract_unsigned_field(dfr0, ID_AA64DFR0_TRACE_FILT_SHIFT))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
drvdata->trfc = true;
|
|
||||||
/*
|
/*
|
||||||
* If the CPU supports v8.4 SelfHosted Tracing, enable
|
* If the CPU supports v8.4 SelfHosted Tracing, enable
|
||||||
* tracing at the kernel EL and EL0, forcing to use the
|
* tracing at the kernel EL and EL0, forcing to use the
|
||||||
@@ -991,7 +1022,7 @@ static void cpu_enable_tracing(struct etmv4_drvdata *drvdata)
|
|||||||
if (is_kernel_in_hyp_mode())
|
if (is_kernel_in_hyp_mode())
|
||||||
trfcr |= TRFCR_EL2_CX;
|
trfcr |= TRFCR_EL2_CX;
|
||||||
|
|
||||||
write_trfcr(trfcr);
|
drvdata->trfcr = trfcr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void etm4_init_arch_data(void *info)
|
static void etm4_init_arch_data(void *info)
|
||||||
@@ -1177,7 +1208,7 @@ static void etm4_init_arch_data(void *info)
|
|||||||
/* NUMCNTR, bits[30:28] number of counters available for tracing */
|
/* NUMCNTR, bits[30:28] number of counters available for tracing */
|
||||||
drvdata->nr_cntr = BMVAL(etmidr5, 28, 30);
|
drvdata->nr_cntr = BMVAL(etmidr5, 28, 30);
|
||||||
etm4_cs_lock(drvdata, csa);
|
etm4_cs_lock(drvdata, csa);
|
||||||
cpu_enable_tracing(drvdata);
|
cpu_detect_trace_filtering(drvdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u32 etm4_get_victlr_access_type(struct etmv4_config *config)
|
static inline u32 etm4_get_victlr_access_type(struct etmv4_config *config)
|
||||||
@@ -1673,7 +1704,7 @@ static int etm4_cpu_save(struct etmv4_drvdata *drvdata)
|
|||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
/* Save the TRFCR irrespective of whether the ETM is ON */
|
/* Save the TRFCR irrespective of whether the ETM is ON */
|
||||||
if (drvdata->trfc)
|
if (drvdata->trfcr)
|
||||||
drvdata->save_trfcr = read_trfcr();
|
drvdata->save_trfcr = read_trfcr();
|
||||||
/*
|
/*
|
||||||
* Save and restore the ETM Trace registers only if
|
* Save and restore the ETM Trace registers only if
|
||||||
@@ -1782,7 +1813,7 @@ static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata)
|
|||||||
|
|
||||||
static void etm4_cpu_restore(struct etmv4_drvdata *drvdata)
|
static void etm4_cpu_restore(struct etmv4_drvdata *drvdata)
|
||||||
{
|
{
|
||||||
if (drvdata->trfc)
|
if (drvdata->trfcr)
|
||||||
write_trfcr(drvdata->save_trfcr);
|
write_trfcr(drvdata->save_trfcr);
|
||||||
if (drvdata->state_needs_restore)
|
if (drvdata->state_needs_restore)
|
||||||
__etm4_cpu_restore(drvdata);
|
__etm4_cpu_restore(drvdata);
|
||||||
|
@@ -919,7 +919,10 @@ struct etmv4_save_state {
|
|||||||
* @nooverflow: Indicate if overflow prevention is supported.
|
* @nooverflow: Indicate if overflow prevention is supported.
|
||||||
* @atbtrig: If the implementation can support ATB triggers
|
* @atbtrig: If the implementation can support ATB triggers
|
||||||
* @lpoverride: If the implementation can support low-power state over.
|
* @lpoverride: If the implementation can support low-power state over.
|
||||||
* @trfc: If the implementation supports Arm v8.4 trace filter controls.
|
* @trfcr: If the CPU supports FEAT_TRF, value of the TRFCR_ELx that
|
||||||
|
* allows tracing at all ELs. We don't want to compute this
|
||||||
|
* at runtime, due to the additional setting of TRFCR_CX when
|
||||||
|
* in EL2. Otherwise, 0.
|
||||||
* @config: structure holding configuration parameters.
|
* @config: structure holding configuration parameters.
|
||||||
* @save_trfcr: Saved TRFCR_EL1 register during a CPU PM event.
|
* @save_trfcr: Saved TRFCR_EL1 register during a CPU PM event.
|
||||||
* @save_state: State to be preserved across power loss
|
* @save_state: State to be preserved across power loss
|
||||||
@@ -972,7 +975,7 @@ struct etmv4_drvdata {
|
|||||||
bool nooverflow;
|
bool nooverflow;
|
||||||
bool atbtrig;
|
bool atbtrig;
|
||||||
bool lpoverride;
|
bool lpoverride;
|
||||||
bool trfc;
|
u64 trfcr;
|
||||||
struct etmv4_config config;
|
struct etmv4_config config;
|
||||||
u64 save_trfcr;
|
u64 save_trfcr;
|
||||||
struct etmv4_save_state *save_state;
|
struct etmv4_save_state *save_state;
|
||||||
|
@@ -21,4 +21,11 @@ static inline void write_trfcr(u64 val)
|
|||||||
isb();
|
isb();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void cpu_prohibit_trace(void)
|
||||||
|
{
|
||||||
|
u64 trfcr = read_trfcr();
|
||||||
|
|
||||||
|
/* Prohibit tracing at EL0 & the kernel EL */
|
||||||
|
write_trfcr(trfcr & ~(TRFCR_ELx_ExTRE | TRFCR_ELx_E0TRE));
|
||||||
|
}
|
||||||
#endif /* __CORESIGHT_SELF_HOSTED_TRACE_H */
|
#endif /* __CORESIGHT_SELF_HOSTED_TRACE_H */
|
||||||
|
Reference in New Issue
Block a user