xref: /openbmc/qemu/linux-user/mips/cpu_loop.c (revision ae4c2099)
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 "user-internals.h"
24 #include "cpu_loop-common.h"
25 #include "signal-common.h"
26 #include "elf.h"
27 #include "internal.h"
28 #include "fpu_helper.h"
29 
30 # ifdef TARGET_ABI_MIPSO32
31 #  define MIPS_SYSCALL_NUMBER_UNUSED -1
32 static const int8_t mips_syscall_args[] = {
33 #include "syscall-args-o32.c.inc"
34 };
35 # endif /* O32 */
36 
37 /* Break codes */
38 enum {
39     BRK_OVERFLOW = 6,
40     BRK_DIVZERO = 7
41 };
42 
43 static int do_break(CPUMIPSState *env, target_siginfo_t *info,
44                     unsigned int code)
45 {
46     int ret = -1;
47 
48     switch (code) {
49     case BRK_OVERFLOW:
50     case BRK_DIVZERO:
51         info->si_signo = TARGET_SIGFPE;
52         info->si_errno = 0;
53         info->si_code = (code == BRK_OVERFLOW) ? FPE_INTOVF : FPE_INTDIV;
54         queue_signal(env, info->si_signo, QEMU_SI_FAULT, &*info);
55         ret = 0;
56         break;
57     default:
58         info->si_signo = TARGET_SIGTRAP;
59         info->si_errno = 0;
60         queue_signal(env, info->si_signo, QEMU_SI_FAULT, &*info);
61         ret = 0;
62         break;
63     }
64 
65     return ret;
66 }
67 
68 void cpu_loop(CPUMIPSState *env)
69 {
70     CPUState *cs = env_cpu(env);
71     target_siginfo_t info;
72     int trapnr;
73     abi_long ret;
74 # ifdef TARGET_ABI_MIPSO32
75     unsigned int syscall_num;
76 # endif
77 
78     for(;;) {
79         cpu_exec_start(cs);
80         trapnr = cpu_exec(cs);
81         cpu_exec_end(cs);
82         process_queued_cpu_work(cs);
83 
84         switch(trapnr) {
85         case EXCP_SYSCALL:
86             env->active_tc.PC += 4;
87 # ifdef TARGET_ABI_MIPSO32
88             syscall_num = env->active_tc.gpr[2] - 4000;
89             if (syscall_num >= sizeof(mips_syscall_args)) {
90                 /* syscall_num is larger that any defined for MIPS O32 */
91                 ret = -TARGET_ENOSYS;
92             } else if (mips_syscall_args[syscall_num] ==
93                        MIPS_SYSCALL_NUMBER_UNUSED) {
94                 /* syscall_num belongs to the range not defined for MIPS O32 */
95                 ret = -TARGET_ENOSYS;
96             } else {
97                 /* syscall_num is valid */
98                 int nb_args;
99                 abi_ulong sp_reg;
100                 abi_ulong arg5 = 0, arg6 = 0, arg7 = 0, arg8 = 0;
101 
102                 nb_args = mips_syscall_args[syscall_num];
103                 sp_reg = env->active_tc.gpr[29];
104                 switch (nb_args) {
105                 /* these arguments are taken from the stack */
106                 case 8:
107                     if ((ret = get_user_ual(arg8, sp_reg + 28)) != 0) {
108                         goto done_syscall;
109                     }
110                     /* fall through */
111                 case 7:
112                     if ((ret = get_user_ual(arg7, sp_reg + 24)) != 0) {
113                         goto done_syscall;
114                     }
115                     /* fall through */
116                 case 6:
117                     if ((ret = get_user_ual(arg6, sp_reg + 20)) != 0) {
118                         goto done_syscall;
119                     }
120                     /* fall through */
121                 case 5:
122                     if ((ret = get_user_ual(arg5, sp_reg + 16)) != 0) {
123                         goto done_syscall;
124                     }
125                     /* fall through */
126                 default:
127                     break;
128                 }
129                 ret = do_syscall(env, env->active_tc.gpr[2],
130                                  env->active_tc.gpr[4],
131                                  env->active_tc.gpr[5],
132                                  env->active_tc.gpr[6],
133                                  env->active_tc.gpr[7],
134                                  arg5, arg6, arg7, arg8);
135             }
136 done_syscall:
137 # else
138             ret = do_syscall(env, env->active_tc.gpr[2],
139                              env->active_tc.gpr[4], env->active_tc.gpr[5],
140                              env->active_tc.gpr[6], env->active_tc.gpr[7],
141                              env->active_tc.gpr[8], env->active_tc.gpr[9],
142                              env->active_tc.gpr[10], env->active_tc.gpr[11]);
143 # endif /* O32 */
144             if (ret == -TARGET_ERESTARTSYS) {
145                 env->active_tc.PC -= 4;
146                 break;
147             }
148             if (ret == -TARGET_QEMU_ESIGRETURN) {
149                 /* Returning from a successful sigreturn syscall.
150                    Avoid clobbering register state.  */
151                 break;
152             }
153             if ((abi_ulong)ret >= (abi_ulong)-1133) {
154                 env->active_tc.gpr[7] = 1; /* error flag */
155                 ret = -ret;
156             } else {
157                 env->active_tc.gpr[7] = 0; /* error flag */
158             }
159             env->active_tc.gpr[2] = ret;
160             break;
161         case EXCP_CpU:
162         case EXCP_RI:
163             info.si_signo = TARGET_SIGILL;
164             info.si_errno = 0;
165             info.si_code = 0;
166             queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
167             break;
168         case EXCP_INTERRUPT:
169             /* just indicate that signals should be handled asap */
170             break;
171         case EXCP_DEBUG:
172             info.si_signo = TARGET_SIGTRAP;
173             info.si_errno = 0;
174             info.si_code = TARGET_TRAP_BRKPT;
175             queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
176             break;
177         case EXCP_DSPDIS:
178             info.si_signo = TARGET_SIGILL;
179             info.si_errno = 0;
180             info.si_code = TARGET_ILL_ILLOPC;
181             queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
182             break;
183         case EXCP_FPE:
184             info.si_signo = TARGET_SIGFPE;
185             info.si_errno = 0;
186             info.si_code = TARGET_FPE_FLTUNK;
187             if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) {
188                 info.si_code = TARGET_FPE_FLTINV;
189             } else if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_DIV0) {
190                 info.si_code = TARGET_FPE_FLTDIV;
191             } else if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_OVERFLOW) {
192                 info.si_code = TARGET_FPE_FLTOVF;
193             } else if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_UNDERFLOW) {
194                 info.si_code = TARGET_FPE_FLTUND;
195             } else if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INEXACT) {
196                 info.si_code = TARGET_FPE_FLTRES;
197             }
198             queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
199             break;
200         /* The code below was inspired by the MIPS Linux kernel trap
201          * handling code in arch/mips/kernel/traps.c.
202          */
203         case EXCP_BREAK:
204             {
205                 abi_ulong trap_instr;
206                 unsigned int code;
207 
208                 if (env->hflags & MIPS_HFLAG_M16) {
209                     if (env->insn_flags & ASE_MICROMIPS) {
210                         /* microMIPS mode */
211                         ret = get_user_u16(trap_instr, env->active_tc.PC);
212                         if (ret != 0) {
213                             goto error;
214                         }
215 
216                         if ((trap_instr >> 10) == 0x11) {
217                             /* 16-bit instruction */
218                             code = trap_instr & 0xf;
219                         } else {
220                             /* 32-bit instruction */
221                             abi_ulong instr_lo;
222 
223                             ret = get_user_u16(instr_lo,
224                                                env->active_tc.PC + 2);
225                             if (ret != 0) {
226                                 goto error;
227                             }
228                             trap_instr = (trap_instr << 16) | instr_lo;
229                             code = ((trap_instr >> 6) & ((1 << 20) - 1));
230                             /* Unfortunately, microMIPS also suffers from
231                                the old assembler bug...  */
232                             if (code >= (1 << 10)) {
233                                 code >>= 10;
234                             }
235                         }
236                     } else {
237                         /* MIPS16e mode */
238                         ret = get_user_u16(trap_instr, env->active_tc.PC);
239                         if (ret != 0) {
240                             goto error;
241                         }
242                         code = (trap_instr >> 6) & 0x3f;
243                     }
244                 } else {
245                     ret = get_user_u32(trap_instr, env->active_tc.PC);
246                     if (ret != 0) {
247                         goto error;
248                     }
249 
250                     /* As described in the original Linux kernel code, the
251                      * below checks on 'code' are to work around an old
252                      * assembly bug.
253                      */
254                     code = ((trap_instr >> 6) & ((1 << 20) - 1));
255                     if (code >= (1 << 10)) {
256                         code >>= 10;
257                     }
258                 }
259 
260                 if (do_break(env, &info, code) != 0) {
261                     goto error;
262                 }
263             }
264             break;
265         case EXCP_TRAP:
266             {
267                 abi_ulong trap_instr;
268                 unsigned int code = 0;
269 
270                 if (env->hflags & MIPS_HFLAG_M16) {
271                     /* microMIPS mode */
272                     abi_ulong instr[2];
273 
274                     ret = get_user_u16(instr[0], env->active_tc.PC) ||
275                           get_user_u16(instr[1], env->active_tc.PC + 2);
276 
277                     trap_instr = (instr[0] << 16) | instr[1];
278                 } else {
279                     ret = get_user_u32(trap_instr, env->active_tc.PC);
280                 }
281 
282                 if (ret != 0) {
283                     goto error;
284                 }
285 
286                 /* The immediate versions don't provide a code.  */
287                 if (!(trap_instr & 0xFC000000)) {
288                     if (env->hflags & MIPS_HFLAG_M16) {
289                         /* microMIPS mode */
290                         code = ((trap_instr >> 12) & ((1 << 4) - 1));
291                     } else {
292                         code = ((trap_instr >> 6) & ((1 << 10) - 1));
293                     }
294                 }
295 
296                 if (do_break(env, &info, code) != 0) {
297                     goto error;
298                 }
299             }
300             break;
301         case EXCP_ATOMIC:
302             cpu_exec_step_atomic(cs);
303             break;
304         default:
305 error:
306             EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
307             abort();
308         }
309         process_pending_signals(env);
310     }
311 }
312 
313 void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
314 {
315     CPUState *cpu = env_cpu(env);
316     TaskState *ts = cpu->opaque;
317     struct image_info *info = ts->info;
318     int i;
319 
320     struct mode_req {
321         bool single;
322         bool soft;
323         bool fr1;
324         bool frdefault;
325         bool fre;
326     };
327 
328     static const struct mode_req fpu_reqs[] = {
329         [MIPS_ABI_FP_ANY]    = { true,  true,  true,  true,  true  },
330         [MIPS_ABI_FP_DOUBLE] = { false, false, false, true,  true  },
331         [MIPS_ABI_FP_SINGLE] = { true,  false, false, false, false },
332         [MIPS_ABI_FP_SOFT]   = { false, true,  false, false, false },
333         [MIPS_ABI_FP_OLD_64] = { false, false, false, false, false },
334         [MIPS_ABI_FP_XX]     = { false, false, true,  true,  true  },
335         [MIPS_ABI_FP_64]     = { false, false, true,  false, false },
336         [MIPS_ABI_FP_64A]    = { false, false, true,  false, true  }
337     };
338 
339     /*
340      * Mode requirements when .MIPS.abiflags is not present in the ELF.
341      * Not present means that everything is acceptable except FR1.
342      */
343     static struct mode_req none_req = { true, true, false, true, true };
344 
345     struct mode_req prog_req;
346     struct mode_req interp_req;
347 
348     for(i = 0; i < 32; i++) {
349         env->active_tc.gpr[i] = regs->regs[i];
350     }
351     env->active_tc.PC = regs->cp0_epc & ~(target_ulong)1;
352     if (regs->cp0_epc & 1) {
353         env->hflags |= MIPS_HFLAG_M16;
354     }
355 
356 #ifdef TARGET_ABI_MIPSO32
357 # define MAX_FP_ABI MIPS_ABI_FP_64A
358 #else
359 # define MAX_FP_ABI MIPS_ABI_FP_SOFT
360 #endif
361      if ((info->fp_abi > MAX_FP_ABI && info->fp_abi != MIPS_ABI_FP_UNKNOWN)
362         || (info->interp_fp_abi > MAX_FP_ABI &&
363             info->interp_fp_abi != MIPS_ABI_FP_UNKNOWN)) {
364         fprintf(stderr, "qemu: Unexpected FPU mode\n");
365         exit(1);
366     }
367 
368     prog_req = (info->fp_abi == MIPS_ABI_FP_UNKNOWN) ? none_req
369                                             : fpu_reqs[info->fp_abi];
370     interp_req = (info->interp_fp_abi == MIPS_ABI_FP_UNKNOWN) ? none_req
371                                             : fpu_reqs[info->interp_fp_abi];
372 
373     prog_req.single &= interp_req.single;
374     prog_req.soft &= interp_req.soft;
375     prog_req.fr1 &= interp_req.fr1;
376     prog_req.frdefault &= interp_req.frdefault;
377     prog_req.fre &= interp_req.fre;
378 
379     bool cpu_has_mips_r2_r6 = env->insn_flags & ISA_MIPS_R2 ||
380                               env->insn_flags & ISA_MIPS_R6;
381 
382     if (prog_req.fre && !prog_req.frdefault && !prog_req.fr1) {
383         env->CP0_Config5 |= (1 << CP0C5_FRE);
384         if (env->active_fpu.fcr0 & (1 << FCR0_FREP)) {
385             env->hflags |= MIPS_HFLAG_FRE;
386         }
387     } else if ((prog_req.fr1 && prog_req.frdefault) ||
388          (prog_req.single && !prog_req.frdefault)) {
389         if ((env->active_fpu.fcr0 & (1 << FCR0_F64)
390             && cpu_has_mips_r2_r6) || prog_req.fr1) {
391             env->CP0_Status |= (1 << CP0St_FR);
392             env->hflags |= MIPS_HFLAG_F64;
393         }
394     } else  if (!prog_req.fre && !prog_req.frdefault &&
395           !prog_req.fr1 && !prog_req.single && !prog_req.soft) {
396         fprintf(stderr, "qemu: Can't find a matching FPU mode\n");
397         exit(1);
398     }
399 
400     if (env->insn_flags & ISA_NANOMIPS32) {
401         return;
402     }
403     if (((info->elf_flags & EF_MIPS_NAN2008) != 0) !=
404         ((env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) != 0)) {
405         if ((env->active_fpu.fcr31_rw_bitmask &
406               (1 << FCR31_NAN2008)) == 0) {
407             fprintf(stderr, "ELF binary's NaN mode not supported by CPU\n");
408             exit(1);
409         }
410         if ((info->elf_flags & EF_MIPS_NAN2008) != 0) {
411             env->active_fpu.fcr31 |= (1 << FCR31_NAN2008);
412         } else {
413             env->active_fpu.fcr31 &= ~(1 << FCR31_NAN2008);
414         }
415         restore_snan_bit_mode(env);
416     }
417 }
418