master
c 271 lines 9.34 KB
Raw
1 /*
2 * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include "qemu/osdep.h"
8 #include "cpu.h"
9 #include "cpu_helper.h"
10 #include "exec/helper-proto.h"
11 #include "qemu/log.h"
12 #include "qemu/main-loop.h"
13 #include "arch.h"
14 #include "internal.h"
15 #include "macros.h"
16 #include "sys_macros.h"
17 #include "accel/tcg/cpu-loop.h"
18 #include "tcg/tcg-op.h"
19 #include "hex_mmu.h"
20 #include "hexswi.h"
21 #include "hw/hexagon/hexagon_globalreg.h"
22
23 #ifdef CONFIG_USER_ONLY
24 #error "This file is only used in system emulation"
25 #endif
26
27 static void set_addresses(CPUHexagonState *env, uint32_t pc_offset,
28 uint32_t exception_index)
29
30 {
31 HexagonCPU *cpu = env_archcpu(env);
32 uint32_t evb = cpu->globalregs ?
33 hexagon_globalreg_read(cpu->globalregs, HEX_SREG_EVB,
34 env->threadId) :
35 cpu->boot_addr;
36 env->t_sreg[HEX_SREG_ELR] = env->gpr[HEX_REG_PC] + pc_offset;
37 env->gpr[HEX_REG_PC] = evb | (exception_index << 2);
38 }
39
40 static const char *event_name[] = {
41 [HEX_EVENT_RESET] = "HEX_EVENT_RESET",
42 [HEX_EVENT_IMPRECISE] = "HEX_EVENT_IMPRECISE",
43 [HEX_EVENT_PRECISE] = "HEX_EVENT_PRECISE",
44 [HEX_EVENT_TLB_MISS_X] = "HEX_EVENT_TLB_MISS_X",
45 [HEX_EVENT_TLB_MISS_RW] = "HEX_EVENT_TLB_MISS_RW",
46 [HEX_EVENT_TRAP0] = "HEX_EVENT_TRAP0",
47 [HEX_EVENT_TRAP1] = "HEX_EVENT_TRAP1",
48 [HEX_EVENT_FPTRAP] = "HEX_EVENT_FPTRAP",
49 [HEX_EVENT_DEBUG] = "HEX_EVENT_DEBUG",
50 [HEX_EVENT_INT0] = "HEX_EVENT_INT0",
51 [HEX_EVENT_INT1] = "HEX_EVENT_INT1",
52 [HEX_EVENT_INT2] = "HEX_EVENT_INT2",
53 [HEX_EVENT_INT3] = "HEX_EVENT_INT3",
54 [HEX_EVENT_INT4] = "HEX_EVENT_INT4",
55 [HEX_EVENT_INT5] = "HEX_EVENT_INT5",
56 [HEX_EVENT_INT6] = "HEX_EVENT_INT6",
57 [HEX_EVENT_INT7] = "HEX_EVENT_INT7",
58 [HEX_EVENT_INT8] = "HEX_EVENT_INT8",
59 [HEX_EVENT_INT9] = "HEX_EVENT_INT9",
60 [HEX_EVENT_INTA] = "HEX_EVENT_INTA",
61 [HEX_EVENT_INTB] = "HEX_EVENT_INTB",
62 [HEX_EVENT_INTC] = "HEX_EVENT_INTC",
63 [HEX_EVENT_INTD] = "HEX_EVENT_INTD",
64 [HEX_EVENT_INTE] = "HEX_EVENT_INTE",
65 [HEX_EVENT_INTF] = "HEX_EVENT_INTF"
66 };
67
68 void hexagon_cpu_do_interrupt(CPUState *cs)
69
70 {
71 CPUHexagonState *env = cpu_env(cs);
72 uint32_t ssr;
73
74 BQL_LOCK_GUARD();
75
76 qemu_log_mask(CPU_LOG_INT,
77 "\t%s: event 0x%02x:%s, cause 0x%" PRIx32 "(%" PRIu32 ")\n",
78 __func__, (unsigned)cs->exception_index,
79 event_name[cs->exception_index], env->cause_code,
80 env->cause_code);
81
82 env->llsc_addr = ~0;
83
84 ssr = env->t_sreg[HEX_SREG_SSR];
85 if (GET_SSR_FIELD(SSR_EX, ssr) == 1) {
86 HexagonCPU *cpu = env_archcpu(env);
87 if (cpu->globalregs) {
88 hexagon_globalreg_write(cpu->globalregs, HEX_SREG_DIAG,
89 env->cause_code, env->threadId);
90 }
91 env->cause_code = HEX_CAUSE_DOUBLE_EXCEPT;
92 cs->exception_index = HEX_EVENT_PRECISE;
93 }
94
95 switch (cs->exception_index) {
96 case HEX_EVENT_TRAP0:
97 if (env->cause_code == 0) {
98 qemu_log_mask(LOG_UNIMP,
99 "trap0 is unhandled, no semihosting available\n");
100 }
101
102 hexagon_ssr_set_cause(env, env->cause_code);
103 set_addresses(env, 4, cs->exception_index);
104 break;
105
106 case HEX_EVENT_TRAP1:
107 hexagon_ssr_set_cause(env, env->cause_code);
108 set_addresses(env, 4, cs->exception_index);
109 break;
110
111 case HEX_EVENT_TLB_MISS_X:
112 switch (env->cause_code) {
113 case HEX_CAUSE_TLBMISSX_CAUSE_NORMAL:
114 case HEX_CAUSE_TLBMISSX_CAUSE_NEXTPAGE:
115 qemu_log_mask(CPU_LOG_MMU,
116 "TLB miss EX exception (0x%02" PRIx32 ") caught: "
117 "Cause code (0x%" PRIx32 ") "
118 "TID = 0x%" PRIx32 ", PC = 0x%" PRIx32
119 ", BADVA = 0x%" PRIx32 "\n",
120 (uint32_t)cs->exception_index,
121 env->cause_code, env->threadId,
122 env->gpr[HEX_REG_PC],
123 env->t_sreg[HEX_SREG_BADVA]);
124
125 hexagon_ssr_set_cause(env, env->cause_code);
126 set_addresses(env, 0, cs->exception_index);
127 break;
128
129 default:
130 cpu_abort(cs,
131 "1:Hexagon exception %" PRId32 "/0x%02" PRIx32 ": "
132 "Unknown cause code %" PRIu32 "/0x%" PRIx32 "\n",
133 (uint32_t)cs->exception_index,
134 (uint32_t)cs->exception_index,
135 env->cause_code,
136 env->cause_code);
137 break;
138 }
139 break;
140
141 case HEX_EVENT_TLB_MISS_RW:
142 switch (env->cause_code) {
143 case HEX_CAUSE_TLBMISSRW_CAUSE_READ:
144 case HEX_CAUSE_TLBMISSRW_CAUSE_WRITE:
145 qemu_log_mask(CPU_LOG_MMU,
146 "TLB miss RW exception (0x%02" PRIx32 ") caught: "
147 "Cause code (0x%" PRIx32 ") "
148 "TID = 0x%" PRIx32 ", PC = 0x%" PRIx32
149 ", BADVA = 0x%" PRIx32 "\n",
150 (uint32_t)cs->exception_index,
151 env->cause_code, env->threadId,
152 env->gpr[HEX_REG_PC],
153 env->t_sreg[HEX_SREG_BADVA]);
154
155 hexagon_ssr_set_cause(env, env->cause_code);
156 set_addresses(env, 0, cs->exception_index);
157 /* env->sreg[HEX_SREG_BADVA] is set when the exception is raised */
158 break;
159
160 default:
161 cpu_abort(cs,
162 "2:Hexagon exception %" PRId32 "/0x%02" PRIx32 ": "
163 "Unknown cause code %" PRIu32 "/0x%" PRIx32 "\n",
164 (uint32_t)cs->exception_index,
165 (uint32_t)cs->exception_index,
166 env->cause_code,
167 env->cause_code);
168 break;
169 }
170 break;
171
172 case HEX_EVENT_FPTRAP:
173 hexagon_ssr_set_cause(env, env->cause_code);
174 set_addresses(env, 0, cs->exception_index);
175 break;
176
177 case HEX_EVENT_DEBUG:
178 hexagon_ssr_set_cause(env, env->cause_code);
179 set_addresses(env, 0, cs->exception_index);
180 qemu_log_mask(LOG_UNIMP, "single-step exception is not handled\n");
181 break;
182
183 case HEX_EVENT_PRECISE:
184 switch (env->cause_code) {
185 case HEX_CAUSE_FETCH_NO_XPAGE:
186 case HEX_CAUSE_FETCH_NO_UPAGE:
187 case HEX_CAUSE_PRIV_NO_READ:
188 case HEX_CAUSE_PRIV_NO_UREAD:
189 case HEX_CAUSE_PRIV_NO_WRITE:
190 case HEX_CAUSE_PRIV_NO_UWRITE:
191 case HEX_CAUSE_MISALIGNED_LOAD:
192 case HEX_CAUSE_MISALIGNED_STORE:
193 case HEX_CAUSE_PC_NOT_ALIGNED:
194 qemu_log_mask(CPU_LOG_MMU,
195 "MMU permission exception (0x%02" PRIx32 ") caught: "
196 "Cause code (0x%" PRIx32 ") "
197 "TID = 0x%" PRIx32 ", PC = 0x%" PRIx32
198 ", BADVA = 0x%" PRIx32 "\n",
199 (uint32_t)cs->exception_index,
200 env->cause_code, env->threadId,
201 env->gpr[HEX_REG_PC],
202 env->t_sreg[HEX_SREG_BADVA]);
203
204
205 hexagon_ssr_set_cause(env, env->cause_code);
206 set_addresses(env, 0, cs->exception_index);
207 /* env->sreg[HEX_SREG_BADVA] is set when the exception is raised */
208 break;
209
210 case HEX_CAUSE_DOUBLE_EXCEPT:
211 case HEX_CAUSE_PRIV_USER_NO_SINSN:
212 case HEX_CAUSE_PRIV_USER_NO_GINSN:
213 case HEX_CAUSE_INVALID_OPCODE:
214 case HEX_CAUSE_NO_COPROC_ENABLE:
215 case HEX_CAUSE_NO_COPROC2_ENABLE:
216 case HEX_CAUSE_UNSUPPORTED_HVX_64B:
217 case HEX_CAUSE_REG_WRITE_CONFLICT:
218 case HEX_CAUSE_VWCTRL_WINDOW_MISS:
219 hexagon_ssr_set_cause(env, env->cause_code);
220 set_addresses(env, 0, cs->exception_index);
221 break;
222
223 case HEX_CAUSE_COPROC_LDST:
224 hexagon_ssr_set_cause(env, env->cause_code);
225 set_addresses(env, 0, cs->exception_index);
226 break;
227
228 case HEX_CAUSE_STACK_LIMIT:
229 hexagon_ssr_set_cause(env, env->cause_code);
230 set_addresses(env, 0, cs->exception_index);
231 break;
232
233 default:
234 cpu_abort(cs,
235 "3:Hexagon exception %" PRId32 "/0x%02" PRIx32 ": "
236 "Unknown cause code %" PRIu32 "/0x%" PRIx32 "\n",
237 (uint32_t)cs->exception_index,
238 (uint32_t)cs->exception_index,
239 env->cause_code,
240 env->cause_code);
241 break;
242 }
243 break;
244
245 case HEX_EVENT_IMPRECISE:
246 qemu_log_mask(LOG_UNIMP,
247 "Imprecise exception: this case is not yet handled");
248 break;
249
250 default:
251 qemu_log_mask(LOG_UNIMP,
252 "Hexagon Unsupported exception 0x%02x/0x%" PRIx32 "\n",
253 (unsigned)cs->exception_index, env->cause_code);
254 break;
255 }
256
257 cs->exception_index = HEX_EVENT_NONE;
258 }
259
260 void register_trap_exception(CPUHexagonState *env, int traptype, int imm,
261 uint32_t PC)
262 {
263 CPUState *cs = env_cpu(env);
264
265 cs->exception_index = (traptype == 0) ? HEX_EVENT_TRAP0 : HEX_EVENT_TRAP1;
266 ASSERT_DIRECT_TO_GUEST_UNSET(env, cs->exception_index);
267
268 env->cause_code = imm;
269 env->gpr[HEX_REG_PC] = PC;
270 cpu_loop_exit(cs);
271 }