@samitouri / QOSamiQemu / commits / 9b63a54dd2

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)