xref: /openbmc/qemu/linux-user/mips/cpu_loop.c (revision 831734cc)
1 /*
2  *  qemu user cpu loop
3  *
4  *  Copyright (c) 2003-2008 Fabrice Bellard
5  *
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.
10  *
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.
15  *
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/>.
18  */
19 
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"
27 
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"
32 };
33 # endif /* O32 */
34 
35 /* Break codes */
36 enum {
37     BRK_OVERFLOW = 6,
38     BRK_DIVZERO = 7
39 };
40 
41 static int do_break(CPUMIPSState *env, target_siginfo_t *info,
42                     unsigned int code)
43 {
44     int ret = -1;
45 
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;
61     }
62 
63     return ret;
64 }
65 
66 void cpu_loop(CPUMIPSState *env)
67 {
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
75 
76     for(;;) {
77         cpu_exec_start(cs);
78         trapnr = cpu_exec(cs);
79         cpu_exec_end(cs);
80         process_queued_cpu_work(cs);
81 
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;
99 
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;
107                     }
108                     /* fall through */
109                 case 7:
110                     if ((ret = get_user_ual(arg7, sp_reg + 24)) != 0) {
111                         goto done_syscall;
112                     }
113                     /* fall through */
114                 case 6:
115                     if ((ret = get_user_ual(arg6, sp_reg + 20)) != 0) {
116                         goto done_syscall;
117                     }
118                     /* fall through */
119                 case 5:
120                     if ((ret = get_user_ual(arg5, sp_reg + 16)) != 0) {
121                         goto done_syscall;
122                     }
123                     /* fall through */
124                 default:
125                     break;
126                 }
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);
133             }
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;
145             }
146             if (ret == -TARGET_QEMU_ESIGRETURN) {
147                 /* Returning from a successful sigreturn syscall.
148                    Avoid clobbering register state.  */
149                 break;
150             }
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 */
156             }
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;
206             }
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.
211          */
212         case EXCP_BREAK:
213             {
214                 abi_ulong trap_instr;
215                 unsigned int code;
216 
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;
223                         }
224 
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;
231 
232                             ret = get_user_u16(instr_lo,
233                                                env->active_tc.PC + 2);
234                             if (ret != 0) {
235                                 goto error;
236                             }
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;
243                             }
244                         }
245                     } else {
246                         /* MIPS16e mode */
247                         ret = get_user_u16(trap_instr, env->active_tc.PC);
248                         if (ret != 0) {
249                             goto error;
250                         }
251                         code = (trap_instr >> 6) & 0x3f;
252                     }
253                 } else {
254                     ret = get_user_u32(trap_instr, env->active_tc.PC);
255                     if (ret != 0) {
256                         goto error;
257                     }
258 
259                     /* As described in the original Linux kernel code, the
260                      * below checks on 'code' are to work around an old
261                      * assembly bug.
262                      */
263                     code = ((trap_instr >> 6) & ((1 << 20) - 1));
264                     if (code >= (1 << 10)) {
265                         code >>= 10;
266                     }
267                 }
268 
269                 if (do_break(env, &info, code) != 0) {
270                     goto error;
271                 }
272             }
273             break;
274         case EXCP_TRAP:
275             {
276                 abi_ulong trap_instr;
277                 unsigned int code = 0;
278 
279                 if (env->hflags & MIPS_HFLAG_M16) {
280                     /* microMIPS mode */
281                     abi_ulong instr[2];
282 
283                     ret = get_user_u16(instr[0], env->active_tc.PC) ||
284                           get_user_u16(instr[1], env->active_tc.PC + 2);
285 
286                     trap_instr = (instr[0] << 16) | instr[1];
287                 } else {
288                     ret = get_user_u32(trap_instr, env->active_tc.PC);
289                 }
290 
291                 if (ret != 0) {
292                     goto error;
293                 }
294 
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));
302                     }
303                 }
304 
305                 if (do_break(env, &info, code) != 0) {
306                     goto error;
307                 }
308             }
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();
317         }
318         process_pending_signals(env);
319     }
320 }
321 
322 void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
323 {
324     CPUState *cpu = env_cpu(env);
325     TaskState *ts = cpu->opaque;
326     struct image_info *info = ts->info;
327     int i;
328 
329     struct mode_req {
330         bool single;
331         bool soft;
332         bool fr1;
333         bool frdefault;
334         bool fre;
335     };
336 
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  }
346     };
347 
348     /*
349      * Mode requirements when .MIPS.abiflags is not present in the ELF.
350      * Not present means that everything is acceptable except FR1.
351      */
352     static struct mode_req none_req = { true, true, false, true, true };
353 
354     struct mode_req prog_req;
355     struct mode_req interp_req;
356 
357     for(i = 0; i < 32; i++) {
358         env->active_tc.gpr[i] = regs->regs[i];
359     }
360     env->active_tc.PC = regs->cp0_epc & ~(target_ulong)1;
361     if (regs->cp0_epc & 1) {
362         env->hflags |= MIPS_HFLAG_M16;
363     }
364 
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);
375     }
376 
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];
381 
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;
387 
388     bool cpu_has_mips_r2_r6 = env->insn_flags & ISA_MIPS_R2 ||
389                               env->insn_flags & ISA_MIPS_R6;
390 
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;
395         }
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;
402         }
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);
407     }
408 
409     if (env->insn_flags & ISA_NANOMIPS32) {
410         return;
411     }
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);
418         }
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);
423         }
424         restore_snan_bit_mode(env);
425     }
426 }
427