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"
22 #include "user-internals.h"
23 #include "cpu_loop-common.h"
24 #include "signal-common.h"
27 #include "fpu_helper.h"
29 # ifdef TARGET_ABI_MIPSO32
30 # define MIPS_SYSCALL_NUMBER_UNUSED -1
31 static const int8_t mips_syscall_args
[] = {
32 #include "syscall-args-o32.c.inc"
42 static void do_tr_or_bp(CPUMIPSState
*env
, unsigned int code
, bool trap
)
44 target_ulong pc
= env
->active_tc
.PC
;
48 force_sig_fault(TARGET_SIGFPE
, TARGET_FPE_INTOVF
, pc
);
51 force_sig_fault(TARGET_SIGFPE
, TARGET_FPE_INTDIV
, pc
);
55 force_sig(TARGET_SIGTRAP
);
57 force_sig_fault(TARGET_SIGTRAP
, TARGET_TRAP_BRKPT
, pc
);
63 void cpu_loop(CPUMIPSState
*env
)
65 CPUState
*cs
= env_cpu(env
);
69 # ifdef TARGET_ABI_MIPSO32
70 unsigned int syscall_num
;
75 trapnr
= cpu_exec(cs
);
77 process_queued_cpu_work(cs
);
81 env
->active_tc
.PC
+= 4;
82 # ifdef TARGET_ABI_MIPSO32
83 syscall_num
= env
->active_tc
.gpr
[2] - 4000;
84 if (syscall_num
>= sizeof(mips_syscall_args
)) {
85 /* syscall_num is larger that any defined for MIPS O32 */
87 } else if (mips_syscall_args
[syscall_num
] ==
88 MIPS_SYSCALL_NUMBER_UNUSED
) {
89 /* syscall_num belongs to the range not defined for MIPS O32 */
92 /* syscall_num is valid */
95 abi_ulong arg5
= 0, arg6
= 0, arg7
= 0, arg8
= 0;
97 nb_args
= mips_syscall_args
[syscall_num
];
98 sp_reg
= env
->active_tc
.gpr
[29];
100 /* these arguments are taken from the stack */
102 if ((ret
= get_user_ual(arg8
, sp_reg
+ 28)) != 0) {
107 if ((ret
= get_user_ual(arg7
, sp_reg
+ 24)) != 0) {
112 if ((ret
= get_user_ual(arg6
, sp_reg
+ 20)) != 0) {
117 if ((ret
= get_user_ual(arg5
, sp_reg
+ 16)) != 0) {
124 ret
= do_syscall(env
, env
->active_tc
.gpr
[2],
125 env
->active_tc
.gpr
[4],
126 env
->active_tc
.gpr
[5],
127 env
->active_tc
.gpr
[6],
128 env
->active_tc
.gpr
[7],
129 arg5
, arg6
, arg7
, arg8
);
133 ret
= do_syscall(env
, env
->active_tc
.gpr
[2],
134 env
->active_tc
.gpr
[4], env
->active_tc
.gpr
[5],
135 env
->active_tc
.gpr
[6], env
->active_tc
.gpr
[7],
136 env
->active_tc
.gpr
[8], env
->active_tc
.gpr
[9],
137 env
->active_tc
.gpr
[10], env
->active_tc
.gpr
[11]);
139 if (ret
== -QEMU_ERESTARTSYS
) {
140 env
->active_tc
.PC
-= 4;
143 if (ret
== -QEMU_ESIGRETURN
) {
144 /* Returning from a successful sigreturn syscall.
145 Avoid clobbering register state. */
148 if ((abi_ulong
)ret
>= (abi_ulong
)-1133) {
149 env
->active_tc
.gpr
[7] = 1; /* error flag */
152 env
->active_tc
.gpr
[7] = 0; /* error flag */
154 env
->active_tc
.gpr
[2] = ret
;
159 force_sig(TARGET_SIGILL
);
162 /* just indicate that signals should be handled asap */
165 force_sig_fault(TARGET_SIGTRAP
, TARGET_TRAP_BRKPT
,
169 si_code
= TARGET_FPE_FLTUNK
;
170 if (GET_FP_CAUSE(env
->active_fpu
.fcr31
) & FP_INVALID
) {
171 si_code
= TARGET_FPE_FLTINV
;
172 } else if (GET_FP_CAUSE(env
->active_fpu
.fcr31
) & FP_DIV0
) {
173 si_code
= TARGET_FPE_FLTDIV
;
174 } else if (GET_FP_CAUSE(env
->active_fpu
.fcr31
) & FP_OVERFLOW
) {
175 si_code
= TARGET_FPE_FLTOVF
;
176 } else if (GET_FP_CAUSE(env
->active_fpu
.fcr31
) & FP_UNDERFLOW
) {
177 si_code
= TARGET_FPE_FLTUND
;
178 } else if (GET_FP_CAUSE(env
->active_fpu
.fcr31
) & FP_INEXACT
) {
179 si_code
= TARGET_FPE_FLTRES
;
181 force_sig_fault(TARGET_SIGFPE
, si_code
, env
->active_tc
.PC
);
184 /* The code below was inspired by the MIPS Linux kernel trap
185 * handling code in arch/mips/kernel/traps.c.
189 * As described in the original Linux kernel code, the below
190 * checks on 'code' are to work around an old assembly bug.
192 code
= env
->error_code
;
193 if (code
>= (1 << 10)) {
196 do_tr_or_bp(env
, code
, false);
199 do_tr_or_bp(env
, env
->error_code
, true);
202 cpu_exec_step_atomic(cs
);
205 EXCP_DUMP(env
, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr
);
208 process_pending_signals(env
);
212 void target_cpu_copy_regs(CPUArchState
*env
, struct target_pt_regs
*regs
)
214 CPUState
*cpu
= env_cpu(env
);
215 TaskState
*ts
= cpu
->opaque
;
216 struct image_info
*info
= ts
->info
;
227 static const struct mode_req fpu_reqs
[] = {
228 [MIPS_ABI_FP_ANY
] = { true, true, true, true, true },
229 [MIPS_ABI_FP_DOUBLE
] = { false, false, false, true, true },
230 [MIPS_ABI_FP_SINGLE
] = { true, false, false, false, false },
231 [MIPS_ABI_FP_SOFT
] = { false, true, false, false, false },
232 [MIPS_ABI_FP_OLD_64
] = { false, false, false, false, false },
233 [MIPS_ABI_FP_XX
] = { false, false, true, true, true },
234 [MIPS_ABI_FP_64
] = { false, false, true, false, false },
235 [MIPS_ABI_FP_64A
] = { false, false, true, false, true }
239 * Mode requirements when .MIPS.abiflags is not present in the ELF.
240 * Not present means that everything is acceptable except FR1.
242 static struct mode_req none_req
= { true, true, false, true, true };
244 struct mode_req prog_req
;
245 struct mode_req interp_req
;
247 for(i
= 0; i
< 32; i
++) {
248 env
->active_tc
.gpr
[i
] = regs
->regs
[i
];
250 env
->active_tc
.PC
= regs
->cp0_epc
& ~(target_ulong
)1;
251 if (regs
->cp0_epc
& 1) {
252 env
->hflags
|= MIPS_HFLAG_M16
;
255 #ifdef TARGET_ABI_MIPSO32
256 # define MAX_FP_ABI MIPS_ABI_FP_64A
258 # define MAX_FP_ABI MIPS_ABI_FP_SOFT
260 if ((info
->fp_abi
> MAX_FP_ABI
&& info
->fp_abi
!= MIPS_ABI_FP_UNKNOWN
)
261 || (info
->interp_fp_abi
> MAX_FP_ABI
&&
262 info
->interp_fp_abi
!= MIPS_ABI_FP_UNKNOWN
)) {
263 fprintf(stderr
, "qemu: Unexpected FPU mode\n");
267 prog_req
= (info
->fp_abi
== MIPS_ABI_FP_UNKNOWN
) ? none_req
268 : fpu_reqs
[info
->fp_abi
];
269 interp_req
= (info
->interp_fp_abi
== MIPS_ABI_FP_UNKNOWN
) ? none_req
270 : fpu_reqs
[info
->interp_fp_abi
];
272 prog_req
.single
&= interp_req
.single
;
273 prog_req
.soft
&= interp_req
.soft
;
274 prog_req
.fr1
&= interp_req
.fr1
;
275 prog_req
.frdefault
&= interp_req
.frdefault
;
276 prog_req
.fre
&= interp_req
.fre
;
278 bool cpu_has_mips_r2_r6
= env
->insn_flags
& ISA_MIPS_R2
||
279 env
->insn_flags
& ISA_MIPS_R6
;
281 if (prog_req
.fre
&& !prog_req
.frdefault
&& !prog_req
.fr1
) {
282 env
->CP0_Config5
|= (1 << CP0C5_FRE
);
283 if (env
->active_fpu
.fcr0
& (1 << FCR0_FREP
)) {
284 env
->hflags
|= MIPS_HFLAG_FRE
;
286 } else if ((prog_req
.fr1
&& prog_req
.frdefault
) ||
287 (prog_req
.single
&& !prog_req
.frdefault
)) {
288 if ((env
->active_fpu
.fcr0
& (1 << FCR0_F64
)
289 && cpu_has_mips_r2_r6
) || prog_req
.fr1
) {
290 env
->CP0_Status
|= (1 << CP0St_FR
);
291 env
->hflags
|= MIPS_HFLAG_F64
;
293 } else if (prog_req
.fr1
) {
294 env
->CP0_Status
|= (1 << CP0St_FR
);
295 env
->hflags
|= MIPS_HFLAG_F64
;
296 } else if (!prog_req
.fre
&& !prog_req
.frdefault
&&
297 !prog_req
.fr1
&& !prog_req
.single
&& !prog_req
.soft
) {
298 fprintf(stderr
, "qemu: Can't find a matching FPU mode\n");
302 if (env
->insn_flags
& ISA_NANOMIPS32
) {
305 if (((info
->elf_flags
& EF_MIPS_NAN2008
) != 0) !=
306 ((env
->active_fpu
.fcr31
& (1 << FCR31_NAN2008
)) != 0)) {
307 if ((env
->active_fpu
.fcr31_rw_bitmask
&
308 (1 << FCR31_NAN2008
)) == 0) {
309 fprintf(stderr
, "ELF binary's NaN mode not supported by CPU\n");
312 if ((info
->elf_flags
& EF_MIPS_NAN2008
) != 0) {
313 env
->active_fpu
.fcr31
|= (1 << FCR31_NAN2008
);
315 env
->active_fpu
.fcr31
&= ~(1 << FCR31_NAN2008
);
317 restore_snan_bit_mode(env
);