blob: c45b474072843d8ed16fda68c8c589386248c828 [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>
8#include <arch_helpers.h>
9#include <debug.h>
10#include <esr.h>
11#include <memory_alloc.h>
12#include <rec.h>
13#include <smc-rmi.h>
14
AlexeiFedorov7bb7a702023-01-17 17:04:14 +000015#define SYSREG_CASE(reg) \
16 case ESR_EL2_SYSREG_##ID_AA64##reg##_EL1:
Soby Mathewb4c6df42022-11-09 11:13:29 +000017
AlexeiFedorov7bb7a702023-01-17 17:04:14 +000018#define SYSREG_READ(reg) \
19 read_ID_AA64##reg##_EL1()
Soby Mathewb4c6df42022-11-09 11:13:29 +000020
AlexeiFedorov7bb7a702023-01-17 17:04:14 +000021#define SYSREG_READ_CLEAR(reg) \
22 (read_ID_AA64##reg##_EL1() & \
23 ~(ID_AA64##reg##_EL1_CLEAR))
24
25#define SYSREG_READ_CLEAR_SET(reg) \
26 ((read_ID_AA64##reg##_EL1() & \
27 ~(ID_AA64##reg##_EL1_CLEAR)) | \
28 (ID_AA64##reg##_EL1_SET))
29
30/* System registers ID_AA64xxx_EL1 feature clear masks and set values */
31
32/*
33 * ID_AA64DFR0_EL1:
34 *
35 * Cleared fields:
36 * - Debug architecture version:
37 * set in ID_AA64DFR0_EL1_SET
38 * - Trace unit System registers not implemented
39 * - PMU is not implemented
40 * - Number of breakpoints:
41 * set in ID_AA64DFR0_EL1_SET
42 * - Number of watchpoints:
43 * set in ID_AA64DFR0_EL1_SET
44 * - Number of breakpoints that are context-aware
45 * - Statistical Profiling Extension not implemented
46 * - Armv8.4 Self-hosted Trace Extension not implemented
47 * - Trace Buffer Extension not implemented
48 * - FEAT_MTPMU not implemented
49 * - Branch Record Buffer Extension not implemented
50 */
51#define ID_AA64DFR0_EL1_CLEAR \
AlexeiFedorov537bee02023-02-02 13:38:23 +000052 MASK(ID_AA64DFR0_EL1_DebugVer) | \
53 MASK(ID_AA64DFR0_EL1_TraceVer) | \
54 MASK(ID_AA64DFR0_EL1_PMUVer) | \
55 MASK(ID_AA64DFR0_EL1_BRPs) | \
56 MASK(ID_AA64DFR0_EL1_WRPs) | \
57 MASK(ID_AA64DFR0_EL1_CTX_CMPS) | \
58 MASK(ID_AA64DFR0_EL1_PMSVer) | \
59 MASK(ID_AA64DFR0_EL1_TraceFilt) | \
60 MASK(ID_AA64DFR0_EL1_TraceBuffer) | \
61 MASK(ID_AA64DFR0_EL1_MTPMU) | \
62 MASK(ID_AA64DFR0_EL1_BRBE)
AlexeiFedorov7bb7a702023-01-17 17:04:14 +000063
64/*
65 * Set fields:
66 * - Armv8 debug architecture
67 * - Number of breakpoints: 2
68 * - Number of watchpoints: 2
69 */
70#define ID_AA64DFR0_EL1_SET \
71 ID_AA64DFR0_EL1_DebugVer_8 | \
72 INPLACE(ID_AA64DFR0_EL1_BRPs, 1UL) | \
73 INPLACE(ID_AA64DFR0_EL1_WRPs, 1UL)
74
75/*
76 * ID_AA64ISAR1_EL1:
77 *
78 * Cleared fields:
79 * - Address and Generic Authentication are not implemented
80 */
81#define ID_AA64ISAR1_EL1_CLEAR \
AlexeiFedorov537bee02023-02-02 13:38:23 +000082 MASK(ID_AA64ISAR1_EL1_APA) | \
83 MASK(ID_AA64ISAR1_EL1_API) | \
84 MASK(ID_AA64ISAR1_EL1_GPA) | \
85 MASK(ID_AA64ISAR1_EL1_GPI)
AlexeiFedorov7bb7a702023-01-17 17:04:14 +000086
87/*
88 * ID_AA64PFR0_EL1:
89 *
90 * Cleared fields:
91 * - Activity Monitors Extension not implemented
92 * - Scalable Vector Extension not implemented.
93 * This is a temporary fix until RMM completely supports SVE.
AlexeiFedorov7bb7a702023-01-17 17:04:14 +000094 */
95#define ID_AA64PFR0_EL1_CLEAR \
96 MASK(ID_AA64PFR0_EL1_AMU) | \
97 MASK(ID_AA64PFR0_EL1_SVE)
Soby Mathewb4c6df42022-11-09 11:13:29 +000098
99/*
Arunachalam Ganapathya27de372023-03-06 11:13:49 +0000100 * ID_AA64PFR1_EL1:
101 *
102 * Cleared fields:
103 * - Memory Tagging Extension is not implemented
104 */
105#define ID_AA64PFR1_EL1_CLEAR \
106 MASK(ID_AA64PFR1_EL1_MTE)
107
108/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000109 * Handle ID_AA64XXX<n>_EL1 instructions
110 */
111static bool handle_id_sysreg_trap(struct rec *rec,
112 struct rmi_rec_exit *rec_exit,
113 unsigned long esr)
114{
115 unsigned int rt;
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000116 unsigned long idreg, value;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000117
118 /*
119 * We only set HCR_EL2.TID3 to trap ID registers at the moment and
120 * that only traps reads of registers. Seeing a write here indicates a
121 * consistency problem with the RMM and we should panic immediately.
122 */
123 assert(!ESR_EL2_SYSREG_IS_WRITE(esr));
124
125 /*
126 * Read Rt value from the issued instruction,
127 * the general-purpose register used for the transfer.
AlexeiFedorovfeaef162022-12-23 16:59:51 +0000128 * Rt bits [9:5] of ISS field cannot exceed 0b11111.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000129 */
130 rt = ESR_EL2_SYSREG_ISS_RT(esr);
131
132 /* Handle writes to XZR register */
133 if (rt == 31U) {
134 return true;
135 }
136
137 idreg = esr & ESR_EL2_SYSREG_MASK;
138
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000139 switch (idreg) {
140 SYSREG_CASE(AFR0)
141 value = SYSREG_READ(AFR0);
142 break;
143 SYSREG_CASE(AFR1)
144 value = SYSREG_READ(AFR1);
145 break;
146 SYSREG_CASE(DFR0)
147 value = SYSREG_READ_CLEAR_SET(DFR0);
148 break;
149 SYSREG_CASE(DFR1)
150 value = SYSREG_READ(DFR1);
151 break;
152 SYSREG_CASE(ISAR0)
153 value = SYSREG_READ(ISAR0);
154 break;
155 SYSREG_CASE(ISAR1)
156 value = SYSREG_READ_CLEAR(ISAR1);
157 break;
158 SYSREG_CASE(MMFR0)
159 value = SYSREG_READ(MMFR0);
160 break;
161 SYSREG_CASE(MMFR1)
162 value = SYSREG_READ(MMFR1);
163 break;
164 SYSREG_CASE(MMFR2)
165 value = SYSREG_READ(MMFR2);
166 break;
167 SYSREG_CASE(PFR0)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000168 /*
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000169 * Workaround for TF-A trapping AMU registers access
170 * to EL3 in Realm state.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000171 */
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000172 value = SYSREG_READ_CLEAR(PFR0);
173 break;
174 SYSREG_CASE(PFR1)
Arunachalam Ganapathya27de372023-03-06 11:13:49 +0000175 value = SYSREG_READ_CLEAR(PFR1);
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000176 break;
177 /*
178 * TODO: not supported without SVE:
179 * SYSREG_CASE(ZFR0)
180 */
181 default:
182 /* All other encodings are in the RES0 space */
183 value = 0UL;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000184 }
185
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000186 rec->regs[rt] = value;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000187 return true;
188}
189
190static bool handle_icc_el1_sysreg_trap(struct rec *rec,
191 struct rmi_rec_exit *rec_exit,
192 unsigned long esr)
193{
194 __unused unsigned long sysreg = esr & ESR_EL2_SYSREG_MASK;
195
196 /*
197 * We should only have configured ICH_HCR_EL2 to trap on DIR and we
198 * always trap on the SGIRs following the architecture, so make sure
199 * we're not accidentally trapping on some other register here.
200 */
201 assert((sysreg == ESR_EL2_SYSREG_ICC_DIR) ||
202 (sysreg == ESR_EL2_SYSREG_ICC_SGI1R_EL1) ||
203 (sysreg == ESR_EL2_SYSREG_ICC_SGI0R_EL1));
204
205 /*
206 * The registers above should only trap to EL2 for writes, read
207 * instructions are not defined and should cause an Undefined exception
208 * at EL1.
209 */
210 assert(ESR_EL2_SYSREG_IS_WRITE(esr));
211
212 rec_exit->exit_reason = RMI_EXIT_SYNC;
213 rec_exit->esr = esr;
214 return false;
215}
216
217typedef bool (*sysreg_handler_fn)(struct rec *rec, struct rmi_rec_exit *rec_exit,
218 unsigned long esr);
219
220struct sysreg_handler {
221 unsigned long esr_mask;
222 unsigned long esr_value;
223 sysreg_handler_fn fn;
224};
225
226#define SYSREG_HANDLER(_mask, _value, _handler_fn) \
227 { .esr_mask = (_mask), .esr_value = (_value), .fn = _handler_fn }
228
229static const struct sysreg_handler sysreg_handlers[] = {
230 SYSREG_HANDLER(ESR_EL2_SYSREG_ID_MASK, ESR_EL2_SYSREG_ID, handle_id_sysreg_trap),
231 SYSREG_HANDLER(ESR_EL2_SYSREG_ICC_EL1_MASK, ESR_EL2_SYSREG_ICC_EL1, handle_icc_el1_sysreg_trap),
232 SYSREG_HANDLER(ESR_EL2_SYSREG_MASK, ESR_EL2_SYSREG_ICC_PMR_EL1, handle_icc_el1_sysreg_trap)
233};
234
235static unsigned long get_sysreg_write_value(struct rec *rec, unsigned long esr)
236{
AlexeiFedorovfeaef162022-12-23 16:59:51 +0000237 /* Rt bits [9:5] of ISS field cannot exceed 0b11111 */
238 unsigned int rt = ESR_EL2_SYSREG_ISS_RT(esr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000239
240 /* Handle reads from XZR register */
241 if (rt == 31U) {
242 return 0UL;
243 }
244
AlexeiFedorovfeaef162022-12-23 16:59:51 +0000245 return rec->regs[rt];
Soby Mathewb4c6df42022-11-09 11:13:29 +0000246}
247
248static void emulate_sysreg_access_ns(struct rec *rec, struct rmi_rec_exit *rec_exit,
249 unsigned long esr)
250{
251 if (ESR_EL2_SYSREG_IS_WRITE(esr)) {
252 rec_exit->gprs[0] = get_sysreg_write_value(rec, esr);
253 }
254}
255
256/*
257 * Handle trapped MSR, MRS or System instruction execution
258 * in AArch64 state
259 */
260bool handle_sysreg_access_trap(struct rec *rec, struct rmi_rec_exit *rec_exit,
261 unsigned long esr)
262{
263 /*
264 * Read Rt value from the issued instruction,
265 * the general-purpose register used for the transfer.
AlexeiFedorovfeaef162022-12-23 16:59:51 +0000266 * Rt bits [9:5] of ISS field cannot exceed 0b11111.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000267 */
268 unsigned int rt = ESR_EL2_SYSREG_ISS_RT(esr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000269 unsigned int __unused op0, op1, crn, crm, op2;
270 unsigned long __unused sysreg;
271
272 /* Check for 32-bit instruction trapped */
273 assert(ESR_IL(esr) != 0UL);
274
Shruti Gupta9debb132022-12-13 14:38:49 +0000275 for (unsigned int i = 0U; i < ARRAY_LEN(sysreg_handlers); i++) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000276 const struct sysreg_handler *handler = &sysreg_handlers[i];
Soby Mathewb4c6df42022-11-09 11:13:29 +0000277
278 if ((esr & handler->esr_mask) == handler->esr_value) {
Shruti Gupta9debb132022-12-13 14:38:49 +0000279 bool handled = handler->fn(rec, rec_exit, esr);
280
Soby Mathewb4c6df42022-11-09 11:13:29 +0000281 if (!handled) {
282 emulate_sysreg_access_ns(rec, rec_exit, esr);
283 }
284 return handled;
285 }
286 }
287
288 /*
289 * For now, treat all unhandled accesses as RAZ/WI.
290 * Handle writes to XZR register.
291 */
292 if (!ESR_EL2_SYSREG_IS_WRITE(esr) && (rt != 31U)) {
AlexeiFedorovfeaef162022-12-23 16:59:51 +0000293 rec->regs[rt] = 0UL;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000294 }
295
296 sysreg = esr & ESR_EL2_SYSREG_MASK;
297
298 /* Extract sytem register encoding */
299 op0 = EXTRACT(ESR_EL2_SYSREG_TRAP_OP0, sysreg);
300 op1 = EXTRACT(ESR_EL2_SYSREG_TRAP_OP1, sysreg);
301 crn = EXTRACT(ESR_EL2_SYSREG_TRAP_CRN, sysreg);
302 crm = EXTRACT(ESR_EL2_SYSREG_TRAP_CRM, sysreg);
303 op2 = EXTRACT(ESR_EL2_SYSREG_TRAP_OP2, sysreg);
304
305 INFO("Unhandled %s S%u_%u_C%u_C%u_%u\n",
306 ESR_EL2_SYSREG_IS_WRITE(esr) ? "write" : "read",
307 op0, op1, crn, crm, op2);
308
309 return true;
310}