target/mips: Extract FPU helpers to 'fpu_helper.h'
[qemu/kevin.git] / linux-user / mips / cpu_loop.c
blob9d813ece4e75a0537ef79c544d8b37bdc34d994a
1 /*
2 * qemu user cpu loop
4 * Copyright (c) 2003-2008 Fabrice Bellard
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include "qemu/osdep.h"
21 #include "qemu-common.h"
22 #include "qemu.h"
23 #include "cpu_loop-common.h"
24 #include "elf.h"
25 #include "internal.h"
26 #include "fpu_helper.h"
28 # ifdef TARGET_ABI_MIPSO32
29 # define MIPS_SYSCALL_NUMBER_UNUSED -1
30 static const int8_t mips_syscall_args[] = {
31 #include "syscall-args-o32.c.inc"
33 # endif /* O32 */
35 /* Break codes */
36 enum {
37 BRK_OVERFLOW = 6,
38 BRK_DIVZERO = 7
41 static int do_break(CPUMIPSState *env, target_siginfo_t *info,
42 unsigned int code)
44 int ret = -1;
46 switch (code) {
47 case BRK_OVERFLOW:
48 case BRK_DIVZERO:
49 info->si_signo = TARGET_SIGFPE;
50 info->si_errno = 0;
51 info->si_code = (code == BRK_OVERFLOW) ? FPE_INTOVF : FPE_INTDIV;
52 queue_signal(env, info->si_signo, QEMU_SI_FAULT, &*info);
53 ret = 0;
54 break;
55 default:
56 info->si_signo = TARGET_SIGTRAP;
57 info->si_errno = 0;
58 queue_signal(env, info->si_signo, QEMU_SI_FAULT, &*info);
59 ret = 0;
60 break;
63 return ret;
66 void cpu_loop(CPUMIPSState *env)
68 CPUState *cs = env_cpu(env);
69 target_siginfo_t info;
70 int trapnr;
71 abi_long ret;
72 # ifdef TARGET_ABI_MIPSO32
73 unsigned int syscall_num;
74 # endif
76 for(;;) {
77 cpu_exec_start(cs);
78 trapnr = cpu_exec(cs);
79 cpu_exec_end(cs);
80 process_queued_cpu_work(cs);
82 switch(trapnr) {
83 case EXCP_SYSCALL:
84 env->active_tc.PC += 4;
85 # ifdef TARGET_ABI_MIPSO32
86 syscall_num = env->active_tc.gpr[2] - 4000;
87 if (syscall_num >= sizeof(mips_syscall_args)) {
88 /* syscall_num is larger that any defined for MIPS O32 */
89 ret = -TARGET_ENOSYS;
90 } else if (mips_syscall_args[syscall_num] ==
91 MIPS_SYSCALL_NUMBER_UNUSED) {
92 /* syscall_num belongs to the range not defined for MIPS O32 */
93 ret = -TARGET_ENOSYS;
94 } else {
95 /* syscall_num is valid */
96 int nb_args;
97 abi_ulong sp_reg;
98 abi_ulong arg5 = 0, arg6 = 0, arg7 = 0, arg8 = 0;
100 nb_args = mips_syscall_args[syscall_num];
101 sp_reg = env->active_tc.gpr[29];
102 switch (nb_args) {
103 /* these arguments are taken from the stack */
104 case 8:
105 if ((ret = get_user_ual(arg8, sp_reg + 28)) != 0) {
106 goto done_syscall;
108 /* fall through */
109 case 7:
110 if ((ret = get_user_ual(arg7, sp_reg + 24)) != 0) {
111 goto done_syscall;
113 /* fall through */
114 case 6:
115 if ((ret = get_user_ual(arg6, sp_reg + 20)) != 0) {
116 goto done_syscall;
118 /* fall through */
119 case 5:
120 if ((ret = get_user_ual(arg5, sp_reg + 16)) != 0) {
121 goto done_syscall;
123 /* fall through */
124 default:
125 break;
127 ret = do_syscall(env, env->active_tc.gpr[2],
128 env->active_tc.gpr[4],
129 env->active_tc.gpr[5],
130 env->active_tc.gpr[6],
131 env->active_tc.gpr[7],
132 arg5, arg6, arg7, arg8);
134 done_syscall:
135 # else
136 ret = do_syscall(env, env->active_tc.gpr[2],
137 env->active_tc.gpr[4], env->active_tc.gpr[5],
138 env->active_tc.gpr[6], env->active_tc.gpr[7],
139 env->active_tc.gpr[8], env->active_tc.gpr[9],
140 env->active_tc.gpr[10], env->active_tc.gpr[11]);
141 # endif /* O32 */
142 if (ret == -TARGET_ERESTARTSYS) {
143 env->active_tc.PC -= 4;
144 break;
146 if (ret == -TARGET_QEMU_ESIGRETURN) {
147 /* Returning from a successful sigreturn syscall.
148 Avoid clobbering register state. */
149 break;
151 if ((abi_ulong)ret >= (abi_ulong)-1133) {
152 env->active_tc.gpr[7] = 1; /* error flag */
153 ret = -ret;
154 } else {
155 env->active_tc.gpr[7] = 0; /* error flag */
157 env->active_tc.gpr[2] = ret;
158 break;
159 case EXCP_TLBL:
160 case EXCP_TLBS:
161 case EXCP_AdEL:
162 case EXCP_AdES:
163 info.si_signo = TARGET_SIGSEGV;
164 info.si_errno = 0;
165 /* XXX: check env->error_code */
166 info.si_code = TARGET_SEGV_MAPERR;
167 info._sifields._sigfault._addr = env->CP0_BadVAddr;
168 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
169 break;
170 case EXCP_CpU:
171 case EXCP_RI:
172 info.si_signo = TARGET_SIGILL;
173 info.si_errno = 0;
174 info.si_code = 0;
175 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
176 break;
177 case EXCP_INTERRUPT:
178 /* just indicate that signals should be handled asap */
179 break;
180 case EXCP_DEBUG:
181 info.si_signo = TARGET_SIGTRAP;
182 info.si_errno = 0;
183 info.si_code = TARGET_TRAP_BRKPT;
184 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
185 break;
186 case EXCP_DSPDIS:
187 info.si_signo = TARGET_SIGILL;
188 info.si_errno = 0;
189 info.si_code = TARGET_ILL_ILLOPC;
190 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
191 break;
192 case EXCP_FPE:
193 info.si_signo = TARGET_SIGFPE;
194 info.si_errno = 0;
195 info.si_code = TARGET_FPE_FLTUNK;
196 if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) {
197 info.si_code = TARGET_FPE_FLTINV;
198 } else if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_DIV0) {
199 info.si_code = TARGET_FPE_FLTDIV;
200 } else if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_OVERFLOW) {
201 info.si_code = TARGET_FPE_FLTOVF;
202 } else if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_UNDERFLOW) {
203 info.si_code = TARGET_FPE_FLTUND;
204 } else if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INEXACT) {
205 info.si_code = TARGET_FPE_FLTRES;
207 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
208 break;
209 /* The code below was inspired by the MIPS Linux kernel trap
210 * handling code in arch/mips/kernel/traps.c.
212 case EXCP_BREAK:
214 abi_ulong trap_instr;
215 unsigned int code;
217 if (env->hflags & MIPS_HFLAG_M16) {
218 if (env->insn_flags & ASE_MICROMIPS) {
219 /* microMIPS mode */
220 ret = get_user_u16(trap_instr, env->active_tc.PC);
221 if (ret != 0) {
222 goto error;
225 if ((trap_instr >> 10) == 0x11) {
226 /* 16-bit instruction */
227 code = trap_instr & 0xf;
228 } else {
229 /* 32-bit instruction */
230 abi_ulong instr_lo;
232 ret = get_user_u16(instr_lo,
233 env->active_tc.PC + 2);
234 if (ret != 0) {
235 goto error;
237 trap_instr = (trap_instr << 16) | instr_lo;
238 code = ((trap_instr >> 6) & ((1 << 20) - 1));
239 /* Unfortunately, microMIPS also suffers from
240 the old assembler bug... */
241 if (code >= (1 << 10)) {
242 code >>= 10;
245 } else {
246 /* MIPS16e mode */
247 ret = get_user_u16(trap_instr, env->active_tc.PC);
248 if (ret != 0) {
249 goto error;
251 code = (trap_instr >> 6) & 0x3f;
253 } else {
254 ret = get_user_u32(trap_instr, env->active_tc.PC);
255 if (ret != 0) {
256 goto error;
259 /* As described in the original Linux kernel code, the
260 * below checks on 'code' are to work around an old
261 * assembly bug.
263 code = ((trap_instr >> 6) & ((1 << 20) - 1));
264 if (code >= (1 << 10)) {
265 code >>= 10;
269 if (do_break(env, &info, code) != 0) {
270 goto error;
273 break;
274 case EXCP_TRAP:
276 abi_ulong trap_instr;
277 unsigned int code = 0;
279 if (env->hflags & MIPS_HFLAG_M16) {
280 /* microMIPS mode */
281 abi_ulong instr[2];
283 ret = get_user_u16(instr[0], env->active_tc.PC) ||
284 get_user_u16(instr[1], env->active_tc.PC + 2);
286 trap_instr = (instr[0] << 16) | instr[1];
287 } else {
288 ret = get_user_u32(trap_instr, env->active_tc.PC);
291 if (ret != 0) {
292 goto error;
295 /* The immediate versions don't provide a code. */
296 if (!(trap_instr & 0xFC000000)) {
297 if (env->hflags & MIPS_HFLAG_M16) {
298 /* microMIPS mode */
299 code = ((trap_instr >> 12) & ((1 << 4) - 1));
300 } else {
301 code = ((trap_instr >> 6) & ((1 << 10) - 1));
305 if (do_break(env, &info, code) != 0) {
306 goto error;
309 break;
310 case EXCP_ATOMIC:
311 cpu_exec_step_atomic(cs);
312 break;
313 default:
314 error:
315 EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
316 abort();
318 process_pending_signals(env);
322 void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
324 CPUState *cpu = env_cpu(env);
325 TaskState *ts = cpu->opaque;
326 struct image_info *info = ts->info;
327 int i;
329 struct mode_req {
330 bool single;
331 bool soft;
332 bool fr1;
333 bool frdefault;
334 bool fre;
337 static const struct mode_req fpu_reqs[] = {
338 [MIPS_ABI_FP_ANY] = { true, true, true, true, true },
339 [MIPS_ABI_FP_DOUBLE] = { false, false, false, true, true },
340 [MIPS_ABI_FP_SINGLE] = { true, false, false, false, false },
341 [MIPS_ABI_FP_SOFT] = { false, true, false, false, false },
342 [MIPS_ABI_FP_OLD_64] = { false, false, false, false, false },
343 [MIPS_ABI_FP_XX] = { false, false, true, true, true },
344 [MIPS_ABI_FP_64] = { false, false, true, false, false },
345 [MIPS_ABI_FP_64A] = { false, false, true, false, true }
349 * Mode requirements when .MIPS.abiflags is not present in the ELF.
350 * Not present means that everything is acceptable except FR1.
352 static struct mode_req none_req = { true, true, false, true, true };
354 struct mode_req prog_req;
355 struct mode_req interp_req;
357 for(i = 0; i < 32; i++) {
358 env->active_tc.gpr[i] = regs->regs[i];
360 env->active_tc.PC = regs->cp0_epc & ~(target_ulong)1;
361 if (regs->cp0_epc & 1) {
362 env->hflags |= MIPS_HFLAG_M16;
365 #ifdef TARGET_ABI_MIPSO32
366 # define MAX_FP_ABI MIPS_ABI_FP_64A
367 #else
368 # define MAX_FP_ABI MIPS_ABI_FP_SOFT
369 #endif
370 if ((info->fp_abi > MAX_FP_ABI && info->fp_abi != MIPS_ABI_FP_UNKNOWN)
371 || (info->interp_fp_abi > MAX_FP_ABI &&
372 info->interp_fp_abi != MIPS_ABI_FP_UNKNOWN)) {
373 fprintf(stderr, "qemu: Unexpected FPU mode\n");
374 exit(1);
377 prog_req = (info->fp_abi == MIPS_ABI_FP_UNKNOWN) ? none_req
378 : fpu_reqs[info->fp_abi];
379 interp_req = (info->interp_fp_abi == MIPS_ABI_FP_UNKNOWN) ? none_req
380 : fpu_reqs[info->interp_fp_abi];
382 prog_req.single &= interp_req.single;
383 prog_req.soft &= interp_req.soft;
384 prog_req.fr1 &= interp_req.fr1;
385 prog_req.frdefault &= interp_req.frdefault;
386 prog_req.fre &= interp_req.fre;
388 bool cpu_has_mips_r2_r6 = env->insn_flags & ISA_MIPS_R2 ||
389 env->insn_flags & ISA_MIPS_R6;
391 if (prog_req.fre && !prog_req.frdefault && !prog_req.fr1) {
392 env->CP0_Config5 |= (1 << CP0C5_FRE);
393 if (env->active_fpu.fcr0 & (1 << FCR0_FREP)) {
394 env->hflags |= MIPS_HFLAG_FRE;
396 } else if ((prog_req.fr1 && prog_req.frdefault) ||
397 (prog_req.single && !prog_req.frdefault)) {
398 if ((env->active_fpu.fcr0 & (1 << FCR0_F64)
399 && cpu_has_mips_r2_r6) || prog_req.fr1) {
400 env->CP0_Status |= (1 << CP0St_FR);
401 env->hflags |= MIPS_HFLAG_F64;
403 } else if (!prog_req.fre && !prog_req.frdefault &&
404 !prog_req.fr1 && !prog_req.single && !prog_req.soft) {
405 fprintf(stderr, "qemu: Can't find a matching FPU mode\n");
406 exit(1);
409 if (env->insn_flags & ISA_NANOMIPS32) {
410 return;
412 if (((info->elf_flags & EF_MIPS_NAN2008) != 0) !=
413 ((env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) != 0)) {
414 if ((env->active_fpu.fcr31_rw_bitmask &
415 (1 << FCR31_NAN2008)) == 0) {
416 fprintf(stderr, "ELF binary's NaN mode not supported by CPU\n");
417 exit(1);
419 if ((info->elf_flags & EF_MIPS_NAN2008) != 0) {
420 env->active_fpu.fcr31 |= (1 << FCR31_NAN2008);
421 } else {
422 env->active_fpu.fcr31 &= ~(1 << FCR31_NAN2008);
424 restore_snan_bit_mode(env);