master
c 870 lines 27.5 KB
Raw
1 /*
2 * Copyright(c) 2019-2023 Qualcomm Innovation Center, Inc. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "qemu/osdep.h"
19 #include "qemu/log.h"
20 #include "qemu/qemu-print.h"
21 #include "cpu.h"
22 #include "internal.h"
23 #include "exec/cputlb.h"
24 #include "exec/translation-block.h"
25 #include "qapi/error.h"
26 #include "hw/core/qdev-properties.h"
27 #include "fpu/softfloat-helpers.h"
28 #include "hw/hexagon/hexagon_tlb.h"
29 #include "tcg/tcg.h"
30 #include "exec/gdbstub.h"
31 #include "accel/tcg/cpu-ops.h"
32 #include "cpu_helper.h"
33 #include "hex_mmu.h"
34
35 #ifndef CONFIG_USER_ONLY
36 #include "macros.h"
37 #include "sys_macros.h"
38 #include "accel/tcg/cpu-ldst.h"
39 #include "qemu/main-loop.h"
40 #include "hex_interrupts.h"
41 #include "hexswi.h"
42 #include "exec/cpu-interrupt.h"
43 #include "exec/page-protection.h"
44 #include "exec/target_page.h"
45 #include "hw/hexagon/hexagon_globalreg.h"
46 #endif
47
48 static ObjectClass *hexagon_cpu_class_by_name(const char *cpu_model)
49 {
50 ObjectClass *oc;
51 char *typename;
52 char **cpuname;
53
54 cpuname = g_strsplit(cpu_model, ",", 1);
55 typename = g_strdup_printf(HEXAGON_CPU_TYPE_NAME("%s"), cpuname[0]);
56 oc = object_class_by_name(typename);
57 g_strfreev(cpuname);
58 g_free(typename);
59
60 return oc;
61 }
62
63 static const Property hexagon_cpu_properties[] = {
64 #ifndef CONFIG_USER_ONLY
65 DEFINE_PROP_LINK("tlb", HexagonCPU, tlb, TYPE_HEXAGON_TLB,
66 HexagonTLBState *),
67 DEFINE_PROP_UINT32("exec-start-addr", HexagonCPU, boot_addr, 0xffffffff),
68 DEFINE_PROP_LINK("l2vic", HexagonCPU, l2vic,
69 TYPE_HEX_L2VIC_INTERFACE, HexL2VicInterface *),
70 DEFINE_PROP_LINK("global-regs", HexagonCPU, globalregs,
71 TYPE_HEXAGON_GLOBALREG, HexagonGlobalRegState *),
72 DEFINE_PROP_UINT32("htid", HexagonCPU, htid, 0),
73 #endif
74 DEFINE_PROP_BOOL("lldb-compat", HexagonCPU, cfg.lldb_compat, false),
75 DEFINE_PROP_UNSIGNED("lldb-stack-adjust", HexagonCPU, cfg.lldb_stack_adjust,
76 0, qdev_prop_uint32, target_ulong),
77 DEFINE_PROP_BOOL("short-circuit", HexagonCPU, cfg.short_circuit, true),
78 DEFINE_PROP_BOOL("ieee-fp", HexagonCPU, cfg.ieee_fp_extension, true),
79 };
80
81 const char * const hexagon_regnames[TOTAL_PER_THREAD_REGS] = {
82 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
83 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
84 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
85 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
86 "sa0", "lc0", "sa1", "lc1", "p3_0", "c5", "m0", "m1",
87 "usr", "pc", "ugp", "gp", "cs0", "cs1", "c14", "c15",
88 "c16", "c17", "c18", "c19", "pkt_cnt", "insn_cnt", "hvx_cnt", "c23",
89 "c24", "c25", "c26", "c27", "c28", "c29", "c30", "c31",
90 };
91
92 #ifndef CONFIG_USER_ONLY
93 const char * const hexagon_sregnames[] = {
94 "sgp0", "sgp1", "stid", "elr", "badva0",
95 "badva1", "ssr", "ccr", "htid", "badva",
96 "imask", "gevb", "vwctrl", "s13", "s14",
97 "s15", "evb", "modectl", "syscfg", "segment",
98 "ipendad", "vid", "vid1", "bestwait", "s24",
99 "schedcfg", "s26", "cfgbase", "diag", "rev",
100 "pcyclelo", "pcyclehi", "isdbst", "isdbcfg0", "isdbcfg1",
101 "livelock", "brkptpc0", "brkptcfg0", "brkptpc1", "brkptcfg1",
102 "isdbmbxin", "isdbmbxout", "isdben", "isdbgpr", "pmucnt4",
103 "pmucnt5", "pmucnt6", "pmucnt7", "pmucnt0", "pmucnt1",
104 "pmucnt2", "pmucnt3", "pmuevtcfg", "pmustid0", "pmuevtcfg1",
105 "pmustid1", "timerlo", "timerhi", "pmucfg", "s59",
106 "s60", "s61", "s62", "s63",
107 };
108
109 G_STATIC_ASSERT(NUM_SREGS == ARRAY_SIZE(hexagon_sregnames));
110
111 const char * const hexagon_gregnames[] = {
112 "gelr", "gsr", "gosp", "gbadva", "gcommit1t",
113 "gcommit2t", "gcommit3t", "gcommit4t", "gcommit5t", "gcommit6t",
114 "gpcycle1t", "gpcycle2t", "gpcycle3t", "gpcycle4t", "gpcycle5t",
115 "gpcycle6t", "gpmucnt4", "gpmucnt5", "gpmucnt6", "gpmucnt7",
116 "gcommit7t", "gcommit8t", "gpcycle7t", "gpcycle8t", "gpcyclelo",
117 "gpcyclehi", "gpmucnt0", "gpmucnt1", "gpmucnt2", "gpmucnt3",
118 "g30", "g31",
119 };
120 #endif
121 /*
122 * One of the main debugging techniques is to use "-d cpu" and compare against
123 * LLDB output when single stepping. However, the target and qemu put the
124 * stacks at different locations. This is used to compensate so the diff is
125 * cleaner.
126 */
127 static target_ulong adjust_stack_ptrs(CPUHexagonState *env, target_ulong addr)
128 {
129 HexagonCPU *cpu = env_archcpu(env);
130 target_ulong stack_adjust = cpu->cfg.lldb_stack_adjust;
131 target_ulong stack_start = env->stack_start;
132 target_ulong stack_size = 0x10000;
133
134 if (stack_adjust == 0) {
135 return addr;
136 }
137
138 if (stack_start + 0x1000 >= addr && addr >= (stack_start - stack_size)) {
139 return addr - stack_adjust;
140 }
141 return addr;
142 }
143
144 /* HEX_REG_P3_0_ALIASED (aka C4) is an alias for the predicate registers */
145 static target_ulong read_p3_0(CPUHexagonState *env)
146 {
147 int32_t control_reg = 0;
148 int i;
149 for (i = NUM_PREGS - 1; i >= 0; i--) {
150 control_reg <<= 8;
151 control_reg |= env->pred[i] & 0xff;
152 }
153 return control_reg;
154 }
155
156 static void print_reg(FILE *f, CPUHexagonState *env, int regnum)
157 {
158 target_ulong value;
159
160 if (regnum == HEX_REG_P3_0_ALIASED) {
161 value = read_p3_0(env);
162 } else {
163 value = regnum < 32 ? adjust_stack_ptrs(env, env->gpr[regnum])
164 : env->gpr[regnum];
165 }
166
167 qemu_fprintf(f, " %s = 0x" TARGET_FMT_lx "\n",
168 hexagon_regnames[regnum], value);
169 }
170
171 #ifndef CONFIG_USER_ONLY
172 static void print_t_sreg(FILE *f, const CPUHexagonState *env, int regnum)
173 {
174 qemu_fprintf(f, " %s = 0x" TARGET_FMT_lx "\n",
175 hexagon_sregnames[regnum], env->t_sreg[regnum]);
176 }
177 #endif
178
179 static void print_vreg(FILE *f, CPUHexagonState *env, int regnum,
180 bool skip_if_zero)
181 {
182 if (skip_if_zero) {
183 bool nonzero_found = false;
184 for (int i = 0; i < MAX_VEC_SIZE_BYTES; i++) {
185 if (env->VRegs[regnum].ub[i] != 0) {
186 nonzero_found = true;
187 break;
188 }
189 }
190 if (!nonzero_found) {
191 return;
192 }
193 }
194
195 qemu_fprintf(f, " v%d = ( ", regnum);
196 qemu_fprintf(f, "0x%02x", env->VRegs[regnum].ub[MAX_VEC_SIZE_BYTES - 1]);
197 for (int i = MAX_VEC_SIZE_BYTES - 2; i >= 0; i--) {
198 qemu_fprintf(f, ", 0x%02x", env->VRegs[regnum].ub[i]);
199 }
200 qemu_fprintf(f, " )\n");
201 }
202
203 void hexagon_debug_vreg(CPUHexagonState *env, int regnum)
204 {
205 print_vreg(stdout, env, regnum, false);
206 }
207
208 static void print_qreg(FILE *f, CPUHexagonState *env, int regnum,
209 bool skip_if_zero)
210 {
211 if (skip_if_zero) {
212 bool nonzero_found = false;
213 for (int i = 0; i < MAX_VEC_SIZE_BYTES / 8; i++) {
214 if (env->QRegs[regnum].ub[i] != 0) {
215 nonzero_found = true;
216 break;
217 }
218 }
219 if (!nonzero_found) {
220 return;
221 }
222 }
223
224 qemu_fprintf(f, " q%d = ( ", regnum);
225 qemu_fprintf(f, "0x%02x",
226 env->QRegs[regnum].ub[MAX_VEC_SIZE_BYTES / 8 - 1]);
227 for (int i = MAX_VEC_SIZE_BYTES / 8 - 2; i >= 0; i--) {
228 qemu_fprintf(f, ", 0x%02x", env->QRegs[regnum].ub[i]);
229 }
230 qemu_fprintf(f, " )\n");
231 }
232
233 void hexagon_debug_qreg(CPUHexagonState *env, int regnum)
234 {
235 print_qreg(stdout, env, regnum, false);
236 }
237
238 static void hexagon_dump(CPUHexagonState *env, FILE *f, int flags)
239 {
240 HexagonCPU *cpu = env_archcpu(env);
241
242 if (cpu->cfg.lldb_compat) {
243 /*
244 * When comparing with LLDB, it doesn't step through single-cycle
245 * hardware loops the same way. So, we just skip them here
246 */
247 if (env->gpr[HEX_REG_PC] == env->last_pc_dumped) {
248 return;
249 }
250 env->last_pc_dumped = env->gpr[HEX_REG_PC];
251 }
252
253 qemu_fprintf(f, "General Purpose Registers = {\n");
254 for (int i = 0; i < 32; i++) {
255 print_reg(f, env, i);
256 }
257 print_reg(f, env, HEX_REG_SA0);
258 print_reg(f, env, HEX_REG_LC0);
259 print_reg(f, env, HEX_REG_SA1);
260 print_reg(f, env, HEX_REG_LC1);
261 print_reg(f, env, HEX_REG_M0);
262 print_reg(f, env, HEX_REG_M1);
263 print_reg(f, env, HEX_REG_USR);
264 print_reg(f, env, HEX_REG_P3_0_ALIASED);
265 print_reg(f, env, HEX_REG_GP);
266 print_reg(f, env, HEX_REG_UGP);
267 print_reg(f, env, HEX_REG_PC);
268 #ifdef CONFIG_USER_ONLY
269 /*
270 * Not modelled in user mode, print junk to minimize the diff's
271 * with LLDB output
272 */
273 qemu_fprintf(f, " cause = 0x000000db\n");
274 qemu_fprintf(f, " badva = 0x00000000\n");
275 qemu_fprintf(f, " cs0 = 0x00000000\n");
276 qemu_fprintf(f, " cs1 = 0x00000000\n");
277 #else
278 print_t_sreg(f, env, HEX_SREG_BADVA);
279 print_reg(f, env, HEX_REG_CS0);
280 print_reg(f, env, HEX_REG_CS1);
281 #endif
282 qemu_fprintf(f, "}\n");
283
284 if (flags & CPU_DUMP_FPU) {
285 qemu_fprintf(f, "Vector Registers = {\n");
286 for (int i = 0; i < NUM_VREGS; i++) {
287 print_vreg(f, env, i, true);
288 }
289 for (int i = 0; i < NUM_QREGS; i++) {
290 print_qreg(f, env, i, true);
291 }
292 qemu_fprintf(f, "}\n");
293 }
294 }
295
296 static void hexagon_dump_state(CPUState *cs, FILE *f, int flags)
297 {
298 hexagon_dump(cpu_env(cs), f, flags);
299 }
300
301 void hexagon_debug(CPUHexagonState *env)
302 {
303 hexagon_dump(env, stdout, CPU_DUMP_FPU);
304 }
305
306 static void hexagon_cpu_set_pc(CPUState *cs, vaddr value)
307 {
308 cpu_env(cs)->gpr[HEX_REG_PC] = value;
309 }
310
311 static vaddr hexagon_cpu_get_pc(CPUState *cs)
312 {
313 return cpu_env(cs)->gpr[HEX_REG_PC];
314 }
315
316 static TCGTBCPUState hexagon_get_tb_cpu_state(CPUState *cs)
317 {
318 CPUHexagonState *env = cpu_env(cs);
319 vaddr pc = env->gpr[HEX_REG_PC];
320 uint32_t hex_flags = 0;
321
322 if (pc == env->gpr[HEX_REG_SA0]) {
323 hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, IS_TIGHT_LOOP, 1);
324 }
325 if (pc & PCALIGN_MASK) {
326 hexagon_raise_exception_err(env, HEX_CAUSE_PC_NOT_ALIGNED, 0);
327 }
328
329 #ifndef CONFIG_USER_ONLY
330 hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, MMU_INDEX,
331 cpu_mmu_index(env_cpu(env), false));
332 hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, PCYCLE_ENABLED, 1);
333 #else
334 hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, MMU_INDEX, MMU_USER_IDX);
335 #endif
336
337 return (TCGTBCPUState){ .pc = pc, .flags = hex_flags };
338 }
339
340 static void hexagon_cpu_synchronize_from_tb(CPUState *cs,
341 const TranslationBlock *tb)
342 {
343 tcg_debug_assert(!tcg_cflags_has(cs, CF_PCREL));
344 cpu_env(cs)->gpr[HEX_REG_PC] = tb->pc;
345 }
346
347 #ifndef CONFIG_USER_ONLY
348 bool hexagon_thread_is_enabled(CPUHexagonState *env)
349 {
350 HexagonCPU *cpu = env_archcpu(env);
351 uint32_t modectl;
352 uint32_t thread_enabled_mask;
353 bool E_bit;
354
355 if (!cpu->globalregs) {
356 return true;
357 }
358 modectl =
359 hexagon_globalreg_read(cpu->globalregs, HEX_SREG_MODECTL,
360 env->threadId);
361 thread_enabled_mask = GET_FIELD(MODECTL_E, modectl);
362 E_bit = thread_enabled_mask & (0x1 << env->threadId);
363
364 return E_bit;
365 }
366
367 static bool hexagon_cpu_has_work(CPUState *cs)
368 {
369 CPUHexagonState *env = cpu_env(cs);
370
371 return hexagon_thread_is_enabled(env) &&
372 (cs->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_SWI
373 | CPU_INTERRUPT_K0_UNLOCK | CPU_INTERRUPT_TLB_UNLOCK));
374 }
375 #endif
376
377 static void hexagon_restore_state_to_opc(CPUState *cs,
378 const TranslationBlock *tb,
379 const uint64_t *data)
380 {
381 cpu_env(cs)->gpr[HEX_REG_PC] = data[0];
382 }
383
384
385 #ifndef CONFIG_USER_ONLY
386 void hexagon_cpu_soft_reset(CPUHexagonState *env)
387 {
388 HexagonCPU *cpu;
389
390 BQL_LOCK_GUARD();
391 env->t_sreg[HEX_SREG_SSR] = 0;
392 hexagon_ssr_set_cause(env, HEX_CAUSE_RESET);
393
394 cpu = env_archcpu(env);
395 if (cpu->globalregs) {
396 uint32_t evb =
397 hexagon_globalreg_read(cpu->globalregs, HEX_SREG_EVB,
398 env->threadId);
399 env->gpr[HEX_REG_PC] = evb;
400 } else {
401 env->gpr[HEX_REG_PC] = cpu->boot_addr;
402 }
403 }
404 #endif
405
406 static void hexagon_cpu_reset_hold(Object *obj, ResetType type)
407 {
408 CPUState *cs = CPU(obj);
409 HexagonCPUClass *mcc = HEXAGON_CPU_GET_CLASS(obj);
410 CPUHexagonState *env = cpu_env(cs);
411 #ifndef CONFIG_USER_ONLY
412 HexagonCPU *cpu = HEXAGON_CPU(cs);
413 #endif
414
415 if (mcc->parent_phases.hold) {
416 mcc->parent_phases.hold(obj, type);
417 }
418
419 set_default_nan_mode(1, &env->fp_status);
420 set_float_detect_tininess(float_tininess_before_rounding, &env->fp_status);
421 /* Default NaN value: sign bit set, all frac bits set */
422 set_float_default_nan_pattern(0b11111111, &env->fp_status);
423
424 set_default_nan_mode(1, &env->hvx_fp_status);
425 set_float_default_nan_pattern(0b01111111, &env->hvx_fp_status);
426 #ifndef CONFIG_USER_ONLY
427 memset(env->t_sreg, 0, sizeof(uint32_t) * NUM_SREGS);
428 memset(env->greg, 0, sizeof(uint32_t) * NUM_GREGS);
429 env->wait_next_pc = 0;
430 env->tlb_lock_state = HEX_LOCK_UNLOCKED;
431 env->k0_lock_state = HEX_LOCK_UNLOCKED;
432 env->tlb_lock_count = 0;
433 env->k0_lock_count = 0;
434 env->next_PC = 0;
435
436 env->t_sreg[HEX_SREG_HTID] = cpu->htid;
437 env->threadId = cpu->htid;
438 hexagon_cpu_soft_reset(env);
439 env->cause_code = HEX_EVENT_NONE;
440 env->gpr[HEX_REG_PC] = cpu->boot_addr;
441 #endif
442 }
443
444 static void hexagon_cpu_disas_set_info(const CPUState *cs,
445 disassemble_info *info)
446 {
447 const HexagonCPU *cpu = HEXAGON_CPU(cs);
448 info->print_insn = print_insn_hexagon;
449 info->endian = BFD_ENDIAN_LITTLE;
450 info->target_info = &cpu->cfg;
451 }
452
453 static void hexagon_cpu_realize(DeviceState *dev, Error **errp)
454 {
455 CPUState *cs = CPU(dev);
456 HexagonCPU *cpu = HEXAGON_CPU(dev);
457 HexagonCPUClass *mcc = HEXAGON_CPU_GET_CLASS(dev);
458 Error *local_err = NULL;
459
460 cpu_common_realize(cs, &local_err);
461 if (local_err != NULL) {
462 error_propagate(errp, local_err);
463 return;
464 }
465
466 cpu->cfg.hex_def = mcc->hex_def;
467
468 gdb_register_coprocessor(cs, hexagon_hvx_gdb_read_register,
469 hexagon_hvx_gdb_write_register,
470 gdb_find_static_feature("hexagon-hvx.xml"));
471
472 #ifndef CONFIG_USER_ONLY
473 if (!HEXAGON_CPU(dev)->tlb) {
474 error_setg(errp, "hexagon cpu requires 'tlb' link property to be set");
475 return;
476 }
477 #endif
478
479 qemu_init_vcpu(cs);
480
481 cpu_reset(cs);
482 mcc->parent_realize(dev, errp);
483 }
484
485 static int hexagon_cpu_mmu_index(CPUState *cs, bool ifetch)
486 {
487 #ifndef CONFIG_USER_ONLY
488 CPUHexagonState *env = cpu_env(cs);
489 HexagonCPU *cpu = HEXAGON_CPU(cs);
490 int cpu_mode;
491
492 BQL_LOCK_GUARD();
493 if (cpu->globalregs) {
494 uint32_t syscfg =
495 hexagon_globalreg_read(cpu->globalregs, HEX_SREG_SYSCFG,
496 env->threadId);
497 uint8_t mmuen = GET_SYSCFG_FIELD(SYSCFG_MMUEN, syscfg);
498 if (!mmuen) {
499 return MMU_KERNEL_IDX;
500 }
501 }
502
503 cpu_mode = get_cpu_mode(env);
504 if (cpu_mode == HEX_CPU_MODE_MONITOR) {
505 return MMU_KERNEL_IDX;
506 } else if (cpu_mode == HEX_CPU_MODE_GUEST) {
507 return MMU_GUEST_IDX;
508 }
509 #endif
510
511 return MMU_USER_IDX;
512 }
513
514 #ifndef CONFIG_USER_ONLY
515 static void hexagon_cpu_set_irq(void *opaque, int irq, int level)
516 {
517 HexagonCPU *cpu = HEXAGON_CPU(opaque);
518 CPUState *cs = CPU(cpu);
519 CPUHexagonState *env = cpu_env(cs);
520
521 switch (irq) {
522 case HEXAGON_CPU_IRQ_0 ... HEXAGON_CPU_IRQ_7:
523 qemu_log_mask(CPU_LOG_INT, "%s: irq %d, level %d\n",
524 __func__, irq, level);
525 if (level) {
526 hex_raise_interrupts(env, 1 << irq, CPU_INTERRUPT_HARD);
527 }
528 break;
529 default:
530 g_assert_not_reached();
531 }
532 }
533 #endif
534
535 static void hexagon_cpu_init(Object *obj)
536 {
537 #ifndef CONFIG_USER_ONLY
538 HexagonCPU *cpu = HEXAGON_CPU(obj);
539 qdev_init_gpio_in(DEVICE(cpu), hexagon_cpu_set_irq, 8);
540 #endif
541 }
542
543 #ifndef CONFIG_USER_ONLY
544 static bool get_physical_address(CPUHexagonState *env, hwaddr *phys, int *prot,
545 uint64_t *size, int32_t *excp,
546 uint32_t address,
547 MMUAccessType access_type, int mmu_idx)
548
549 {
550 if (hexagon_cpu_mmu_enabled(env)) {
551 return hex_tlb_find_match(env, address, access_type, phys, prot, size,
552 excp, mmu_idx);
553 } else {
554 *phys = address & 0xFFFFFFFF;
555 *prot = PAGE_VALID | PAGE_READ | PAGE_WRITE | PAGE_EXEC;
556 *size = TARGET_PAGE_SIZE;
557 return true;
558 }
559 }
560
561 /* qemu seems to only want to know about TARGET_PAGE_SIZE pages */
562 static void find_qemu_subpage(vaddr *addr, hwaddr *phys, uint64_t page_size)
563 {
564 vaddr page_start = *addr & ~((vaddr)(page_size - 1));
565 vaddr offset = ((*addr - page_start) / TARGET_PAGE_SIZE) * TARGET_PAGE_SIZE;
566 *addr = page_start + offset;
567 *phys += offset;
568 }
569
570 static hwaddr hexagon_cpu_get_phys_addr_debug(CPUState *cs, vaddr addr)
571 {
572 CPUHexagonState *env = cpu_env(cs);
573 hwaddr phys_addr;
574 int prot;
575 uint64_t page_size = 0;
576 int32_t excp = 0;
577 int mmu_idx = MMU_KERNEL_IDX;
578
579 if (get_physical_address(env, &phys_addr, &prot, &page_size, &excp,
580 addr, 0, mmu_idx)) {
581 vaddr page_offset = addr & (TARGET_PAGE_SIZE - 1);
582 find_qemu_subpage(&addr, &phys_addr, page_size);
583 phys_addr += hexagon_cpu_mmu_enabled(env) ? page_offset : 0;
584 return phys_addr;
585 }
586
587 return -1;
588 }
589
590
591 #define INVALID_BADVA 0xbadabada
592
593 static void set_badva_regs(CPUHexagonState *env, uint32_t VA, int slot,
594 MMUAccessType access_type)
595 {
596 env->t_sreg[HEX_SREG_BADVA] = VA;
597
598 if (access_type == MMU_INST_FETCH || slot == 0) {
599 env->t_sreg[HEX_SREG_BADVA0] = VA;
600 env->t_sreg[HEX_SREG_BADVA1] = INVALID_BADVA;
601 SET_SSR_FIELD(env, SSR_V0, 1);
602 SET_SSR_FIELD(env, SSR_V1, 0);
603 SET_SSR_FIELD(env, SSR_BVS, 0);
604 } else if (slot == 1) {
605 env->t_sreg[HEX_SREG_BADVA0] = INVALID_BADVA;
606 env->t_sreg[HEX_SREG_BADVA1] = VA;
607 SET_SSR_FIELD(env, SSR_V0, 0);
608 SET_SSR_FIELD(env, SSR_V1, 1);
609 SET_SSR_FIELD(env, SSR_BVS, 1);
610 } else {
611 g_assert_not_reached();
612 }
613 }
614
615 static void raise_tlbmiss_exception(CPUState *cs, uint32_t VA, int slot,
616 MMUAccessType access_type)
617 {
618 CPUHexagonState *env = cpu_env(cs);
619
620 set_badva_regs(env, VA, slot, access_type);
621
622 switch (access_type) {
623 case MMU_INST_FETCH:
624 cs->exception_index = HEX_EVENT_TLB_MISS_X;
625 if ((VA & ~TARGET_PAGE_MASK) == 0) {
626 env->cause_code = HEX_CAUSE_TLBMISSX_CAUSE_NEXTPAGE;
627 } else {
628 env->cause_code = HEX_CAUSE_TLBMISSX_CAUSE_NORMAL;
629 }
630 break;
631 case MMU_DATA_LOAD:
632 cs->exception_index = HEX_EVENT_TLB_MISS_RW;
633 env->cause_code = HEX_CAUSE_TLBMISSRW_CAUSE_READ;
634 break;
635 case MMU_DATA_STORE:
636 cs->exception_index = HEX_EVENT_TLB_MISS_RW;
637 env->cause_code = HEX_CAUSE_TLBMISSRW_CAUSE_WRITE;
638 break;
639 }
640 }
641
642 static void raise_perm_exception(CPUState *cs, uint32_t VA, int slot,
643 MMUAccessType access_type, int32_t excp)
644 {
645 CPUHexagonState *env = cpu_env(cs);
646
647 set_badva_regs(env, VA, slot, access_type);
648 cs->exception_index = excp;
649 }
650
651 static void raise_misaligned_exception(CPUState *cs, uint32_t VA, int slot,
652 MMUAccessType access_type)
653 {
654 CPUHexagonState *env = cpu_env(cs);
655 int32_t excp = (access_type == MMU_DATA_STORE) ?
656 HEX_CAUSE_MISALIGNED_STORE : HEX_CAUSE_MISALIGNED_LOAD;
657
658 set_badva_regs(env, VA, slot, access_type);
659 cs->exception_index = HEX_EVENT_PRECISE;
660 env->cause_code = excp;
661 }
662
663 static const char *access_type_names[] = { "MMU_DATA_LOAD ", "MMU_DATA_STORE",
664 "MMU_INST_FETCH" };
665
666 static const char *mmu_idx_names[] = { "MMU_USER_IDX", "MMU_GUEST_IDX",
667 "MMU_KERNEL_IDX" };
668
669 static bool hexagon_tlb_fill(CPUState *cs, vaddr address, int size,
670 MMUAccessType access_type, int mmu_idx, bool probe,
671 uintptr_t retaddr)
672 {
673 CPUHexagonState *env = cpu_env(cs);
674 int slot = 0;
675 hwaddr phys;
676 int prot = 0;
677 uint64_t page_size = 0;
678 int32_t excp = 0;
679 bool ret = 0;
680
681 qemu_log_mask(
682 CPU_LOG_MMU,
683 "%s: tid = 0x%" PRIx32 ", pc = 0x%08" PRIx32
684 ", vaddr = 0x%08" VADDR_PRIx ", size = %d, %s,\tprobe = %d, %s\n",
685 __func__, env->threadId, env->gpr[HEX_REG_PC], address, size,
686 access_type_names[access_type], probe, mmu_idx_names[mmu_idx]);
687 ret = get_physical_address(env, &phys, &prot, &page_size, &excp, address,
688 access_type, mmu_idx);
689 if (ret) {
690 if (!excp) {
691 find_qemu_subpage(&address, &phys, page_size);
692 tlb_set_page(cs, address, phys, prot, mmu_idx, TARGET_PAGE_SIZE);
693 return ret;
694 }
695 if (probe) {
696 return false;
697 }
698 raise_perm_exception(cs, address, slot, access_type, excp);
699 do_raise_exception(env, cs->exception_index, env->gpr[HEX_REG_PC],
700 retaddr);
701 }
702 if (probe) {
703 return false;
704 }
705 raise_tlbmiss_exception(cs, address, slot, access_type);
706 do_raise_exception(env, cs->exception_index, env->gpr[HEX_REG_PC], retaddr);
707 }
708
709 #include "hw/core/sysemu-cpu-ops.h"
710
711 static const struct SysemuCPUOps hexagon_sysemu_ops = {
712 .has_work = hexagon_cpu_has_work,
713 .get_phys_addr_debug = hexagon_cpu_get_phys_addr_debug,
714 };
715
716 static bool hexagon_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
717 {
718 CPUHexagonState *env = cpu_env(cs);
719 if (interrupt_request & CPU_INTERRUPT_TLB_UNLOCK) {
720 cs->halted = false;
721 cpu_reset_interrupt(cs, CPU_INTERRUPT_TLB_UNLOCK);
722 return true;
723 }
724 if (interrupt_request & CPU_INTERRUPT_K0_UNLOCK) {
725 cs->halted = false;
726 cpu_reset_interrupt(cs, CPU_INTERRUPT_K0_UNLOCK);
727 return true;
728 }
729 if (interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_SWI)) {
730 return hex_check_interrupts(env);
731 }
732 return false;
733 }
734
735 static vaddr hexagon_pointer_wrap(CPUState *cs, int mmu_idx,
736 vaddr result, vaddr base)
737 {
738 return result;
739 }
740
741 static G_NORETURN
742 void hexagon_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
743 MMUAccessType access_type, int mmu_idx,
744 uintptr_t retaddr)
745 {
746 CPUHexagonState *env = cpu_env(cs);
747
748 raise_misaligned_exception(cs, addr, 0, access_type);
749 do_raise_exception(env, cs->exception_index, env->gpr[HEX_REG_PC],
750 retaddr);
751 }
752
753 #endif
754
755 static const TCGCPUOps hexagon_tcg_ops = {
756 /* MTTCG not yet supported: require strict ordering */
757 .guest_default_memory_order = TCG_MO_ALL,
758 .mttcg_supported = false,
759 .initialize = hexagon_translate_init,
760 .translate_code = hexagon_translate_code,
761 .get_tb_cpu_state = hexagon_get_tb_cpu_state,
762 .synchronize_from_tb = hexagon_cpu_synchronize_from_tb,
763 .restore_state_to_opc = hexagon_restore_state_to_opc,
764 .mmu_index = hexagon_cpu_mmu_index,
765 #ifndef CONFIG_USER_ONLY
766 .cpu_exec_interrupt = hexagon_cpu_exec_interrupt,
767 .pointer_wrap = hexagon_pointer_wrap,
768 .cpu_exec_reset = cpu_reset,
769 .tlb_fill = hexagon_tlb_fill,
770 .do_unaligned_access = hexagon_cpu_do_unaligned_access,
771 .cpu_exec_halt = hexagon_cpu_has_work,
772 .do_interrupt = hexagon_cpu_do_interrupt,
773 #endif /* !CONFIG_USER_ONLY */
774 };
775
776 static void hexagon_cpu_class_init(ObjectClass *c, const void *data)
777 {
778 HexagonCPUClass *mcc = HEXAGON_CPU_CLASS(c);
779 CPUClass *cc = CPU_CLASS(c);
780 DeviceClass *dc = DEVICE_CLASS(c);
781 ResettableClass *rc = RESETTABLE_CLASS(c);
782
783 device_class_set_parent_realize(dc, hexagon_cpu_realize,
784 &mcc->parent_realize);
785
786 device_class_set_props(dc, hexagon_cpu_properties);
787 resettable_class_set_parent_phases(rc, NULL, hexagon_cpu_reset_hold, NULL,
788 &mcc->parent_phases);
789
790 cc->class_by_name = hexagon_cpu_class_by_name;
791 cc->dump_state = hexagon_dump_state;
792 cc->set_pc = hexagon_cpu_set_pc;
793 cc->get_pc = hexagon_cpu_get_pc;
794 cc->gdb_read_register = hexagon_gdb_read_register;
795 cc->gdb_write_register = hexagon_gdb_write_register;
796 cc->gdb_stop_before_watchpoint = true;
797 cc->gdb_core_xml_file = "hexagon-core.xml";
798 cc->disas_set_info = hexagon_cpu_disas_set_info;
799 #ifndef CONFIG_USER_ONLY
800 cc->sysemu_ops = &hexagon_sysemu_ops;
801 dc->vmsd = &vmstate_hexagon_cpu;
802 #endif
803 #ifdef CONFIG_TCG
804 cc->tcg_ops = &hexagon_tcg_ops;
805 #endif
806 }
807
808 #ifndef CONFIG_USER_ONLY
809 uint32_t hexagon_greg_read(CPUHexagonState *env, uint32_t reg)
810 {
811 if (reg <= HEX_GREG_G3) {
812 return env->greg[reg];
813 }
814 switch (reg) {
815 case HEX_GREG_GPCYCLELO:
816 return hexagon_get_sys_pcycle_count_low(env);
817 case HEX_GREG_GPCYCLEHI:
818 return hexagon_get_sys_pcycle_count_high(env);
819 default:
820 qemu_log_mask(LOG_UNIMP, "reading greg %" PRId32
821 " not yet supported.\n", reg);
822 return 0;
823 }
824 }
825 #endif
826
827 static void hexagon_cpu_class_base_init(ObjectClass *c, const void *data)
828 {
829 HexagonCPUClass *mcc = HEXAGON_CPU_CLASS(c);
830 /* Make sure all CPU models define a HexagonCPUDef */
831 g_assert(!object_class_is_abstract(c) && data != NULL);
832 mcc->hex_def = data;
833 }
834
835 #define DEFINE_CPU(type_name, version) \
836 { \
837 .name = type_name, \
838 .parent = TYPE_HEXAGON_CPU, \
839 .class_data = &(const HexagonCPUDef) { \
840 .hex_version = version, \
841 } \
842 }
843
844 static const TypeInfo hexagon_cpu_type_infos[] = {
845 {
846 .name = TYPE_HEXAGON_CPU,
847 .parent = TYPE_CPU,
848 .instance_size = sizeof(HexagonCPU),
849 .instance_align = __alignof(HexagonCPU),
850 .instance_init = hexagon_cpu_init,
851 .abstract = true,
852 .class_size = sizeof(HexagonCPUClass),
853 .class_init = hexagon_cpu_class_init,
854 .class_base_init = hexagon_cpu_class_base_init,
855 },
856 DEFINE_CPU(TYPE_HEXAGON_CPU_V5, HEX_VER_V5),
857 DEFINE_CPU(TYPE_HEXAGON_CPU_V55, HEX_VER_V55),
858 DEFINE_CPU(TYPE_HEXAGON_CPU_V60, HEX_VER_V60),
859 DEFINE_CPU(TYPE_HEXAGON_CPU_V61, HEX_VER_V61),
860 DEFINE_CPU(TYPE_HEXAGON_CPU_V62, HEX_VER_V62),
861 DEFINE_CPU(TYPE_HEXAGON_CPU_V65, HEX_VER_V65),
862 DEFINE_CPU(TYPE_HEXAGON_CPU_V66, HEX_VER_V66),
863 DEFINE_CPU(TYPE_HEXAGON_CPU_V67, HEX_VER_V67),
864 DEFINE_CPU(TYPE_HEXAGON_CPU_V68, HEX_VER_V68),
865 DEFINE_CPU(TYPE_HEXAGON_CPU_V69, HEX_VER_V69),
866 DEFINE_CPU(TYPE_HEXAGON_CPU_V71, HEX_VER_V71),
867 DEFINE_CPU(TYPE_HEXAGON_CPU_V73, HEX_VER_V73),
868 };
869
870 DEFINE_TYPES(hexagon_cpu_type_infos)