blob: b2f7a666e3199f68996569fe54c65d0260ce2a0d [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
15#define SYSREG_READ_CASE(reg) \
16 case ESR_EL2_SYSREG_##reg: return read_##reg()
17
18static 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 */
46static 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.
AlexeiFedorovfeaef162022-12-23 16:59:51 +000063 * Rt bits [9:5] of ISS field cannot exceed 0b11111.
Soby Mathewb4c6df42022-11-09 11:13:29 +000064 */
65 rt = ESR_EL2_SYSREG_ISS_RT(esr);
66
67 /* Handle writes to XZR register */
68 if (rt == 31U) {
69 return true;
70 }
71
72 idreg = esr & ESR_EL2_SYSREG_MASK;
73
74 if (idreg == ESR_EL2_SYSREG_ID_AA64ISAR1_EL1) {
75 /* Clear Address and Generic Authentication bits */
76 mask = (0xfUL << ESR_EL2_SYSREG_ID_AA64ISAR1_APA_SHIFT) |
77 (0xfUL << ESR_EL2_SYSREG_ID_AA64ISAR1_API_SHIFT) |
78 (0xfUL << ESR_EL2_SYSREG_ID_AA64ISAR1_GPA_SHIFT) |
79 (0xfUL << ESR_EL2_SYSREG_ID_AA64ISAR1_GPI_SHIFT);
80 /*
81 * Workaround for TF-A trapping AMU registers access
82 * to EL3 in Realm state
83 */
84 } else if (idreg == ESR_EL2_SYSREG_ID_AA64PFR0_EL1) {
85 /* Clear support for Activity Monitors Extension */
86 mask = MASK(ID_AA64PFR0_EL1_AMU);
87
88 /*
89 * Clear support for SVE. This is a temporary fix until RMM
90 * completely supports SVE.
91 */
92 mask |= MASK(ID_AA64PFR0_EL1_SVE);
93 } else {
94 mask = 0UL;
95 }
96
AlexeiFedorovfeaef162022-12-23 16:59:51 +000097 rec->regs[rt] = read_idreg(idreg) & ~mask;
Soby Mathewb4c6df42022-11-09 11:13:29 +000098 return true;
99}
100
101static 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
128typedef bool (*sysreg_handler_fn)(struct rec *rec, struct rmi_rec_exit *rec_exit,
129 unsigned long esr);
130
131struct 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
140static 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
146static unsigned long get_sysreg_write_value(struct rec *rec, unsigned long esr)
147{
AlexeiFedorovfeaef162022-12-23 16:59:51 +0000148 /* Rt bits [9:5] of ISS field cannot exceed 0b11111 */
149 unsigned int rt = ESR_EL2_SYSREG_ISS_RT(esr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000150
151 /* Handle reads from XZR register */
152 if (rt == 31U) {
153 return 0UL;
154 }
155
AlexeiFedorovfeaef162022-12-23 16:59:51 +0000156 return rec->regs[rt];
Soby Mathewb4c6df42022-11-09 11:13:29 +0000157}
158
159static void emulate_sysreg_access_ns(struct rec *rec, struct rmi_rec_exit *rec_exit,
160 unsigned long esr)
161{
162 if (ESR_EL2_SYSREG_IS_WRITE(esr)) {
163 rec_exit->gprs[0] = get_sysreg_write_value(rec, esr);
164 }
165}
166
167/*
168 * Handle trapped MSR, MRS or System instruction execution
169 * in AArch64 state
170 */
171bool handle_sysreg_access_trap(struct rec *rec, struct rmi_rec_exit *rec_exit,
172 unsigned long esr)
173{
174 /*
175 * Read Rt value from the issued instruction,
176 * the general-purpose register used for the transfer.
AlexeiFedorovfeaef162022-12-23 16:59:51 +0000177 * Rt bits [9:5] of ISS field cannot exceed 0b11111.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000178 */
179 unsigned int rt = ESR_EL2_SYSREG_ISS_RT(esr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000180 unsigned int __unused op0, op1, crn, crm, op2;
181 unsigned long __unused sysreg;
182
183 /* Check for 32-bit instruction trapped */
184 assert(ESR_IL(esr) != 0UL);
185
Shruti Gupta9debb132022-12-13 14:38:49 +0000186 for (unsigned int i = 0U; i < ARRAY_LEN(sysreg_handlers); i++) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000187 const struct sysreg_handler *handler = &sysreg_handlers[i];
Soby Mathewb4c6df42022-11-09 11:13:29 +0000188
189 if ((esr & handler->esr_mask) == handler->esr_value) {
Shruti Gupta9debb132022-12-13 14:38:49 +0000190 bool handled = handler->fn(rec, rec_exit, esr);
191
Soby Mathewb4c6df42022-11-09 11:13:29 +0000192 if (!handled) {
193 emulate_sysreg_access_ns(rec, rec_exit, esr);
194 }
195 return handled;
196 }
197 }
198
199 /*
200 * For now, treat all unhandled accesses as RAZ/WI.
201 * Handle writes to XZR register.
202 */
203 if (!ESR_EL2_SYSREG_IS_WRITE(esr) && (rt != 31U)) {
AlexeiFedorovfeaef162022-12-23 16:59:51 +0000204 rec->regs[rt] = 0UL;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000205 }
206
207 sysreg = esr & ESR_EL2_SYSREG_MASK;
208
209 /* Extract sytem register encoding */
210 op0 = EXTRACT(ESR_EL2_SYSREG_TRAP_OP0, sysreg);
211 op1 = EXTRACT(ESR_EL2_SYSREG_TRAP_OP1, sysreg);
212 crn = EXTRACT(ESR_EL2_SYSREG_TRAP_CRN, sysreg);
213 crm = EXTRACT(ESR_EL2_SYSREG_TRAP_CRM, sysreg);
214 op2 = EXTRACT(ESR_EL2_SYSREG_TRAP_OP2, sysreg);
215
216 INFO("Unhandled %s S%u_%u_C%u_C%u_%u\n",
217 ESR_EL2_SYSREG_IS_WRITE(esr) ? "write" : "read",
218 op0, op1, crn, crm, op2);
219
220 return true;
221}