target/hexagon: Implement software interrupt
Co-authored-by: Mike Lambert <mlambert@quicinc.com> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
Brian Cain committed
Jun 22, 2026 at 15:28 UTC
a998dcc69e6ead002cb6b700acf453ec33553351
3 files changed
+289
target/hexagon/cpu.c
+1
@@ -34,6 +34,7 @@
34
#include "sys_macros.h"
35
#include "accel/tcg/cpu-ldst.h"
36
#include "qemu/main-loop.h"
37
+#include "hex_interrupts.h"
38
#endif
39
40
static ObjectClass *hexagon_cpu_class_by_name(const char *cpu_model)
target/hexagon/hexswi.c
new
+271
@@ -0,0 +1,271 @@
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
+}
target/hexagon/hexswi.h
new
+17
@@ -0,0 +1,17 @@
1
+/*
2
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
3
+ *
4
+ * SPDX-License-Identifier: GPL-2.0-or-later
5
+ */
6
+
7
+#ifndef HEXSWI_H
8
+#define HEXSWI_H
9
+
10
+
11
+#include "cpu.h"
12
+
13
+void hexagon_cpu_do_interrupt(CPUState *cpu);
14
+void register_trap_exception(CPUHexagonState *env, int type, int imm,
15
+ uint32_t PC);
16
+
17
+#endif /* HEXSWI_H */