blob: fa0275eb621a248efcf6ded99ace24332b4fbc11 [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_AA64ISAR1_EL1:
91 *
92 * Cleared fields:
93 * - Address and Generic Authentication are not implemented
94 */
95#define ID_AA64ISAR1_EL1_CLEAR \
AlexeiFedorov537bee02023-02-02 13:38:23 +000096 MASK(ID_AA64ISAR1_EL1_APA) | \
97 MASK(ID_AA64ISAR1_EL1_API) | \
98 MASK(ID_AA64ISAR1_EL1_GPA) | \
99 MASK(ID_AA64ISAR1_EL1_GPI)
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000100
101/*
102 * ID_AA64PFR0_EL1:
103 *
104 * Cleared fields:
105 * - Activity Monitors Extension not implemented
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000106 */
107#define ID_AA64PFR0_EL1_CLEAR \
Arunachalam Ganapathyf6491212023-02-23 16:04:34 +0000108 MASK(ID_AA64PFR0_EL1_AMU)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000109/*
Arunachalam Ganapathya27de372023-03-06 11:13:49 +0000110 * ID_AA64PFR1_EL1:
111 *
112 * Cleared fields:
113 * - Memory Tagging Extension is not implemented
114 */
115#define ID_AA64PFR1_EL1_CLEAR \
116 MASK(ID_AA64PFR1_EL1_MTE)
117
118/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000119 * Handle ID_AA64XXX<n>_EL1 instructions
120 */
121static bool handle_id_sysreg_trap(struct rec *rec,
122 struct rmi_rec_exit *rec_exit,
123 unsigned long esr)
124{
125 unsigned int rt;
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000126 unsigned long idreg, value;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000127
128 /*
129 * We only set HCR_EL2.TID3 to trap ID registers at the moment and
130 * that only traps reads of registers. Seeing a write here indicates a
131 * consistency problem with the RMM and we should panic immediately.
132 */
133 assert(!ESR_EL2_SYSREG_IS_WRITE(esr));
134
135 /*
136 * Read Rt value from the issued instruction,
137 * the general-purpose register used for the transfer.
AlexeiFedorovfeaef162022-12-23 16:59:51 +0000138 * Rt bits [9:5] of ISS field cannot exceed 0b11111.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000139 */
140 rt = ESR_EL2_SYSREG_ISS_RT(esr);
141
142 /* Handle writes to XZR register */
143 if (rt == 31U) {
144 return true;
145 }
146
147 idreg = esr & ESR_EL2_SYSREG_MASK;
148
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000149 switch (idreg) {
150 SYSREG_CASE(AFR0)
151 value = SYSREG_READ(AFR0);
152 break;
153 SYSREG_CASE(AFR1)
154 value = SYSREG_READ(AFR1);
155 break;
156 SYSREG_CASE(DFR0)
157 value = SYSREG_READ_CLEAR_SET(DFR0);
158 break;
159 SYSREG_CASE(DFR1)
AlexeiFedoroveaec0c42023-02-01 18:13:32 +0000160 value = SYSREG_READ_CLEAR(DFR1);
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000161 break;
162 SYSREG_CASE(ISAR0)
163 value = SYSREG_READ(ISAR0);
164 break;
165 SYSREG_CASE(ISAR1)
166 value = SYSREG_READ_CLEAR(ISAR1);
167 break;
168 SYSREG_CASE(MMFR0)
169 value = SYSREG_READ(MMFR0);
170 break;
171 SYSREG_CASE(MMFR1)
172 value = SYSREG_READ(MMFR1);
173 break;
174 SYSREG_CASE(MMFR2)
175 value = SYSREG_READ(MMFR2);
176 break;
177 SYSREG_CASE(PFR0)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000178 /*
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000179 * Workaround for TF-A trapping AMU registers access
180 * to EL3 in Realm state.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000181 */
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000182 value = SYSREG_READ_CLEAR(PFR0);
Arunachalam Ganapathyf6491212023-02-23 16:04:34 +0000183
184 /*
185 * Clear SVE bits if architecture supports it but SVE is
186 * disabled for current realm.
187 */
188 if ((EXTRACT(ID_AA64PFR0_EL1_SVE, value) != 0UL) &&
189 rec->realm_info.sve_enabled == false) {
190 value &= ~MASK(ID_AA64PFR0_EL1_SVE);
191 }
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000192 break;
193 SYSREG_CASE(PFR1)
Arunachalam Ganapathya27de372023-03-06 11:13:49 +0000194 value = SYSREG_READ_CLEAR(PFR1);
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000195 break;
Arunachalam Ganapathyf6491212023-02-23 16:04:34 +0000196 SYSREG_CASE(ZFR0)
197 if (is_feat_sve_present() && rec->realm_info.sve_enabled) {
198 value = read_id_aa64zfr0_el1();
199 } else {
200 value = 0UL;
201 }
202 break;
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000203 default:
204 /* All other encodings are in the RES0 space */
205 value = 0UL;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000206 }
207
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000208 rec->regs[rt] = value;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000209 return true;
210}
211
212static bool handle_icc_el1_sysreg_trap(struct rec *rec,
213 struct rmi_rec_exit *rec_exit,
214 unsigned long esr)
215{
216 __unused unsigned long sysreg = esr & ESR_EL2_SYSREG_MASK;
217
218 /*
219 * We should only have configured ICH_HCR_EL2 to trap on DIR and we
220 * always trap on the SGIRs following the architecture, so make sure
221 * we're not accidentally trapping on some other register here.
222 */
223 assert((sysreg == ESR_EL2_SYSREG_ICC_DIR) ||
224 (sysreg == ESR_EL2_SYSREG_ICC_SGI1R_EL1) ||
225 (sysreg == ESR_EL2_SYSREG_ICC_SGI0R_EL1));
226
227 /*
228 * The registers above should only trap to EL2 for writes, read
229 * instructions are not defined and should cause an Undefined exception
230 * at EL1.
231 */
232 assert(ESR_EL2_SYSREG_IS_WRITE(esr));
233
234 rec_exit->exit_reason = RMI_EXIT_SYNC;
235 rec_exit->esr = esr;
236 return false;
237}
238
239typedef bool (*sysreg_handler_fn)(struct rec *rec, struct rmi_rec_exit *rec_exit,
240 unsigned long esr);
241
242struct sysreg_handler {
243 unsigned long esr_mask;
244 unsigned long esr_value;
245 sysreg_handler_fn fn;
246};
247
248#define SYSREG_HANDLER(_mask, _value, _handler_fn) \
249 { .esr_mask = (_mask), .esr_value = (_value), .fn = _handler_fn }
250
251static const struct sysreg_handler sysreg_handlers[] = {
252 SYSREG_HANDLER(ESR_EL2_SYSREG_ID_MASK, ESR_EL2_SYSREG_ID, handle_id_sysreg_trap),
253 SYSREG_HANDLER(ESR_EL2_SYSREG_ICC_EL1_MASK, ESR_EL2_SYSREG_ICC_EL1, handle_icc_el1_sysreg_trap),
254 SYSREG_HANDLER(ESR_EL2_SYSREG_MASK, ESR_EL2_SYSREG_ICC_PMR_EL1, handle_icc_el1_sysreg_trap)
255};
256
257static unsigned long get_sysreg_write_value(struct rec *rec, unsigned long esr)
258{
AlexeiFedorovfeaef162022-12-23 16:59:51 +0000259 /* Rt bits [9:5] of ISS field cannot exceed 0b11111 */
260 unsigned int rt = ESR_EL2_SYSREG_ISS_RT(esr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000261
262 /* Handle reads from XZR register */
263 if (rt == 31U) {
264 return 0UL;
265 }
266
AlexeiFedorovfeaef162022-12-23 16:59:51 +0000267 return rec->regs[rt];
Soby Mathewb4c6df42022-11-09 11:13:29 +0000268}
269
270static void emulate_sysreg_access_ns(struct rec *rec, struct rmi_rec_exit *rec_exit,
271 unsigned long esr)
272{
273 if (ESR_EL2_SYSREG_IS_WRITE(esr)) {
274 rec_exit->gprs[0] = get_sysreg_write_value(rec, esr);
275 }
276}
277
278/*
279 * Handle trapped MSR, MRS or System instruction execution
280 * in AArch64 state
281 */
282bool handle_sysreg_access_trap(struct rec *rec, struct rmi_rec_exit *rec_exit,
283 unsigned long esr)
284{
285 /*
286 * Read Rt value from the issued instruction,
287 * the general-purpose register used for the transfer.
AlexeiFedorovfeaef162022-12-23 16:59:51 +0000288 * Rt bits [9:5] of ISS field cannot exceed 0b11111.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000289 */
290 unsigned int rt = ESR_EL2_SYSREG_ISS_RT(esr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000291 unsigned int __unused op0, op1, crn, crm, op2;
292 unsigned long __unused sysreg;
293
294 /* Check for 32-bit instruction trapped */
295 assert(ESR_IL(esr) != 0UL);
296
Shruti Gupta9debb132022-12-13 14:38:49 +0000297 for (unsigned int i = 0U; i < ARRAY_LEN(sysreg_handlers); i++) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000298 const struct sysreg_handler *handler = &sysreg_handlers[i];
Soby Mathewb4c6df42022-11-09 11:13:29 +0000299
300 if ((esr & handler->esr_mask) == handler->esr_value) {
Shruti Gupta9debb132022-12-13 14:38:49 +0000301 bool handled = handler->fn(rec, rec_exit, esr);
302
Soby Mathewb4c6df42022-11-09 11:13:29 +0000303 if (!handled) {
304 emulate_sysreg_access_ns(rec, rec_exit, esr);
305 }
306 return handled;
307 }
308 }
309
310 /*
311 * For now, treat all unhandled accesses as RAZ/WI.
312 * Handle writes to XZR register.
313 */
314 if (!ESR_EL2_SYSREG_IS_WRITE(esr) && (rt != 31U)) {
AlexeiFedorovfeaef162022-12-23 16:59:51 +0000315 rec->regs[rt] = 0UL;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000316 }
317
318 sysreg = esr & ESR_EL2_SYSREG_MASK;
319
320 /* Extract sytem register encoding */
321 op0 = EXTRACT(ESR_EL2_SYSREG_TRAP_OP0, sysreg);
322 op1 = EXTRACT(ESR_EL2_SYSREG_TRAP_OP1, sysreg);
323 crn = EXTRACT(ESR_EL2_SYSREG_TRAP_CRN, sysreg);
324 crm = EXTRACT(ESR_EL2_SYSREG_TRAP_CRM, sysreg);
325 op2 = EXTRACT(ESR_EL2_SYSREG_TRAP_OP2, sysreg);
326
327 INFO("Unhandled %s S%u_%u_C%u_C%u_%u\n",
328 ESR_EL2_SYSREG_IS_WRITE(esr) ? "write" : "read",
329 op0, op1, crn, crm, op2);
330
331 return true;
332}