blob: 06e71a3d83b5d252c09a16ad12974e23988f2666 [file] [log] [blame]
Soby Mathewb4c6df42022-11-09 11:13:29 +00001/*
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
5 */
6
7#include <arch.h>
Arunachalam Ganapathyf6491212023-02-23 16:04:34 +00008#include <arch_features.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +00009#include <arch_helpers.h>
10#include <debug.h>
11#include <esr.h>
12#include <memory_alloc.h>
13#include <rec.h>
14#include <smc-rmi.h>
15
AlexeiFedorov7bb7a702023-01-17 17:04:14 +000016#define SYSREG_CASE(reg) \
17 case ESR_EL2_SYSREG_##ID_AA64##reg##_EL1:
Soby Mathewb4c6df42022-11-09 11:13:29 +000018
AlexeiFedorov7bb7a702023-01-17 17:04:14 +000019#define SYSREG_READ(reg) \
20 read_ID_AA64##reg##_EL1()
Soby Mathewb4c6df42022-11-09 11:13:29 +000021
AlexeiFedorov7bb7a702023-01-17 17:04:14 +000022#define SYSREG_READ_CLEAR(reg) \
23 (read_ID_AA64##reg##_EL1() & \
24 ~(ID_AA64##reg##_EL1_CLEAR))
25
26#define SYSREG_READ_CLEAR_SET(reg) \
27 ((read_ID_AA64##reg##_EL1() & \
28 ~(ID_AA64##reg##_EL1_CLEAR)) | \
29 (ID_AA64##reg##_EL1_SET))
30
31/* System registers ID_AA64xxx_EL1 feature clear masks and set values */
32
33/*
34 * ID_AA64DFR0_EL1:
35 *
36 * Cleared fields:
37 * - Debug architecture version:
38 * set in ID_AA64DFR0_EL1_SET
39 * - Trace unit System registers not implemented
AlexeiFedorov7bb7a702023-01-17 17:04:14 +000040 * - Number of breakpoints:
41 * set in ID_AA64DFR0_EL1_SET
AlexeiFedoroveaec0c42023-02-01 18:13:32 +000042 * - PMU Snapshot extension not implemented
AlexeiFedorov7bb7a702023-01-17 17:04:14 +000043 * - Number of watchpoints:
44 * set in ID_AA64DFR0_EL1_SET
AlexeiFedoroveaec0c42023-02-01 18:13:32 +000045 * - Synchronous-exception-based event profiling not implemented
AlexeiFedorov7bb7a702023-01-17 17:04:14 +000046 * - Number of breakpoints that are context-aware
47 * - Statistical Profiling Extension not implemented
48 * - Armv8.4 Self-hosted Trace Extension not implemented
49 * - Trace Buffer Extension not implemented
AlexeiFedorov7bb7a702023-01-17 17:04:14 +000050 * - Branch Record Buffer Extension not implemented
AlexeiFedoroveaec0c42023-02-01 18:13:32 +000051 * - Trace Buffer External Mode not implemented
AlexeiFedorov7bb7a702023-01-17 17:04:14 +000052 */
53#define ID_AA64DFR0_EL1_CLEAR \
AlexeiFedorov537bee02023-02-02 13:38:23 +000054 MASK(ID_AA64DFR0_EL1_DebugVer) | \
55 MASK(ID_AA64DFR0_EL1_TraceVer) | \
AlexeiFedorov537bee02023-02-02 13:38:23 +000056 MASK(ID_AA64DFR0_EL1_BRPs) | \
AlexeiFedoroveaec0c42023-02-01 18:13:32 +000057 MASK(ID_AA64DFR0_EL1_PMSS) | \
AlexeiFedorov537bee02023-02-02 13:38:23 +000058 MASK(ID_AA64DFR0_EL1_WRPs) | \
AlexeiFedoroveaec0c42023-02-01 18:13:32 +000059 MASK(ID_AA64DFR0_EL1_SEBEP) | \
AlexeiFedorov537bee02023-02-02 13:38:23 +000060 MASK(ID_AA64DFR0_EL1_CTX_CMPS) | \
61 MASK(ID_AA64DFR0_EL1_PMSVer) | \
62 MASK(ID_AA64DFR0_EL1_TraceFilt) | \
63 MASK(ID_AA64DFR0_EL1_TraceBuffer) | \
AlexeiFedoroveaec0c42023-02-01 18:13:32 +000064 MASK(ID_AA64DFR0_EL1_BRBE) | \
65 MASK(ID_AA64DFR0_EL1_ExtTrcBuff)
AlexeiFedorov7bb7a702023-01-17 17:04:14 +000066
67/*
68 * Set fields:
69 * - Armv8 debug architecture
70 * - Number of breakpoints: 2
71 * - Number of watchpoints: 2
72 */
AlexeiFedoroveaec0c42023-02-01 18:13:32 +000073#define ID_AA64DFR0_EL1_SET \
74 INPLACE(ID_AA64DFR0_EL1_DebugVer, ID_AA64DFR0_EL1_Debugv8) | \
75 INPLACE(ID_AA64DFR0_EL1_BRPs, 1UL) | \
AlexeiFedorov7bb7a702023-01-17 17:04:14 +000076 INPLACE(ID_AA64DFR0_EL1_WRPs, 1UL)
77
78/*
AlexeiFedoroveaec0c42023-02-01 18:13:32 +000079 * ID_AA64DFR1_EL1:
80 *
81 * Cleared fields:
82 * - Exception-based event profiling not implemented
83 * - PMU fixed-function instruction counter not implemented
84 */
85#define ID_AA64DFR1_EL1_CLEAR \
86 MASK(ID_AA64DFR1_EL1_EBEP) | \
87 MASK(ID_AA64DFR1_EL1_ICNTR)
88
89/*
AlexeiFedorov7bb7a702023-01-17 17:04:14 +000090 * ID_AA64PFR0_EL1:
91 *
92 * Cleared fields:
93 * - Activity Monitors Extension not implemented
AlexeiFedorov7bb7a702023-01-17 17:04:14 +000094 */
95#define ID_AA64PFR0_EL1_CLEAR \
Arunachalam Ganapathyf6491212023-02-23 16:04:34 +000096 MASK(ID_AA64PFR0_EL1_AMU)
Soby Mathewb4c6df42022-11-09 11:13:29 +000097/*
Arunachalam Ganapathya27de372023-03-06 11:13:49 +000098 * ID_AA64PFR1_EL1:
99 *
100 * Cleared fields:
101 * - Memory Tagging Extension is not implemented
102 */
103#define ID_AA64PFR1_EL1_CLEAR \
104 MASK(ID_AA64PFR1_EL1_MTE)
105
106/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000107 * Handle ID_AA64XXX<n>_EL1 instructions
108 */
109static bool handle_id_sysreg_trap(struct rec *rec,
110 struct rmi_rec_exit *rec_exit,
111 unsigned long esr)
112{
113 unsigned int rt;
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000114 unsigned long idreg, value;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000115
116 /*
117 * We only set HCR_EL2.TID3 to trap ID registers at the moment and
118 * that only traps reads of registers. Seeing a write here indicates a
119 * consistency problem with the RMM and we should panic immediately.
120 */
121 assert(!ESR_EL2_SYSREG_IS_WRITE(esr));
122
123 /*
124 * Read Rt value from the issued instruction,
125 * the general-purpose register used for the transfer.
AlexeiFedorovfeaef162022-12-23 16:59:51 +0000126 * Rt bits [9:5] of ISS field cannot exceed 0b11111.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000127 */
128 rt = ESR_EL2_SYSREG_ISS_RT(esr);
129
130 /* Handle writes to XZR register */
131 if (rt == 31U) {
132 return true;
133 }
134
135 idreg = esr & ESR_EL2_SYSREG_MASK;
136
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000137 switch (idreg) {
138 SYSREG_CASE(AFR0)
139 value = SYSREG_READ(AFR0);
140 break;
141 SYSREG_CASE(AFR1)
142 value = SYSREG_READ(AFR1);
143 break;
144 SYSREG_CASE(DFR0)
145 value = SYSREG_READ_CLEAR_SET(DFR0);
146 break;
147 SYSREG_CASE(DFR1)
AlexeiFedoroveaec0c42023-02-01 18:13:32 +0000148 value = SYSREG_READ_CLEAR(DFR1);
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000149 break;
150 SYSREG_CASE(ISAR0)
151 value = SYSREG_READ(ISAR0);
152 break;
153 SYSREG_CASE(ISAR1)
Arvind Ram Prakashbd36a1b2022-12-15 12:16:36 -0600154 value = SYSREG_READ(ISAR1);
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000155 break;
156 SYSREG_CASE(MMFR0)
157 value = SYSREG_READ(MMFR0);
158 break;
159 SYSREG_CASE(MMFR1)
160 value = SYSREG_READ(MMFR1);
161 break;
162 SYSREG_CASE(MMFR2)
163 value = SYSREG_READ(MMFR2);
164 break;
165 SYSREG_CASE(PFR0)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000166 /*
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000167 * Workaround for TF-A trapping AMU registers access
168 * to EL3 in Realm state.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000169 */
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000170 value = SYSREG_READ_CLEAR(PFR0);
Arunachalam Ganapathyf6491212023-02-23 16:04:34 +0000171
172 /*
173 * Clear SVE bits if architecture supports it but SVE is
174 * disabled for current realm.
175 */
176 if ((EXTRACT(ID_AA64PFR0_EL1_SVE, value) != 0UL) &&
177 rec->realm_info.sve_enabled == false) {
178 value &= ~MASK(ID_AA64PFR0_EL1_SVE);
179 }
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000180 break;
181 SYSREG_CASE(PFR1)
Arunachalam Ganapathya27de372023-03-06 11:13:49 +0000182 value = SYSREG_READ_CLEAR(PFR1);
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000183 break;
Arunachalam Ganapathyf6491212023-02-23 16:04:34 +0000184 SYSREG_CASE(ZFR0)
185 if (is_feat_sve_present() && rec->realm_info.sve_enabled) {
186 value = read_id_aa64zfr0_el1();
187 } else {
188 value = 0UL;
189 }
190 break;
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000191 default:
192 /* All other encodings are in the RES0 space */
193 value = 0UL;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000194 }
195
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000196 rec->regs[rt] = value;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000197 return true;
198}
199
200static bool handle_icc_el1_sysreg_trap(struct rec *rec,
201 struct rmi_rec_exit *rec_exit,
202 unsigned long esr)
203{
204 __unused unsigned long sysreg = esr & ESR_EL2_SYSREG_MASK;
205
206 /*
207 * We should only have configured ICH_HCR_EL2 to trap on DIR and we
208 * always trap on the SGIRs following the architecture, so make sure
209 * we're not accidentally trapping on some other register here.
210 */
211 assert((sysreg == ESR_EL2_SYSREG_ICC_DIR) ||
212 (sysreg == ESR_EL2_SYSREG_ICC_SGI1R_EL1) ||
213 (sysreg == ESR_EL2_SYSREG_ICC_SGI0R_EL1));
214
215 /*
216 * The registers above should only trap to EL2 for writes, read
217 * instructions are not defined and should cause an Undefined exception
218 * at EL1.
219 */
220 assert(ESR_EL2_SYSREG_IS_WRITE(esr));
221
222 rec_exit->exit_reason = RMI_EXIT_SYNC;
223 rec_exit->esr = esr;
224 return false;
225}
226
227typedef bool (*sysreg_handler_fn)(struct rec *rec, struct rmi_rec_exit *rec_exit,
228 unsigned long esr);
229
230struct sysreg_handler {
231 unsigned long esr_mask;
232 unsigned long esr_value;
233 sysreg_handler_fn fn;
234};
235
236#define SYSREG_HANDLER(_mask, _value, _handler_fn) \
237 { .esr_mask = (_mask), .esr_value = (_value), .fn = _handler_fn }
238
239static const struct sysreg_handler sysreg_handlers[] = {
240 SYSREG_HANDLER(ESR_EL2_SYSREG_ID_MASK, ESR_EL2_SYSREG_ID, handle_id_sysreg_trap),
241 SYSREG_HANDLER(ESR_EL2_SYSREG_ICC_EL1_MASK, ESR_EL2_SYSREG_ICC_EL1, handle_icc_el1_sysreg_trap),
242 SYSREG_HANDLER(ESR_EL2_SYSREG_MASK, ESR_EL2_SYSREG_ICC_PMR_EL1, handle_icc_el1_sysreg_trap)
243};
244
245static unsigned long get_sysreg_write_value(struct rec *rec, unsigned long esr)
246{
AlexeiFedorovfeaef162022-12-23 16:59:51 +0000247 /* Rt bits [9:5] of ISS field cannot exceed 0b11111 */
248 unsigned int rt = ESR_EL2_SYSREG_ISS_RT(esr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000249
250 /* Handle reads from XZR register */
251 if (rt == 31U) {
252 return 0UL;
253 }
254
AlexeiFedorovfeaef162022-12-23 16:59:51 +0000255 return rec->regs[rt];
Soby Mathewb4c6df42022-11-09 11:13:29 +0000256}
257
258static void emulate_sysreg_access_ns(struct rec *rec, struct rmi_rec_exit *rec_exit,
259 unsigned long esr)
260{
261 if (ESR_EL2_SYSREG_IS_WRITE(esr)) {
262 rec_exit->gprs[0] = get_sysreg_write_value(rec, esr);
263 }
264}
265
266/*
267 * Handle trapped MSR, MRS or System instruction execution
268 * in AArch64 state
269 */
270bool handle_sysreg_access_trap(struct rec *rec, struct rmi_rec_exit *rec_exit,
271 unsigned long esr)
272{
273 /*
274 * Read Rt value from the issued instruction,
275 * the general-purpose register used for the transfer.
AlexeiFedorovfeaef162022-12-23 16:59:51 +0000276 * Rt bits [9:5] of ISS field cannot exceed 0b11111.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000277 */
278 unsigned int rt = ESR_EL2_SYSREG_ISS_RT(esr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000279 unsigned int __unused op0, op1, crn, crm, op2;
280 unsigned long __unused sysreg;
281
282 /* Check for 32-bit instruction trapped */
283 assert(ESR_IL(esr) != 0UL);
284
Shruti Gupta9debb132022-12-13 14:38:49 +0000285 for (unsigned int i = 0U; i < ARRAY_LEN(sysreg_handlers); i++) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000286 const struct sysreg_handler *handler = &sysreg_handlers[i];
Soby Mathewb4c6df42022-11-09 11:13:29 +0000287
288 if ((esr & handler->esr_mask) == handler->esr_value) {
Shruti Gupta9debb132022-12-13 14:38:49 +0000289 bool handled = handler->fn(rec, rec_exit, esr);
290
Soby Mathewb4c6df42022-11-09 11:13:29 +0000291 if (!handled) {
292 emulate_sysreg_access_ns(rec, rec_exit, esr);
293 }
294 return handled;
295 }
296 }
297
298 /*
299 * For now, treat all unhandled accesses as RAZ/WI.
300 * Handle writes to XZR register.
301 */
302 if (!ESR_EL2_SYSREG_IS_WRITE(esr) && (rt != 31U)) {
AlexeiFedorovfeaef162022-12-23 16:59:51 +0000303 rec->regs[rt] = 0UL;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000304 }
305
306 sysreg = esr & ESR_EL2_SYSREG_MASK;
307
308 /* Extract sytem register encoding */
309 op0 = EXTRACT(ESR_EL2_SYSREG_TRAP_OP0, sysreg);
310 op1 = EXTRACT(ESR_EL2_SYSREG_TRAP_OP1, sysreg);
311 crn = EXTRACT(ESR_EL2_SYSREG_TRAP_CRN, sysreg);
312 crm = EXTRACT(ESR_EL2_SYSREG_TRAP_CRM, sysreg);
313 op2 = EXTRACT(ESR_EL2_SYSREG_TRAP_OP2, sysreg);
314
315 INFO("Unhandled %s S%u_%u_C%u_C%u_%u\n",
316 ESR_EL2_SYSREG_IS_WRITE(esr) ? "write" : "read",
317 op0, op1, crn, crm, op2);
318
319 return true;
320}