1 /*
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
15 #define SYSREG_READ_CASE(reg) \
16 case ESR_EL2_SYSREG_##reg: return read_##reg()
17
read_idreg(unsigned int idreg)18 static unsigned long read_idreg(unsigned int idreg)
19 {
20 switch (idreg) {
21 SYSREG_READ_CASE(ID_AA64PFR0_EL1);
22 SYSREG_READ_CASE(ID_AA64PFR1_EL1);
23 /*
24 * TODO: not supported without SVE:
25 * SYSREG_READ_CASE(ID_AA64ZFR0_EL1);
26 */
27 SYSREG_READ_CASE(ID_AA64DFR0_EL1);
28 SYSREG_READ_CASE(ID_AA64DFR1_EL1);
29 SYSREG_READ_CASE(ID_AA64AFR0_EL1);
30 SYSREG_READ_CASE(ID_AA64AFR1_EL1);
31 SYSREG_READ_CASE(ID_AA64ISAR0_EL1);
32 SYSREG_READ_CASE(ID_AA64ISAR1_EL1);
33 SYSREG_READ_CASE(ID_AA64MMFR0_EL1);
34 SYSREG_READ_CASE(ID_AA64MMFR1_EL1);
35 SYSREG_READ_CASE(ID_AA64MMFR2_EL1);
36
37 default:
38 /* All other encodings are in the RES0 space */
39 return 0UL;
40 }
41 }
42
43 /*
44 * Handle ID_AA64XXX<n>_EL1 instructions
45 */
handle_id_sysreg_trap(struct rec * rec,struct rmi_rec_exit * rec_exit,unsigned long esr)46 static bool handle_id_sysreg_trap(struct rec *rec,
47 struct rmi_rec_exit *rec_exit,
48 unsigned long esr)
49 {
50 unsigned int rt;
51 unsigned long idreg, mask;
52
53 /*
54 * We only set HCR_EL2.TID3 to trap ID registers at the moment and
55 * that only traps reads of registers. Seeing a write here indicates a
56 * consistency problem with the RMM and we should panic immediately.
57 */
58 assert(!ESR_EL2_SYSREG_IS_WRITE(esr));
59
60 /*
61 * Read Rt value from the issued instruction,
62 * the general-purpose register used for the transfer.
63 */
64 rt = ESR_EL2_SYSREG_ISS_RT(esr);
65
66 /* Handle writes to XZR register */
67 if (rt == 31U) {
68 return true;
69 }
70
71 idreg = esr & ESR_EL2_SYSREG_MASK;
72
73 if (idreg == ESR_EL2_SYSREG_ID_AA64ISAR1_EL1) {
74 /* Clear Address and Generic Authentication bits */
75 mask = (0xfUL << ESR_EL2_SYSREG_ID_AA64ISAR1_APA_SHIFT) |
76 (0xfUL << ESR_EL2_SYSREG_ID_AA64ISAR1_API_SHIFT) |
77 (0xfUL << ESR_EL2_SYSREG_ID_AA64ISAR1_GPA_SHIFT) |
78 (0xfUL << ESR_EL2_SYSREG_ID_AA64ISAR1_GPI_SHIFT);
79 /*
80 * Workaround for TF-A trapping AMU registers access
81 * to EL3 in Realm state
82 */
83 } else if (idreg == ESR_EL2_SYSREG_ID_AA64PFR0_EL1) {
84 /* Clear support for Activity Monitors Extension */
85 mask = MASK(ID_AA64PFR0_EL1_AMU);
86
87 /*
88 * Clear support for SVE. This is a temporary fix until RMM
89 * completely supports SVE.
90 */
91 mask |= MASK(ID_AA64PFR0_EL1_SVE);
92 } else {
93 mask = 0UL;
94 }
95
96 ARRAY_WRITE(rec->regs, rt, read_idreg(idreg) & ~mask);
97
98 return true;
99 }
100
handle_icc_el1_sysreg_trap(struct rec * rec,struct rmi_rec_exit * rec_exit,unsigned long esr)101 static bool handle_icc_el1_sysreg_trap(struct rec *rec,
102 struct rmi_rec_exit *rec_exit,
103 unsigned long esr)
104 {
105 __unused unsigned long sysreg = esr & ESR_EL2_SYSREG_MASK;
106
107 /*
108 * We should only have configured ICH_HCR_EL2 to trap on DIR and we
109 * always trap on the SGIRs following the architecture, so make sure
110 * we're not accidentally trapping on some other register here.
111 */
112 assert((sysreg == ESR_EL2_SYSREG_ICC_DIR) ||
113 (sysreg == ESR_EL2_SYSREG_ICC_SGI1R_EL1) ||
114 (sysreg == ESR_EL2_SYSREG_ICC_SGI0R_EL1));
115
116 /*
117 * The registers above should only trap to EL2 for writes, read
118 * instructions are not defined and should cause an Undefined exception
119 * at EL1.
120 */
121 assert(ESR_EL2_SYSREG_IS_WRITE(esr));
122
123 rec_exit->exit_reason = RMI_EXIT_SYNC;
124 rec_exit->esr = esr;
125 return false;
126 }
127
128 typedef bool (*sysreg_handler_fn)(struct rec *rec, struct rmi_rec_exit *rec_exit,
129 unsigned long esr);
130
131 struct sysreg_handler {
132 unsigned long esr_mask;
133 unsigned long esr_value;
134 sysreg_handler_fn fn;
135 };
136
137 #define SYSREG_HANDLER(_mask, _value, _handler_fn) \
138 { .esr_mask = (_mask), .esr_value = (_value), .fn = _handler_fn }
139
140 static const struct sysreg_handler sysreg_handlers[] = {
141 SYSREG_HANDLER(ESR_EL2_SYSREG_ID_MASK, ESR_EL2_SYSREG_ID, handle_id_sysreg_trap),
142 SYSREG_HANDLER(ESR_EL2_SYSREG_ICC_EL1_MASK, ESR_EL2_SYSREG_ICC_EL1, handle_icc_el1_sysreg_trap),
143 SYSREG_HANDLER(ESR_EL2_SYSREG_MASK, ESR_EL2_SYSREG_ICC_PMR_EL1, handle_icc_el1_sysreg_trap)
144 };
145
get_sysreg_write_value(struct rec * rec,unsigned long esr)146 static unsigned long get_sysreg_write_value(struct rec *rec, unsigned long esr)
147 {
148 unsigned int rt = esr_sysreg_rt(esr);
149 unsigned long val;
150
151 /* Handle reads from XZR register */
152 if (rt == 31U) {
153 return 0UL;
154 }
155
156 ARRAY_READ(rec->regs, rt, val);
157 return val;
158 }
159
emulate_sysreg_access_ns(struct rec * rec,struct rmi_rec_exit * rec_exit,unsigned long esr)160 static void emulate_sysreg_access_ns(struct rec *rec, struct rmi_rec_exit *rec_exit,
161 unsigned long esr)
162 {
163 if (ESR_EL2_SYSREG_IS_WRITE(esr)) {
164 rec_exit->gprs[0] = get_sysreg_write_value(rec, esr);
165 }
166 }
167
168 /*
169 * Handle trapped MSR, MRS or System instruction execution
170 * in AArch64 state
171 */
handle_sysreg_access_trap(struct rec * rec,struct rmi_rec_exit * rec_exit,unsigned long esr)172 bool handle_sysreg_access_trap(struct rec *rec, struct rmi_rec_exit *rec_exit,
173 unsigned long esr)
174 {
175 /*
176 * Read Rt value from the issued instruction,
177 * the general-purpose register used for the transfer.
178 */
179 unsigned int rt = ESR_EL2_SYSREG_ISS_RT(esr);
180 unsigned int i;
181 unsigned int __unused op0, op1, crn, crm, op2;
182 unsigned long __unused sysreg;
183
184 /* Check for 32-bit instruction trapped */
185 assert(ESR_IL(esr) != 0UL);
186
187 for (i = 0U; i < ARRAY_LEN(sysreg_handlers); i++) {
188 const struct sysreg_handler *handler = &sysreg_handlers[i];
189 bool handled;
190
191 if ((esr & handler->esr_mask) == handler->esr_value) {
192 handled = handler->fn(rec, rec_exit, esr);
193 if (!handled) {
194 emulate_sysreg_access_ns(rec, rec_exit, esr);
195 }
196 return handled;
197 }
198 }
199
200 /*
201 * For now, treat all unhandled accesses as RAZ/WI.
202 * Handle writes to XZR register.
203 */
204 if (!ESR_EL2_SYSREG_IS_WRITE(esr) && (rt != 31U)) {
205 ARRAY_WRITE(rec->regs, rt, 0UL);
206 }
207
208 sysreg = esr & ESR_EL2_SYSREG_MASK;
209
210 /* Extract sytem register encoding */
211 op0 = EXTRACT(ESR_EL2_SYSREG_TRAP_OP0, sysreg);
212 op1 = EXTRACT(ESR_EL2_SYSREG_TRAP_OP1, sysreg);
213 crn = EXTRACT(ESR_EL2_SYSREG_TRAP_CRN, sysreg);
214 crm = EXTRACT(ESR_EL2_SYSREG_TRAP_CRM, sysreg);
215 op2 = EXTRACT(ESR_EL2_SYSREG_TRAP_OP2, sysreg);
216
217 INFO("Unhandled %s S%u_%u_C%u_C%u_%u\n",
218 ESR_EL2_SYSREG_IS_WRITE(esr) ? "write" : "read",
219 op0, op1, crn, crm, op2);
220
221 return true;
222 }
223