aboutsummaryrefslogtreecommitdiff
path: root/linux-user
diff options
context:
space:
mode:
Diffstat (limited to 'linux-user')
-rw-r--r--linux-user/main.c76
1 files changed, 75 insertions, 1 deletions
diff --git a/linux-user/main.c b/linux-user/main.c
index 29845f9c81..cb14c0bcad 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -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);