]> git.proxmox.com Git - qemu.git/blobdiff - linux-user/main.c
target-mips: Translate breaks and traps into the appropriate signal
[qemu.git] / linux-user / main.c
index 29845f9c81c4de9ad6ed216f289770fdcbc4a5fc..cb14c0bcadeecc14183bd0d2f153514236cd4502 100644 (file)
@@ -2186,6 +2186,33 @@ static int do_store_exclusive(CPUMIPSState *env)
     return segv;
 }
 
+/* Break codes */
+enum {
+    BRK_OVERFLOW = 6,
+    BRK_DIVZERO = 7
+};
+
+static int do_break(CPUMIPSState *env, target_siginfo_t *info,
+                    unsigned int code)
+{
+    int ret = -1;
+
+    switch (code) {
+    case BRK_OVERFLOW:
+    case BRK_DIVZERO:
+        info->si_signo = TARGET_SIGFPE;
+        info->si_errno = 0;
+        info->si_code = (code == BRK_OVERFLOW) ? FPE_INTOVF : FPE_INTDIV;
+        queue_signal(env, info->si_signo, &*info);
+        ret = 0;
+        break;
+    default:
+        break;
+    }
+
+    return ret;
+}
+
 void cpu_loop(CPUMIPSState *env)
 {
     CPUState *cs = CPU(mips_env_get_cpu(env));
@@ -2302,8 +2329,55 @@ done_syscall:
             info.si_code = TARGET_ILL_ILLOPC;
             queue_signal(env, info.si_signo, &info);
             break;
+        /* The code below was inspired by the MIPS Linux kernel trap
+         * handling code in arch/mips/kernel/traps.c.
+         */
+        case EXCP_BREAK:
+            {
+                abi_ulong trap_instr;
+                unsigned int code;
+
+                ret = get_user_ual(trap_instr, env->active_tc.PC);
+                if (ret != 0) {
+                    goto error;
+                }
+
+                /* As described in the original Linux kernel code, the
+                 * below checks on 'code' are to work around an old
+                 * assembly bug.
+                 */
+                code = ((trap_instr >> 6) & ((1 << 20) - 1));
+                if (code >= (1 << 10)) {
+                    code >>= 10;
+                }
+
+                if (do_break(env, &info, code) != 0) {
+                    goto error;
+                }
+            }
+            break;
+        case EXCP_TRAP:
+            {
+                abi_ulong trap_instr;
+                unsigned int code = 0;
+
+                ret = get_user_ual(trap_instr, env->active_tc.PC);
+                if (ret != 0) {
+                    goto error;
+                }
+
+                /* The immediate versions don't provide a code.  */
+                if (!(trap_instr & 0xFC000000)) {
+                    code = ((trap_instr >> 6) & ((1 << 10) - 1));
+                }
+
+                if (do_break(env, &info, code) != 0) {
+                    goto error;
+                }
+            }
+            break;
         default:
-            //        error:
+error:
             fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
                     trapnr);
             cpu_dump_state(env, stderr, fprintf, 0);