1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3 * QEMU LoongArch user cpu_loop.
4 *
5 * Copyright (c) 2021 Loongson Technology Corporation Limited
6 */
7
8 #include "qemu/osdep.h"
9 #include "qemu.h"
10 #include "user-internals.h"
11 #include "user/cpu_loop.h"
12 #include "signal-common.h"
13
14 /* Break codes */
15 enum {
16 BRK_OVERFLOW = 6,
17 BRK_DIVZERO = 7
18 };
19
cpu_loop(CPULoongArchState * env)20 void cpu_loop(CPULoongArchState *env)
21 {
22 CPUState *cs = env_cpu(env);
23 int trapnr, si_code;
24 abi_long ret;
25
26 for (;;) {
27 cpu_exec_start(cs);
28 trapnr = cpu_exec(cs);
29 cpu_exec_end(cs);
30 process_queued_cpu_work(cs);
31
32 switch (trapnr) {
33 case EXCP_INTERRUPT:
34 /* just indicate that signals should be handled asap */
35 break;
36 case EXCCODE_SYS:
37 env->pc += 4;
38 ret = do_syscall(env, env->gpr[11],
39 env->gpr[4], env->gpr[5],
40 env->gpr[6], env->gpr[7],
41 env->gpr[8], env->gpr[9],
42 -1, -1);
43 if (ret == -QEMU_ERESTARTSYS) {
44 env->pc -= 4;
45 break;
46 }
47 if (ret == -QEMU_ESIGRETURN) {
48 /*
49 * Returning from a successful sigreturn syscall.
50 * Avoid clobbering register state.
51 */
52 break;
53 }
54 env->gpr[4] = ret;
55 break;
56 case EXCCODE_INE:
57 force_sig_fault(TARGET_SIGILL, 0, env->pc);
58 break;
59 case EXCCODE_FPE:
60 si_code = TARGET_FPE_FLTUNK;
61 if (GET_FP_CAUSE(env->fcsr0) & FP_INVALID) {
62 si_code = TARGET_FPE_FLTINV;
63 } else if (GET_FP_CAUSE(env->fcsr0) & FP_DIV0) {
64 si_code = TARGET_FPE_FLTDIV;
65 } else if (GET_FP_CAUSE(env->fcsr0) & FP_OVERFLOW) {
66 si_code = TARGET_FPE_FLTOVF;
67 } else if (GET_FP_CAUSE(env->fcsr0) & FP_UNDERFLOW) {
68 si_code = TARGET_FPE_FLTUND;
69 } else if (GET_FP_CAUSE(env->fcsr0) & FP_INEXACT) {
70 si_code = TARGET_FPE_FLTRES;
71 }
72 force_sig_fault(TARGET_SIGFPE, si_code, env->pc);
73 break;
74 case EXCP_DEBUG:
75 force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
76 break;
77 case EXCCODE_BRK:
78 {
79 unsigned int opcode;
80
81 get_user_u32(opcode, env->pc);
82
83 switch (opcode & 0x7fff) {
84 case BRK_OVERFLOW:
85 force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTOVF, env->pc);
86 break;
87 case BRK_DIVZERO:
88 force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTDIV, env->pc);
89 break;
90 default:
91 force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
92 }
93 }
94 break;
95 case EXCCODE_BCE:
96 force_sig_fault(TARGET_SIGSYS, TARGET_SI_KERNEL, env->pc);
97 break;
98
99 /*
100 * Begin with LSX and LASX disabled, then enable on the first trap.
101 * In this way we can tell if the unit is in use. This is used to
102 * choose the layout of any signal frame.
103 */
104 case EXCCODE_SXD:
105 env->CSR_EUEN |= R_CSR_EUEN_SXE_MASK;
106 break;
107 case EXCCODE_ASXD:
108 env->CSR_EUEN |= R_CSR_EUEN_ASXE_MASK;
109 break;
110
111 case EXCP_ATOMIC:
112 cpu_exec_step_atomic(cs);
113 break;
114 default:
115 EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n",
116 trapnr);
117 exit(EXIT_FAILURE);
118 }
119 process_pending_signals(env);
120 }
121 }
122
target_cpu_copy_regs(CPUArchState * env,target_pt_regs * regs)123 void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs)
124 {
125 int i;
126
127 for (i = 0; i < 32; i++) {
128 env->gpr[i] = regs->regs[i];
129 }
130 env->pc = regs->csr.era;
131
132 }
133