master
c 399 lines 10.1 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 "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 uint64_t total = 0;
37 CPUState *cs;
38
39 g_assert(bql_locked());
40 CPU_FOREACH(cs) {
41 CPUHexagonState *thread_env = cpu_env(cs);
42 total += thread_env->t_cycle_count;
43 }
44 return total;
45 }
46
47 uint32_t hexagon_get_sys_pcycle_count_high(CPUHexagonState *env)
48 {
49 return (uint32_t)(hexagon_get_sys_pcycle_count(env) >> 32);
50 }
51
52 uint32_t hexagon_get_sys_pcycle_count_low(CPUHexagonState *env)
53 {
54 return (uint32_t)(hexagon_get_sys_pcycle_count(env));
55 }
56
57 void hexagon_set_sys_pcycle_count_high(CPUHexagonState *env, uint32_t val)
58 {
59 uint64_t old;
60
61 g_assert(bql_locked());
62 old = hexagon_get_sys_pcycle_count(env);
63 old = deposit64(old, 32, 32, val);
64 hexagon_set_sys_pcycle_count(env, old);
65 }
66
67 void hexagon_set_sys_pcycle_count_low(CPUHexagonState *env, uint32_t val)
68 {
69 uint64_t old;
70
71 g_assert(bql_locked());
72 old = hexagon_get_sys_pcycle_count(env);
73 old = deposit64(old, 0, 32, val);
74 hexagon_set_sys_pcycle_count(env, old);
75 }
76
77 void hexagon_set_sys_pcycle_count(CPUHexagonState *env, uint64_t val)
78 {
79 CPUState *cs;
80 uint64_t total;
81 int num_threads;
82 int64_t delta, per_thread, remainder;
83
84 g_assert(bql_locked());
85 total = hexagon_get_sys_pcycle_count(env);
86
87 /* Count active threads */
88 num_threads = 0;
89 CPU_FOREACH(cs) {
90 num_threads++;
91 }
92 g_assert(num_threads > 0);
93
94 /*
95 * Distribute the delta evenly across all threads.
96 * Any remainder goes to the calling thread.
97 */
98 delta = (int64_t)(val - total);
99 per_thread = delta / num_threads;
100 remainder = delta - per_thread * num_threads;
101
102 CPU_FOREACH(cs) {
103 CPUHexagonState *thread_env = cpu_env(cs);
104 thread_env->t_cycle_count += per_thread;
105 }
106 env->t_cycle_count += remainder;
107 }
108
109 static void hexagon_resume_thread(CPUHexagonState *env)
110 {
111 CPUState *cs = env_cpu(env);
112 clear_wait_mode(env);
113 /*
114 * The wait instruction keeps the PC pointing to itself
115 * so that it has an opportunity to check for interrupts.
116 *
117 * When we come out of wait mode, adjust the PC to the
118 * next executable instruction.
119 */
120 env->gpr[HEX_REG_PC] = env->wait_next_pc;
121 cs = env_cpu(env);
122 ASSERT_DIRECT_TO_GUEST_UNSET(env, cs->exception_index);
123 cs->halted = false;
124 cs->exception_index = HEX_EVENT_NONE;
125 qemu_cpu_kick(cs);
126 }
127
128 void hexagon_resume_threads(CPUHexagonState *current_env, uint32_t mask)
129 {
130 CPUState *cs;
131 CPUHexagonState *env;
132
133 g_assert(bql_locked());
134 CPU_FOREACH(cs) {
135 env = cpu_env(cs);
136 g_assert(env->threadId < THREADS_MAX);
137 if ((mask & (0x1 << env->threadId))) {
138 if (get_exe_mode(env) == HEX_EXE_MODE_WAIT) {
139 hexagon_resume_thread(env);
140 }
141 }
142 }
143 }
144
145 void hexagon_modify_ssr(CPUHexagonState *env, uint32_t new, uint32_t old)
146 {
147 bool old_EX, old_UM, old_GM, old_IE;
148 bool new_EX, new_UM, new_GM, new_IE;
149 uint8_t old_asid, new_asid;
150
151 g_assert(bql_locked());
152
153 old_EX = GET_SSR_FIELD(SSR_EX, old);
154 old_UM = GET_SSR_FIELD(SSR_UM, old);
155 old_GM = GET_SSR_FIELD(SSR_GM, old);
156 old_IE = GET_SSR_FIELD(SSR_IE, old);
157 new_EX = GET_SSR_FIELD(SSR_EX, new);
158 new_UM = GET_SSR_FIELD(SSR_UM, new);
159 new_GM = GET_SSR_FIELD(SSR_GM, new);
160 new_IE = GET_SSR_FIELD(SSR_IE, new);
161
162 if ((old_EX != new_EX) ||
163 (old_UM != new_UM) ||
164 (old_GM != new_GM)) {
165 hex_mmu_mode_change(env);
166 }
167
168 old_asid = GET_SSR_FIELD(SSR_ASID, old);
169 new_asid = GET_SSR_FIELD(SSR_ASID, new);
170 if (new_asid != old_asid) {
171 CPUState *cs = env_cpu(env);
172 tlb_flush(cs);
173 }
174
175 /* See if the interrupts have been enabled or we have exited EX mode */
176 if ((new_IE && !old_IE) ||
177 (!new_EX && old_EX)) {
178 hex_interrupt_update(env);
179 }
180 }
181
182 void clear_wait_mode(CPUHexagonState *env)
183 {
184 HexagonCPU *cpu;
185 uint32_t modectl, thread_wait_mask;
186
187 g_assert(bql_locked());
188
189 cpu = env_archcpu(env);
190 if (cpu->globalregs) {
191 modectl =
192 hexagon_globalreg_read(cpu->globalregs, HEX_SREG_MODECTL,
193 env->threadId);
194 thread_wait_mask = GET_FIELD(MODECTL_W, modectl);
195 thread_wait_mask &= ~(0x1 << env->threadId);
196 SET_SYSTEM_FIELD(env, HEX_SREG_MODECTL, MODECTL_W, thread_wait_mask);
197 }
198 }
199
200 void hexagon_ssr_set_cause(CPUHexagonState *env, uint32_t cause)
201 {
202 uint32_t old, new;
203
204 g_assert(bql_locked());
205
206 old = env->t_sreg[HEX_SREG_SSR];
207 SET_SYSTEM_FIELD(env, HEX_SREG_SSR, SSR_EX, 1);
208 SET_SYSTEM_FIELD(env, HEX_SREG_SSR, SSR_CAUSE, cause);
209 new = env->t_sreg[HEX_SREG_SSR];
210
211 hexagon_modify_ssr(env, new, old);
212 }
213
214
215 int get_exe_mode(CPUHexagonState *env)
216 {
217 HexagonCPU *cpu;
218 uint32_t modectl, thread_enabled_mask, thread_wait_mask;
219 uint32_t isdbst, debugmode;
220 bool E_bit, W_bit, D_bit;
221
222 g_assert(bql_locked());
223
224 cpu = env_archcpu(env);
225 modectl = cpu->globalregs ?
226 hexagon_globalreg_read(cpu->globalregs, HEX_SREG_MODECTL,
227 env->threadId) : 0;
228 thread_enabled_mask = GET_FIELD(MODECTL_E, modectl);
229 E_bit = thread_enabled_mask & (0x1 << env->threadId);
230 thread_wait_mask = GET_FIELD(MODECTL_W, modectl);
231 W_bit = thread_wait_mask & (0x1 << env->threadId);
232 isdbst = cpu->globalregs ?
233 hexagon_globalreg_read(cpu->globalregs, HEX_SREG_ISDBST,
234 env->threadId) : 0;
235 debugmode = GET_FIELD(ISDBST_DEBUGMODE, isdbst);
236 D_bit = debugmode & (0x1 << env->threadId);
237
238 if (!D_bit && !W_bit && !E_bit) {
239 return HEX_EXE_MODE_OFF;
240 }
241 if (!D_bit && !W_bit && E_bit) {
242 return HEX_EXE_MODE_RUN;
243 }
244 if (!D_bit && W_bit && E_bit) {
245 return HEX_EXE_MODE_WAIT;
246 }
247 if (D_bit && !W_bit && E_bit) {
248 return HEX_EXE_MODE_DEBUG;
249 }
250 g_assert_not_reached();
251 }
252
253 static uint32_t set_enable_mask(CPUHexagonState *env)
254 {
255 HexagonCPU *cpu;
256 uint32_t modectl, thread_enabled_mask;
257
258 g_assert(bql_locked());
259
260 cpu = env_archcpu(env);
261 if (!cpu->globalregs) {
262 return 0;
263 }
264 modectl =
265 hexagon_globalreg_read(cpu->globalregs, HEX_SREG_MODECTL,
266 env->threadId);
267 thread_enabled_mask = GET_FIELD(MODECTL_E, modectl);
268 thread_enabled_mask |= 0x1 << env->threadId;
269 SET_SYSTEM_FIELD(env, HEX_SREG_MODECTL, MODECTL_E, thread_enabled_mask);
270 return thread_enabled_mask;
271 }
272
273 static uint32_t clear_enable_mask(CPUHexagonState *env)
274 {
275 HexagonCPU *cpu;
276 uint32_t modectl, thread_enabled_mask;
277
278 g_assert(bql_locked());
279
280 cpu = env_archcpu(env);
281 if (!cpu->globalregs) {
282 return 0;
283 }
284 modectl =
285 hexagon_globalreg_read(cpu->globalregs, HEX_SREG_MODECTL,
286 env->threadId);
287 thread_enabled_mask = GET_FIELD(MODECTL_E, modectl);
288 thread_enabled_mask &= ~(0x1 << env->threadId);
289 SET_SYSTEM_FIELD(env, HEX_SREG_MODECTL, MODECTL_E, thread_enabled_mask);
290 return thread_enabled_mask;
291 }
292 static void do_start_thread(CPUState *cs, run_on_cpu_data tbd)
293 {
294 CPUHexagonState *env;
295
296 BQL_LOCK_GUARD();
297
298 env = cpu_env(cs);
299
300 hexagon_cpu_soft_reset(env);
301
302 set_enable_mask(env);
303
304 cs->halted = 0;
305 cs->exception_index = HEX_EVENT_NONE;
306 cpu_resume(cs);
307 }
308
309 void hexagon_start_threads(CPUHexagonState *current_env, uint32_t mask)
310 {
311 CPUState *cs;
312 CPU_FOREACH(cs) {
313 CPUHexagonState *env = cpu_env(cs);
314 if (!(mask & (0x1 << env->threadId))) {
315 continue;
316 }
317
318 if (current_env->threadId != env->threadId) {
319 async_safe_run_on_cpu(cs, do_start_thread, RUN_ON_CPU_NULL);
320 }
321 }
322 }
323
324 /*
325 * When we have all threads stopped, the return
326 * value to the shell is register 2 from thread 0.
327 */
328 static uint32_t get_thread0_r2(void)
329 {
330 CPUState *cs;
331 CPU_FOREACH(cs) {
332 CPUHexagonState *thread = cpu_env(cs);
333 if (thread->threadId == 0) {
334 return thread->gpr[2];
335 }
336 }
337 g_assert_not_reached();
338 }
339
340 void hexagon_stop_thread(CPUHexagonState *env)
341 {
342 uint32_t thread_enabled_mask;
343 CPUState *cs;
344
345 BQL_LOCK_GUARD();
346
347 thread_enabled_mask = clear_enable_mask(env);
348 cs = env_cpu(env);
349 cpu_interrupt(cs, CPU_INTERRUPT_HALT);
350 if (!thread_enabled_mask) {
351 /* All threads are stopped, request shutdown */
352 qemu_system_shutdown_request_with_code(
353 SHUTDOWN_CAUSE_GUEST_SHUTDOWN, get_thread0_r2());
354 }
355 }
356
357 static int sys_in_monitor_mode_ssr(uint32_t ssr)
358 {
359 if ((GET_SSR_FIELD(SSR_EX, ssr) != 0) ||
360 ((GET_SSR_FIELD(SSR_EX, ssr) == 0) &&
361 (GET_SSR_FIELD(SSR_UM, ssr) == 0))) {
362 return 1;
363 }
364 return 0;
365 }
366
367 static int sys_in_guest_mode_ssr(uint32_t ssr)
368 {
369 if ((GET_SSR_FIELD(SSR_EX, ssr) == 0) &&
370 (GET_SSR_FIELD(SSR_UM, ssr) != 0) &&
371 (GET_SSR_FIELD(SSR_GM, ssr) != 0)) {
372 return 1;
373 }
374 return 0;
375 }
376
377 static int sys_in_user_mode_ssr(uint32_t ssr)
378 {
379 if ((GET_SSR_FIELD(SSR_EX, ssr) == 0) &&
380 (GET_SSR_FIELD(SSR_UM, ssr) != 0) &&
381 (GET_SSR_FIELD(SSR_GM, ssr) == 0)) {
382 return 1;
383 }
384 return 0;
385 }
386
387 int get_cpu_mode(CPUHexagonState *env)
388 {
389 uint32_t ssr = env->t_sreg[HEX_SREG_SSR];
390
391 if (sys_in_monitor_mode_ssr(ssr)) {
392 return HEX_CPU_MODE_MONITOR;
393 } else if (sys_in_guest_mode_ssr(ssr)) {
394 return HEX_CPU_MODE_GUEST;
395 } else if (sys_in_user_mode_ssr(ssr)) {
396 return HEX_CPU_MODE_USER;
397 }
398 return HEX_CPU_MODE_MONITOR;
399 }