blob: 7a55e9a6a7725ac8a95434995ed6ad1a612ae9c7 [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/*
100 * Handle ID_AA64XXX<n>_EL1 instructions
101 */
102static bool handle_id_sysreg_trap(struct rec *rec,
103 struct rmi_rec_exit *rec_exit,
104 unsigned long esr)
105{
106 unsigned int rt;
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000107 unsigned long idreg, value;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000108
109 /*
110 * We only set HCR_EL2.TID3 to trap ID registers at the moment and
111 * that only traps reads of registers. Seeing a write here indicates a
112 * consistency problem with the RMM and we should panic immediately.
113 */
114 assert(!ESR_EL2_SYSREG_IS_WRITE(esr));
115
116 /*
117 * Read Rt value from the issued instruction,
118 * the general-purpose register used for the transfer.
AlexeiFedorovfeaef162022-12-23 16:59:51 +0000119 * Rt bits [9:5] of ISS field cannot exceed 0b11111.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000120 */
121 rt = ESR_EL2_SYSREG_ISS_RT(esr);
122
123 /* Handle writes to XZR register */
124 if (rt == 31U) {
125 return true;
126 }
127
128 idreg = esr & ESR_EL2_SYSREG_MASK;
129
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000130 switch (idreg) {
131 SYSREG_CASE(AFR0)
132 value = SYSREG_READ(AFR0);
133 break;
134 SYSREG_CASE(AFR1)
135 value = SYSREG_READ(AFR1);
136 break;
137 SYSREG_CASE(DFR0)
138 value = SYSREG_READ_CLEAR_SET(DFR0);
139 break;
140 SYSREG_CASE(DFR1)
141 value = SYSREG_READ(DFR1);
142 break;
143 SYSREG_CASE(ISAR0)
144 value = SYSREG_READ(ISAR0);
145 break;
146 SYSREG_CASE(ISAR1)
147 value = SYSREG_READ_CLEAR(ISAR1);
148 break;
149 SYSREG_CASE(MMFR0)
150 value = SYSREG_READ(MMFR0);
151 break;
152 SYSREG_CASE(MMFR1)
153 value = SYSREG_READ(MMFR1);
154 break;
155 SYSREG_CASE(MMFR2)
156 value = SYSREG_READ(MMFR2);
157 break;
158 SYSREG_CASE(PFR0)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000159 /*
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000160 * Workaround for TF-A trapping AMU registers access
161 * to EL3 in Realm state.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000162 */
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000163 value = SYSREG_READ_CLEAR(PFR0);
164 break;
165 SYSREG_CASE(PFR1)
166 value = SYSREG_READ(PFR1);
167 break;
168 /*
169 * TODO: not supported without SVE:
170 * SYSREG_CASE(ZFR0)
171 */
172 default:
173 /* All other encodings are in the RES0 space */
174 value = 0UL;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000175 }
176
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000177 rec->regs[rt] = value;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000178 return true;
179}
180
181static bool handle_icc_el1_sysreg_trap(struct rec *rec,
182 struct rmi_rec_exit *rec_exit,
183 unsigned long esr)
184{
185 __unused unsigned long sysreg = esr & ESR_EL2_SYSREG_MASK;
186
187 /*
188 * We should only have configured ICH_HCR_EL2 to trap on DIR and we
189 * always trap on the SGIRs following the architecture, so make sure
190 * we're not accidentally trapping on some other register here.
191 */
192 assert((sysreg == ESR_EL2_SYSREG_ICC_DIR) ||
193 (sysreg == ESR_EL2_SYSREG_ICC_SGI1R_EL1) ||
194 (sysreg == ESR_EL2_SYSREG_ICC_SGI0R_EL1));
195
196 /*
197 * The registers above should only trap to EL2 for writes, read
198 * instructions are not defined and should cause an Undefined exception
199 * at EL1.
200 */
201 assert(ESR_EL2_SYSREG_IS_WRITE(esr));
202
203 rec_exit->exit_reason = RMI_EXIT_SYNC;
204 rec_exit->esr = esr;
205 return false;
206}
207
208typedef bool (*sysreg_handler_fn)(struct rec *rec, struct rmi_rec_exit *rec_exit,
209 unsigned long esr);
210
211struct sysreg_handler {
212 unsigned long esr_mask;
213 unsigned long esr_value;
214 sysreg_handler_fn fn;
215};
216
217#define SYSREG_HANDLER(_mask, _value, _handler_fn) \
218 { .esr_mask = (_mask), .esr_value = (_value), .fn = _handler_fn }
219
220static const struct sysreg_handler sysreg_handlers[] = {
221 SYSREG_HANDLER(ESR_EL2_SYSREG_ID_MASK, ESR_EL2_SYSREG_ID, handle_id_sysreg_trap),
222 SYSREG_HANDLER(ESR_EL2_SYSREG_ICC_EL1_MASK, ESR_EL2_SYSREG_ICC_EL1, handle_icc_el1_sysreg_trap),
223 SYSREG_HANDLER(ESR_EL2_SYSREG_MASK, ESR_EL2_SYSREG_ICC_PMR_EL1, handle_icc_el1_sysreg_trap)
224};
225
226static unsigned long get_sysreg_write_value(struct rec *rec, unsigned long esr)
227{
AlexeiFedorovfeaef162022-12-23 16:59:51 +0000228 /* Rt bits [9:5] of ISS field cannot exceed 0b11111 */
229 unsigned int rt = ESR_EL2_SYSREG_ISS_RT(esr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000230
231 /* Handle reads from XZR register */
232 if (rt == 31U) {
233 return 0UL;
234 }
235
AlexeiFedorovfeaef162022-12-23 16:59:51 +0000236 return rec->regs[rt];
Soby Mathewb4c6df42022-11-09 11:13:29 +0000237}
238
239static void emulate_sysreg_access_ns(struct rec *rec, struct rmi_rec_exit *rec_exit,
240 unsigned long esr)
241{
242 if (ESR_EL2_SYSREG_IS_WRITE(esr)) {
243 rec_exit->gprs[0] = get_sysreg_write_value(rec, esr);
244 }
245}
246
247/*
248 * Handle trapped MSR, MRS or System instruction execution
249 * in AArch64 state
250 */
251bool handle_sysreg_access_trap(struct rec *rec, struct rmi_rec_exit *rec_exit,
252 unsigned long esr)
253{
254 /*
255 * Read Rt value from the issued instruction,
256 * the general-purpose register used for the transfer.
AlexeiFedorovfeaef162022-12-23 16:59:51 +0000257 * Rt bits [9:5] of ISS field cannot exceed 0b11111.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000258 */
259 unsigned int rt = ESR_EL2_SYSREG_ISS_RT(esr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000260 unsigned int __unused op0, op1, crn, crm, op2;
261 unsigned long __unused sysreg;
262
263 /* Check for 32-bit instruction trapped */
264 assert(ESR_IL(esr) != 0UL);
265
Shruti Gupta9debb132022-12-13 14:38:49 +0000266 for (unsigned int i = 0U; i < ARRAY_LEN(sysreg_handlers); i++) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000267 const struct sysreg_handler *handler = &sysreg_handlers[i];
Soby Mathewb4c6df42022-11-09 11:13:29 +0000268
269 if ((esr & handler->esr_mask) == handler->esr_value) {
Shruti Gupta9debb132022-12-13 14:38:49 +0000270 bool handled = handler->fn(rec, rec_exit, esr);
271
Soby Mathewb4c6df42022-11-09 11:13:29 +0000272 if (!handled) {
273 emulate_sysreg_access_ns(rec, rec_exit, esr);
274 }
275 return handled;
276 }
277 }
278
279 /*
280 * For now, treat all unhandled accesses as RAZ/WI.
281 * Handle writes to XZR register.
282 */
283 if (!ESR_EL2_SYSREG_IS_WRITE(esr) && (rt != 31U)) {
AlexeiFedorovfeaef162022-12-23 16:59:51 +0000284 rec->regs[rt] = 0UL;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000285 }
286
287 sysreg = esr & ESR_EL2_SYSREG_MASK;
288
289 /* Extract sytem register encoding */
290 op0 = EXTRACT(ESR_EL2_SYSREG_TRAP_OP0, sysreg);
291 op1 = EXTRACT(ESR_EL2_SYSREG_TRAP_OP1, sysreg);
292 crn = EXTRACT(ESR_EL2_SYSREG_TRAP_CRN, sysreg);
293 crm = EXTRACT(ESR_EL2_SYSREG_TRAP_CRM, sysreg);
294 op2 = EXTRACT(ESR_EL2_SYSREG_TRAP_OP2, sysreg);
295
296 INFO("Unhandled %s S%u_%u_C%u_C%u_%u\n",
297 ESR_EL2_SYSREG_IS_WRITE(esr) ? "write" : "read",
298 op0, op1, crn, crm, op2);
299
300 return true;
301}