target/hexagon: Add sreg_{read,write} helpers
Co-authored-by: Sid Manning <sidneym@quicinc.com> Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
Brian Cain committed
Jun 22, 2026 at 15:28 UTC
9b63a54dd2c0ea9a667c9e9dc662755b9feffa7e
3 files changed
+384
-4
target/hexagon/cpu.c
-1
@@ -334,7 +334,6 @@ static void hexagon_cpu_realize(DeviceState *dev, Error **errp)
334
335
qemu_init_vcpu(cs);
336
cpu_reset(cs);
337
-
337
mcc->parent_realize(dev, errp);
338
}
339
target/hexagon/cpu_helper.c
new
+354
@@ -0,0 +1,354 @@
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 "system/cpus.h"
11
+#include "hw/core/boards.h"
12
+#include "hw/hexagon/hexagon.h"
13
+#include "hw/hexagon/hexagon_globalreg.h"
14
+#include "hex_interrupts.h"
15
+#include "hex_mmu.h"
16
+#include "system/runstate.h"
17
+#include "exec/cpu-interrupt.h"
18
+#include "exec/target_page.h"
19
+#include "accel/tcg/cpu-ldst.h"
20
+#include "exec/cputlb.h"
21
+#include "qemu/log.h"
22
+#include "tcg/tcg-op.h"
23
+#include "internal.h"
24
+#include "macros.h"
25
+#include "sys_macros.h"
26
+#include "arch.h"
27
+
28
+
29
+uint32_t hexagon_get_pmu_counter(CPUHexagonState *cur_env, int index)
30
+{
31
+ g_assert_not_reached();
32
+}
33
+
34
+uint64_t hexagon_get_sys_pcycle_count(CPUHexagonState *env)
35
+{
36
+ g_assert_not_reached();
37
+}
38
+
39
+uint32_t hexagon_get_sys_pcycle_count_high(CPUHexagonState *env)
40
+{
41
+ g_assert_not_reached();
42
+}
43
+
44
+uint32_t hexagon_get_sys_pcycle_count_low(CPUHexagonState *env)
45
+{
46
+ g_assert_not_reached();
47
+}
48
+
49
+void hexagon_set_sys_pcycle_count_high(CPUHexagonState *env, uint32_t val)
50
+{
51
+ g_assert_not_reached();
52
+}
53
+
54
+void hexagon_set_sys_pcycle_count_low(CPUHexagonState *env, uint32_t val)
55
+{
56
+ g_assert_not_reached();
57
+}
58
+
59
+void hexagon_set_sys_pcycle_count(CPUHexagonState *env, uint64_t val)
60
+{
61
+ g_assert_not_reached();
62
+}
63
+
64
+static void hexagon_resume_thread(CPUHexagonState *env)
65
+{
66
+ CPUState *cs = env_cpu(env);
67
+ clear_wait_mode(env);
68
+ /*
69
+ * The wait instruction keeps the PC pointing to itself
70
+ * so that it has an opportunity to check for interrupts.
71
+ *
72
+ * When we come out of wait mode, adjust the PC to the
73
+ * next executable instruction.
74
+ */
75
+ env->gpr[HEX_REG_PC] = env->wait_next_pc;
76
+ cs = env_cpu(env);
77
+ ASSERT_DIRECT_TO_GUEST_UNSET(env, cs->exception_index);
78
+ cs->halted = false;
79
+ cs->exception_index = HEX_EVENT_NONE;
80
+ qemu_cpu_kick(cs);
81
+}
82
+
83
+void hexagon_resume_threads(CPUHexagonState *current_env, uint32_t mask)
84
+{
85
+ CPUState *cs;
86
+ CPUHexagonState *env;
87
+
88
+ g_assert(bql_locked());
89
+ CPU_FOREACH(cs) {
90
+ env = cpu_env(cs);
91
+ g_assert(env->threadId < THREADS_MAX);
92
+ if ((mask & (0x1 << env->threadId))) {
93
+ if (get_exe_mode(env) == HEX_EXE_MODE_WAIT) {
94
+ hexagon_resume_thread(env);
95
+ }
96
+ }
97
+ }
98
+}
99
+
100
+void hexagon_modify_ssr(CPUHexagonState *env, uint32_t new, uint32_t old)
101
+{
102
+ bool old_EX, old_UM, old_GM, old_IE;
103
+ bool new_EX, new_UM, new_GM, new_IE;
104
+ uint8_t old_asid, new_asid;
105
+
106
+ g_assert(bql_locked());
107
+
108
+ old_EX = GET_SSR_FIELD(SSR_EX, old);
109
+ old_UM = GET_SSR_FIELD(SSR_UM, old);
110
+ old_GM = GET_SSR_FIELD(SSR_GM, old);
111
+ old_IE = GET_SSR_FIELD(SSR_IE, old);
112
+ new_EX = GET_SSR_FIELD(SSR_EX, new);
113
+ new_UM = GET_SSR_FIELD(SSR_UM, new);
114
+ new_GM = GET_SSR_FIELD(SSR_GM, new);
115
+ new_IE = GET_SSR_FIELD(SSR_IE, new);
116
+
117
+ if ((old_EX != new_EX) ||
118
+ (old_UM != new_UM) ||
119
+ (old_GM != new_GM)) {
120
+ hex_mmu_mode_change(env);
121
+ }
122
+
123
+ old_asid = GET_SSR_FIELD(SSR_ASID, old);
124
+ new_asid = GET_SSR_FIELD(SSR_ASID, new);
125
+ if (new_asid != old_asid) {
126
+ CPUState *cs = env_cpu(env);
127
+ tlb_flush(cs);
128
+ }
129
+
130
+ /* See if the interrupts have been enabled or we have exited EX mode */
131
+ if ((new_IE && !old_IE) ||
132
+ (!new_EX && old_EX)) {
133
+ hex_interrupt_update(env);
134
+ }
135
+}
136
+
137
+void clear_wait_mode(CPUHexagonState *env)
138
+{
139
+ HexagonCPU *cpu;
140
+ uint32_t modectl, thread_wait_mask;
141
+
142
+ g_assert(bql_locked());
143
+
144
+ cpu = env_archcpu(env);
145
+ if (cpu->globalregs) {
146
+ modectl =
147
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_MODECTL,
148
+ env->threadId);
149
+ thread_wait_mask = GET_FIELD(MODECTL_W, modectl);
150
+ thread_wait_mask &= ~(0x1 << env->threadId);
151
+ SET_SYSTEM_FIELD(env, HEX_SREG_MODECTL, MODECTL_W, thread_wait_mask);
152
+ }
153
+}
154
+
155
+void hexagon_ssr_set_cause(CPUHexagonState *env, uint32_t cause)
156
+{
157
+ uint32_t old, new;
158
+
159
+ g_assert(bql_locked());
160
+
161
+ old = env->t_sreg[HEX_SREG_SSR];
162
+ SET_SYSTEM_FIELD(env, HEX_SREG_SSR, SSR_EX, 1);
163
+ SET_SYSTEM_FIELD(env, HEX_SREG_SSR, SSR_CAUSE, cause);
164
+ new = env->t_sreg[HEX_SREG_SSR];
165
+
166
+ hexagon_modify_ssr(env, new, old);
167
+}
168
+
169
+
170
+int get_exe_mode(CPUHexagonState *env)
171
+{
172
+ HexagonCPU *cpu;
173
+ uint32_t modectl, thread_enabled_mask, thread_wait_mask;
174
+ uint32_t isdbst, debugmode;
175
+ bool E_bit, W_bit, D_bit;
176
+
177
+ g_assert(bql_locked());
178
+
179
+ cpu = env_archcpu(env);
180
+ modectl = cpu->globalregs ?
181
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_MODECTL,
182
+ env->threadId) : 0;
183
+ thread_enabled_mask = GET_FIELD(MODECTL_E, modectl);
184
+ E_bit = thread_enabled_mask & (0x1 << env->threadId);
185
+ thread_wait_mask = GET_FIELD(MODECTL_W, modectl);
186
+ W_bit = thread_wait_mask & (0x1 << env->threadId);
187
+ isdbst = cpu->globalregs ?
188
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_ISDBST,
189
+ env->threadId) : 0;
190
+ debugmode = GET_FIELD(ISDBST_DEBUGMODE, isdbst);
191
+ D_bit = debugmode & (0x1 << env->threadId);
192
+
193
+ if (!D_bit && !W_bit && !E_bit) {
194
+ return HEX_EXE_MODE_OFF;
195
+ }
196
+ if (!D_bit && !W_bit && E_bit) {
197
+ return HEX_EXE_MODE_RUN;
198
+ }
199
+ if (!D_bit && W_bit && E_bit) {
200
+ return HEX_EXE_MODE_WAIT;
201
+ }
202
+ if (D_bit && !W_bit && E_bit) {
203
+ return HEX_EXE_MODE_DEBUG;
204
+ }
205
+ g_assert_not_reached();
206
+}
207
+
208
+static uint32_t set_enable_mask(CPUHexagonState *env)
209
+{
210
+ HexagonCPU *cpu;
211
+ uint32_t modectl, thread_enabled_mask;
212
+
213
+ g_assert(bql_locked());
214
+
215
+ cpu = env_archcpu(env);
216
+ if (!cpu->globalregs) {
217
+ return 0;
218
+ }
219
+ modectl =
220
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_MODECTL,
221
+ env->threadId);
222
+ thread_enabled_mask = GET_FIELD(MODECTL_E, modectl);
223
+ thread_enabled_mask |= 0x1 << env->threadId;
224
+ SET_SYSTEM_FIELD(env, HEX_SREG_MODECTL, MODECTL_E, thread_enabled_mask);
225
+ return thread_enabled_mask;
226
+}
227
+
228
+static uint32_t clear_enable_mask(CPUHexagonState *env)
229
+{
230
+ HexagonCPU *cpu;
231
+ uint32_t modectl, thread_enabled_mask;
232
+
233
+ g_assert(bql_locked());
234
+
235
+ cpu = env_archcpu(env);
236
+ if (!cpu->globalregs) {
237
+ return 0;
238
+ }
239
+ modectl =
240
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_MODECTL,
241
+ env->threadId);
242
+ thread_enabled_mask = GET_FIELD(MODECTL_E, modectl);
243
+ thread_enabled_mask &= ~(0x1 << env->threadId);
244
+ SET_SYSTEM_FIELD(env, HEX_SREG_MODECTL, MODECTL_E, thread_enabled_mask);
245
+ return thread_enabled_mask;
246
+}
247
+static void do_start_thread(CPUState *cs, run_on_cpu_data tbd)
248
+{
249
+ CPUHexagonState *env;
250
+
251
+ BQL_LOCK_GUARD();
252
+
253
+ env = cpu_env(cs);
254
+
255
+ hexagon_cpu_soft_reset(env);
256
+
257
+ set_enable_mask(env);
258
+
259
+ cs->halted = 0;
260
+ cs->exception_index = HEX_EVENT_NONE;
261
+ cpu_resume(cs);
262
+}
263
+
264
+void hexagon_start_threads(CPUHexagonState *current_env, uint32_t mask)
265
+{
266
+ CPUState *cs;
267
+ CPU_FOREACH(cs) {
268
+ CPUHexagonState *env = cpu_env(cs);
269
+ if (!(mask & (0x1 << env->threadId))) {
270
+ continue;
271
+ }
272
+
273
+ if (current_env->threadId != env->threadId) {
274
+ async_safe_run_on_cpu(cs, do_start_thread, RUN_ON_CPU_NULL);
275
+ }
276
+ }
277
+}
278
+
279
+/*
280
+ * When we have all threads stopped, the return
281
+ * value to the shell is register 2 from thread 0.
282
+ */
283
+static uint32_t get_thread0_r2(void)
284
+{
285
+ CPUState *cs;
286
+ CPU_FOREACH(cs) {
287
+ CPUHexagonState *thread = cpu_env(cs);
288
+ if (thread->threadId == 0) {
289
+ return thread->gpr[2];
290
+ }
291
+ }
292
+ g_assert_not_reached();
293
+}
294
+
295
+void hexagon_stop_thread(CPUHexagonState *env)
296
+{
297
+ uint32_t thread_enabled_mask;
298
+ CPUState *cs;
299
+
300
+ BQL_LOCK_GUARD();
301
+
302
+ thread_enabled_mask = clear_enable_mask(env);
303
+ cs = env_cpu(env);
304
+ cpu_interrupt(cs, CPU_INTERRUPT_HALT);
305
+ if (!thread_enabled_mask) {
306
+ /* All threads are stopped, request shutdown */
307
+ qemu_system_shutdown_request_with_code(
308
+ SHUTDOWN_CAUSE_GUEST_SHUTDOWN, get_thread0_r2());
309
+ }
310
+}
311
+
312
+static int sys_in_monitor_mode_ssr(uint32_t ssr)
313
+{
314
+ if ((GET_SSR_FIELD(SSR_EX, ssr) != 0) ||
315
+ ((GET_SSR_FIELD(SSR_EX, ssr) == 0) &&
316
+ (GET_SSR_FIELD(SSR_UM, ssr) == 0))) {
317
+ return 1;
318
+ }
319
+ return 0;
320
+}
321
+
322
+static int sys_in_guest_mode_ssr(uint32_t ssr)
323
+{
324
+ if ((GET_SSR_FIELD(SSR_EX, ssr) == 0) &&
325
+ (GET_SSR_FIELD(SSR_UM, ssr) != 0) &&
326
+ (GET_SSR_FIELD(SSR_GM, ssr) != 0)) {
327
+ return 1;
328
+ }
329
+ return 0;
330
+}
331
+
332
+static int sys_in_user_mode_ssr(uint32_t ssr)
333
+{
334
+ if ((GET_SSR_FIELD(SSR_EX, ssr) == 0) &&
335
+ (GET_SSR_FIELD(SSR_UM, ssr) != 0) &&
336
+ (GET_SSR_FIELD(SSR_GM, ssr) == 0)) {
337
+ return 1;
338
+ }
339
+ return 0;
340
+}
341
+
342
+int get_cpu_mode(CPUHexagonState *env)
343
+{
344
+ uint32_t ssr = env->t_sreg[HEX_SREG_SSR];
345
+
346
+ if (sys_in_monitor_mode_ssr(ssr)) {
347
+ return HEX_CPU_MODE_MONITOR;
348
+ } else if (sys_in_guest_mode_ssr(ssr)) {
349
+ return HEX_CPU_MODE_GUEST;
350
+ } else if (sys_in_user_mode_ssr(ssr)) {
351
+ return HEX_CPU_MODE_USER;
352
+ }
353
+ return HEX_CPU_MODE_MONITOR;
354
+}
target/hexagon/op_helper.c
+30
-3
@@ -20,6 +20,7 @@
20
#include "accel/tcg/cpu-ldst.h"
21
#include "accel/tcg/cpu-loop.h"
22
#include "accel/tcg/probe.h"
23
+#include "qemu/main-loop.h"
24
#include "cpu.h"
25
#include "exec/helper-proto.h"
26
#include "fpu/softfloat.h"
@@ -1452,17 +1453,43 @@ void HELPER(setimask)(CPUHexagonState *env, uint32_t tid, uint32_t imask)
1453
1454
void HELPER(sreg_write_masked)(CPUHexagonState *env, uint32_t reg, uint32_t val)
1455
{
1455
- g_assert_not_reached();
1456
+ BQL_LOCK_GUARD();
1457
+ if (reg < HEX_SREG_GLB_START) {
1458
+ env->t_sreg[reg] = val;
1459
+ } else {
1460
+ HexagonCPU *cpu = env_archcpu(env);
1461
+ if (cpu->globalregs) {
1462
+ hexagon_globalreg_write_masked(cpu->globalregs, reg, val);
1463
+ }
1464
+ }
1465
+}
1466
+
1467
+static inline QEMU_ALWAYS_INLINE uint32_t sreg_read(CPUHexagonState *env,
1468
+ uint32_t reg)
1469
+{
1470
+ HexagonCPU *cpu;
1471
+
1472
+ g_assert(bql_locked());
1473
+ if (reg < HEX_SREG_GLB_START) {
1474
+ return env->t_sreg[reg];
1475
+ }
1476
+ cpu = env_archcpu(env);
1477
+ return cpu->globalregs ?
1478
+ hexagon_globalreg_read(cpu->globalregs, reg, env->threadId) : 0;
1479
}
1480
1481
uint32_t HELPER(sreg_read)(CPUHexagonState *env, uint32_t reg)
1482
{
1460
- g_assert_not_reached();
1483
+ BQL_LOCK_GUARD();
1484
+ return sreg_read(env, reg);
1485
}
1486
1487
uint64_t HELPER(sreg_read_pair)(CPUHexagonState *env, uint32_t reg)
1488
{
1465
- g_assert_not_reached();
1489
+ BQL_LOCK_GUARD();
1490
+
1491
+ return deposit64((uint64_t) sreg_read(env, reg), 32, 32,
1492
+ sreg_read(env, reg + 1));
1493
}
1494
1495
uint32_t HELPER(greg_read)(CPUHexagonState *env, uint32_t reg)