blob: 4d5a719b9d85d41234e4867d75a5bcc614e77ca0 [file] [log] [blame]
Brad Bishopbec4ebc2022-08-03 09:55:16 -04001From 55228b0522bfb7d945019a8931742ab9b063b6c9 Mon Sep 17 00:00:00 2001
2From: Suzuki K Poulose <suzuki.poulose@arm.com>
3Date: Tue, 14 Sep 2021 11:26:33 +0100
4Subject: [PATCH 2/2] coresight: etm4x: Use Trace Filtering controls
5 dynamically
6
7The Trace Filtering support (FEAT_TRF) ensures that the ETM
8can be prohibited from generating any trace for a given EL.
9This is much stricter knob, than the TRCVICTLR exception level
10masks, which doesn't prevent the ETM from generating Context
11packets for an "excluded" EL. At the moment, we do a onetime
12enable trace at user and kernel and leave it untouched for the
13kernel life time. This implies that the ETM could potentially
14generate trace packets containing the kernel addresses, and
15thus leaking the kernel virtual address in the trace.
16
17This patch makes the switch dynamic, by honoring the filters
18set by the user and enforcing them in the TRFCR controls.
19We also rename the cpu_enable_tracing() appropriately to
20cpu_detect_trace_filtering() and the drvdata member
21trfc => trfcr to indicate the "value" of the TRFCR_EL1.
22
23Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
24Cc: Al Grant <al.grant@arm.com>
25Cc: Mike Leach <mike.leach@linaro.org>
26Cc: Leo Yan <leo.yan@linaro.org>
27Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
28Reviewed-by: Anshuman Khandual <anshuman.khandual@arm.com>
29Link: https://lore.kernel.org/r/20210914102641.1852544-3-suzuki.poulose@arm.com
30Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
31
32Upstream-Status: Backport [https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=5f6fd1aa8cc147b111af1a833574487a87237dc0]
33Signed-off-by: Davidson K <davidson.kumaresan@arm.com>
34---
35 .../coresight/coresight-etm4x-core.c | 63 ++++++++++++++-----
36 drivers/hwtracing/coresight/coresight-etm4x.h | 7 ++-
37 .../coresight/coresight-self-hosted-trace.h | 7 +++
38 3 files changed, 59 insertions(+), 18 deletions(-)
39
40diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
41index b78080d169f8..b804d4413b43 100644
42--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
43+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
44@@ -237,6 +237,45 @@ struct etm4_enable_arg {
45 int rc;
46 };
47
48+/*
49+ * etm4x_prohibit_trace - Prohibit the CPU from tracing at all ELs.
50+ * When the CPU supports FEAT_TRF, we could move the ETM to a trace
51+ * prohibited state by filtering the Exception levels via TRFCR_EL1.
52+ */
53+static void etm4x_prohibit_trace(struct etmv4_drvdata *drvdata)
54+{
55+ /* If the CPU doesn't support FEAT_TRF, nothing to do */
56+ if (!drvdata->trfcr)
57+ return;
58+ cpu_prohibit_trace();
59+}
60+
61+/*
62+ * etm4x_allow_trace - Allow CPU tracing in the respective ELs,
63+ * as configured by the drvdata->config.mode for the current
64+ * session. Even though we have TRCVICTLR bits to filter the
65+ * trace in the ELs, it doesn't prevent the ETM from generating
66+ * a packet (e.g, TraceInfo) that might contain the addresses from
67+ * the excluded levels. Thus we use the additional controls provided
68+ * via the Trace Filtering controls (FEAT_TRF) to make sure no trace
69+ * is generated for the excluded ELs.
70+ */
71+static void etm4x_allow_trace(struct etmv4_drvdata *drvdata)
72+{
73+ u64 trfcr = drvdata->trfcr;
74+
75+ /* If the CPU doesn't support FEAT_TRF, nothing to do */
76+ if (!trfcr)
77+ return;
78+
79+ if (drvdata->config.mode & ETM_MODE_EXCL_KERN)
80+ trfcr &= ~TRFCR_ELx_ExTRE;
81+ if (drvdata->config.mode & ETM_MODE_EXCL_USER)
82+ trfcr &= ~TRFCR_ELx_E0TRE;
83+
84+ write_trfcr(trfcr);
85+}
86+
87 #ifdef CONFIG_ETM4X_IMPDEF_FEATURE
88
89 #define HISI_HIP08_AMBA_ID 0x000b6d01
90@@ -441,6 +480,7 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
91 if (etm4x_is_ete(drvdata))
92 etm4x_relaxed_write32(csa, TRCRSR_TA, TRCRSR);
93
94+ etm4x_allow_trace(drvdata);
95 /* Enable the trace unit */
96 etm4x_relaxed_write32(csa, 1, TRCPRGCTLR);
97
98@@ -724,7 +764,6 @@ static int etm4_enable(struct coresight_device *csdev,
99 static void etm4_disable_hw(void *info)
100 {
101 u32 control;
102- u64 trfcr;
103 struct etmv4_drvdata *drvdata = info;
104 struct etmv4_config *config = &drvdata->config;
105 struct coresight_device *csdev = drvdata->csdev;
106@@ -751,12 +790,7 @@ static void etm4_disable_hw(void *info)
107 * If the CPU supports v8.4 Trace filter Control,
108 * set the ETM to trace prohibited region.
109 */
110- if (drvdata->trfc) {
111- trfcr = read_sysreg_s(SYS_TRFCR_EL1);
112- write_sysreg_s(trfcr & ~(TRFCR_ELx_ExTRE | TRFCR_ELx_E0TRE),
113- SYS_TRFCR_EL1);
114- isb();
115- }
116+ etm4x_prohibit_trace(drvdata);
117 /*
118 * Make sure everything completes before disabling, as recommended
119 * by section 7.3.77 ("TRCVICTLR, ViewInst Main Control Register,
120@@ -772,9 +806,6 @@ static void etm4_disable_hw(void *info)
121 if (coresight_timeout(csa, TRCSTATR, TRCSTATR_PMSTABLE_BIT, 1))
122 dev_err(etm_dev,
123 "timeout while waiting for PM stable Trace Status\n");
124- if (drvdata->trfc)
125- write_sysreg_s(trfcr, SYS_TRFCR_EL1);
126-
127 /* read the status of the single shot comparators */
128 for (i = 0; i < drvdata->nr_ss_cmp; i++) {
129 config->ss_status[i] =
130@@ -969,15 +1000,15 @@ static bool etm4_init_csdev_access(struct etmv4_drvdata *drvdata,
131 return false;
132 }
133
134-static void cpu_enable_tracing(struct etmv4_drvdata *drvdata)
135+static void cpu_detect_trace_filtering(struct etmv4_drvdata *drvdata)
136 {
137 u64 dfr0 = read_sysreg(id_aa64dfr0_el1);
138 u64 trfcr;
139
140+ drvdata->trfcr = 0;
141 if (!cpuid_feature_extract_unsigned_field(dfr0, ID_AA64DFR0_TRACE_FILT_SHIFT))
142 return;
143
144- drvdata->trfc = true;
145 /*
146 * If the CPU supports v8.4 SelfHosted Tracing, enable
147 * tracing at the kernel EL and EL0, forcing to use the
148@@ -991,7 +1022,7 @@ static void cpu_enable_tracing(struct etmv4_drvdata *drvdata)
149 if (is_kernel_in_hyp_mode())
150 trfcr |= TRFCR_EL2_CX;
151
152- write_trfcr(trfcr);
153+ drvdata->trfcr = trfcr;
154 }
155
156 static void etm4_init_arch_data(void *info)
157@@ -1177,7 +1208,7 @@ static void etm4_init_arch_data(void *info)
158 /* NUMCNTR, bits[30:28] number of counters available for tracing */
159 drvdata->nr_cntr = BMVAL(etmidr5, 28, 30);
160 etm4_cs_lock(drvdata, csa);
161- cpu_enable_tracing(drvdata);
162+ cpu_detect_trace_filtering(drvdata);
163 }
164
165 static inline u32 etm4_get_victlr_access_type(struct etmv4_config *config)
166@@ -1673,7 +1704,7 @@ static int etm4_cpu_save(struct etmv4_drvdata *drvdata)
167 int ret = 0;
168
169 /* Save the TRFCR irrespective of whether the ETM is ON */
170- if (drvdata->trfc)
171+ if (drvdata->trfcr)
172 drvdata->save_trfcr = read_trfcr();
173 /*
174 * Save and restore the ETM Trace registers only if
175@@ -1782,7 +1813,7 @@ static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata)
176
177 static void etm4_cpu_restore(struct etmv4_drvdata *drvdata)
178 {
179- if (drvdata->trfc)
180+ if (drvdata->trfcr)
181 write_trfcr(drvdata->save_trfcr);
182 if (drvdata->state_needs_restore)
183 __etm4_cpu_restore(drvdata);
184diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
185index 82cba16b73a6..3c4d69b096ca 100644
186--- a/drivers/hwtracing/coresight/coresight-etm4x.h
187+++ b/drivers/hwtracing/coresight/coresight-etm4x.h
188@@ -919,7 +919,10 @@ struct etmv4_save_state {
189 * @nooverflow: Indicate if overflow prevention is supported.
190 * @atbtrig: If the implementation can support ATB triggers
191 * @lpoverride: If the implementation can support low-power state over.
192- * @trfc: If the implementation supports Arm v8.4 trace filter controls.
193+ * @trfcr: If the CPU supports FEAT_TRF, value of the TRFCR_ELx that
194+ * allows tracing at all ELs. We don't want to compute this
195+ * at runtime, due to the additional setting of TRFCR_CX when
196+ * in EL2. Otherwise, 0.
197 * @config: structure holding configuration parameters.
198 * @save_trfcr: Saved TRFCR_EL1 register during a CPU PM event.
199 * @save_state: State to be preserved across power loss
200@@ -972,7 +975,7 @@ struct etmv4_drvdata {
201 bool nooverflow;
202 bool atbtrig;
203 bool lpoverride;
204- bool trfc;
205+ u64 trfcr;
206 struct etmv4_config config;
207 u64 save_trfcr;
208 struct etmv4_save_state *save_state;
209diff --git a/drivers/hwtracing/coresight/coresight-self-hosted-trace.h b/drivers/hwtracing/coresight/coresight-self-hosted-trace.h
210index 303d71911870..23f05df3f173 100644
211--- a/drivers/hwtracing/coresight/coresight-self-hosted-trace.h
212+++ b/drivers/hwtracing/coresight/coresight-self-hosted-trace.h
213@@ -21,4 +21,11 @@ static inline void write_trfcr(u64 val)
214 isb();
215 }
216
217+static inline void cpu_prohibit_trace(void)
218+{
219+ u64 trfcr = read_trfcr();
220+
221+ /* Prohibit tracing at EL0 & the kernel EL */
222+ write_trfcr(trfcr & ~(TRFCR_ELx_ExTRE | TRFCR_ELx_E0TRE));
223+}
224 #endif /* __CORESIGHT_SELF_HOSTED_TRACE_H */
225--
2262.34.1
227