blob: 7b8ab09bf180b8018cbacfb57ab449b033f870c9 [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 \
52 ID_AA64DFR0_EL1_DebugVer_MASK | \
53 ID_AA64DFR0_EL1_TraceVer_MASK | \
54 ID_AA64DFR0_EL1_PMUVer_MASK | \
55 ID_AA64DFR0_EL1_BRPs_MASK | \
56 ID_AA64DFR0_EL1_WRPs_MASK | \
57 ID_AA64DFR0_EL1_CTX_CMPS_MASK | \
58 ID_AA64DFR0_EL1_PMSVer_MASK | \
59 ID_AA64DFR0_EL1_TraceFilt_MASK | \
60 ID_AA64DFR0_EL1_TraceBuffer_MASK | \
61 ID_AA64DFR0_EL1_MTPMU_MASK | \
62 ID_AA64DFR0_EL1_BRBE_MASK
63
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 \
82 ID_AA64ISAR1_EL1_APA_MASK | \
83 ID_AA64ISAR1_EL1_API_MASK | \
84 ID_AA64ISAR1_EL1_GPA_MASK | \
85 ID_AA64ISAR1_EL1_GPI_MASK
86
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.
94 *
95 * TODO: use and define:
96 * ID_AA64PFR0_EL1_AMU_MASK & ID_AA64PFR0_EL1_SVE_MASK
97 */
98#define ID_AA64PFR0_EL1_CLEAR \
99 MASK(ID_AA64PFR0_EL1_AMU) | \
100 MASK(ID_AA64PFR0_EL1_SVE)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000101
102/*
103 * Handle ID_AA64XXX<n>_EL1 instructions
104 */
105static bool handle_id_sysreg_trap(struct rec *rec,
106 struct rmi_rec_exit *rec_exit,
107 unsigned long esr)
108{
109 unsigned int rt;
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000110 unsigned long idreg, value;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000111
112 /*
113 * We only set HCR_EL2.TID3 to trap ID registers at the moment and
114 * that only traps reads of registers. Seeing a write here indicates a
115 * consistency problem with the RMM and we should panic immediately.
116 */
117 assert(!ESR_EL2_SYSREG_IS_WRITE(esr));
118
119 /*
120 * Read Rt value from the issued instruction,
121 * the general-purpose register used for the transfer.
AlexeiFedorovfeaef162022-12-23 16:59:51 +0000122 * Rt bits [9:5] of ISS field cannot exceed 0b11111.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000123 */
124 rt = ESR_EL2_SYSREG_ISS_RT(esr);
125
126 /* Handle writes to XZR register */
127 if (rt == 31U) {
128 return true;
129 }
130
131 idreg = esr & ESR_EL2_SYSREG_MASK;
132
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000133 switch (idreg) {
134 SYSREG_CASE(AFR0)
135 value = SYSREG_READ(AFR0);
136 break;
137 SYSREG_CASE(AFR1)
138 value = SYSREG_READ(AFR1);
139 break;
140 SYSREG_CASE(DFR0)
141 value = SYSREG_READ_CLEAR_SET(DFR0);
142 break;
143 SYSREG_CASE(DFR1)
144 value = SYSREG_READ(DFR1);
145 break;
146 SYSREG_CASE(ISAR0)
147 value = SYSREG_READ(ISAR0);
148 break;
149 SYSREG_CASE(ISAR1)
150 value = SYSREG_READ_CLEAR(ISAR1);
151 break;
152 SYSREG_CASE(MMFR0)
153 value = SYSREG_READ(MMFR0);
154 break;
155 SYSREG_CASE(MMFR1)
156 value = SYSREG_READ(MMFR1);
157 break;
158 SYSREG_CASE(MMFR2)
159 value = SYSREG_READ(MMFR2);
160 break;
161 SYSREG_CASE(PFR0)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000162 /*
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000163 * Workaround for TF-A trapping AMU registers access
164 * to EL3 in Realm state.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000165 */
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000166 value = SYSREG_READ_CLEAR(PFR0);
167 break;
168 SYSREG_CASE(PFR1)
169 value = SYSREG_READ(PFR1);
170 break;
171 /*
172 * TODO: not supported without SVE:
173 * SYSREG_CASE(ZFR0)
174 */
175 default:
176 /* All other encodings are in the RES0 space */
177 value = 0UL;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000178 }
179
AlexeiFedorov7bb7a702023-01-17 17:04:14 +0000180 rec->regs[rt] = value;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000181 return true;
182}
183
184static bool handle_icc_el1_sysreg_trap(struct rec *rec,
185 struct rmi_rec_exit *rec_exit,
186 unsigned long esr)
187{
188 __unused unsigned long sysreg = esr & ESR_EL2_SYSREG_MASK;
189
190 /*
191 * We should only have configured ICH_HCR_EL2 to trap on DIR and we
192 * always trap on the SGIRs following the architecture, so make sure
193 * we're not accidentally trapping on some other register here.
194 */
195 assert((sysreg == ESR_EL2_SYSREG_ICC_DIR) ||
196 (sysreg == ESR_EL2_SYSREG_ICC_SGI1R_EL1) ||
197 (sysreg == ESR_EL2_SYSREG_ICC_SGI0R_EL1));
198
199 /*
200 * The registers above should only trap to EL2 for writes, read
201 * instructions are not defined and should cause an Undefined exception
202 * at EL1.
203 */
204 assert(ESR_EL2_SYSREG_IS_WRITE(esr));
205
206 rec_exit->exit_reason = RMI_EXIT_SYNC;
207 rec_exit->esr = esr;
208 return false;
209}
210
211typedef bool (*sysreg_handler_fn)(struct rec *rec, struct rmi_rec_exit *rec_exit,
212 unsigned long esr);
213
214struct sysreg_handler {
215 unsigned long esr_mask;
216 unsigned long esr_value;
217 sysreg_handler_fn fn;
218};
219
220#define SYSREG_HANDLER(_mask, _value, _handler_fn) \
221 { .esr_mask = (_mask), .esr_value = (_value), .fn = _handler_fn }
222
223static const struct sysreg_handler sysreg_handlers[] = {
224 SYSREG_HANDLER(ESR_EL2_SYSREG_ID_MASK, ESR_EL2_SYSREG_ID, handle_id_sysreg_trap),
225 SYSREG_HANDLER(ESR_EL2_SYSREG_ICC_EL1_MASK, ESR_EL2_SYSREG_ICC_EL1, handle_icc_el1_sysreg_trap),
226 SYSREG_HANDLER(ESR_EL2_SYSREG_MASK, ESR_EL2_SYSREG_ICC_PMR_EL1, handle_icc_el1_sysreg_trap)
227};
228
229static unsigned long get_sysreg_write_value(struct rec *rec, unsigned long esr)
230{
AlexeiFedorovfeaef162022-12-23 16:59:51 +0000231 /* Rt bits [9:5] of ISS field cannot exceed 0b11111 */
232 unsigned int rt = ESR_EL2_SYSREG_ISS_RT(esr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000233
234 /* Handle reads from XZR register */
235 if (rt == 31U) {
236 return 0UL;
237 }
238
AlexeiFedorovfeaef162022-12-23 16:59:51 +0000239 return rec->regs[rt];
Soby Mathewb4c6df42022-11-09 11:13:29 +0000240}
241
242static void emulate_sysreg_access_ns(struct rec *rec, struct rmi_rec_exit *rec_exit,
243 unsigned long esr)
244{
245 if (ESR_EL2_SYSREG_IS_WRITE(esr)) {
246 rec_exit->gprs[0] = get_sysreg_write_value(rec, esr);
247 }
248}
249
250/*
251 * Handle trapped MSR, MRS or System instruction execution
252 * in AArch64 state
253 */
254bool handle_sysreg_access_trap(struct rec *rec, struct rmi_rec_exit *rec_exit,
255 unsigned long esr)
256{
257 /*
258 * Read Rt value from the issued instruction,
259 * the general-purpose register used for the transfer.
AlexeiFedorovfeaef162022-12-23 16:59:51 +0000260 * Rt bits [9:5] of ISS field cannot exceed 0b11111.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000261 */
262 unsigned int rt = ESR_EL2_SYSREG_ISS_RT(esr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000263 unsigned int __unused op0, op1, crn, crm, op2;
264 unsigned long __unused sysreg;
265
266 /* Check for 32-bit instruction trapped */
267 assert(ESR_IL(esr) != 0UL);
268
Shruti Gupta9debb132022-12-13 14:38:49 +0000269 for (unsigned int i = 0U; i < ARRAY_LEN(sysreg_handlers); i++) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000270 const struct sysreg_handler *handler = &sysreg_handlers[i];
Soby Mathewb4c6df42022-11-09 11:13:29 +0000271
272 if ((esr & handler->esr_mask) == handler->esr_value) {
Shruti Gupta9debb132022-12-13 14:38:49 +0000273 bool handled = handler->fn(rec, rec_exit, esr);
274
Soby Mathewb4c6df42022-11-09 11:13:29 +0000275 if (!handled) {
276 emulate_sysreg_access_ns(rec, rec_exit, esr);
277 }
278 return handled;
279 }
280 }
281
282 /*
283 * For now, treat all unhandled accesses as RAZ/WI.
284 * Handle writes to XZR register.
285 */
286 if (!ESR_EL2_SYSREG_IS_WRITE(esr) && (rt != 31U)) {
AlexeiFedorovfeaef162022-12-23 16:59:51 +0000287 rec->regs[rt] = 0UL;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000288 }
289
290 sysreg = esr & ESR_EL2_SYSREG_MASK;
291
292 /* Extract sytem register encoding */
293 op0 = EXTRACT(ESR_EL2_SYSREG_TRAP_OP0, sysreg);
294 op1 = EXTRACT(ESR_EL2_SYSREG_TRAP_OP1, sysreg);
295 crn = EXTRACT(ESR_EL2_SYSREG_TRAP_CRN, sysreg);
296 crm = EXTRACT(ESR_EL2_SYSREG_TRAP_CRM, sysreg);
297 op2 = EXTRACT(ESR_EL2_SYSREG_TRAP_OP2, sysreg);
298
299 INFO("Unhandled %s S%u_%u_C%u_C%u_%u\n",
300 ESR_EL2_SYSREG_IS_WRITE(esr) ? "write" : "read",
301 op0, op1, crn, crm, op2);
302
303 return true;
304}