From d5a103cd6eb3b407feb4e007cb778a89b1b20c5f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 14 Sep 2012 19:31:57 -0700 Subject: target-s390: Reorg exception handling Make the user path more like the system path. Prepare for more kinds of runtime exceptions. Rename ILC to ILEN to make it clear that we want to pass around a full instruction length, rather than a "code" that happens to be stored one bit left in a larger field. Signed-off-by: Richard Henderson --- linux-user/main.c | 140 +++++++++++++++++++++++++++++---------------- linux-user/s390x/syscall.h | 2 +- 2 files changed, 93 insertions(+), 49 deletions(-) (limited to 'linux-user') diff --git a/linux-user/main.c b/linux-user/main.c index f6c4c8d7a3..15bacb9a30 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2933,71 +2933,115 @@ void cpu_loop(CPUAlphaState *env) #ifdef TARGET_S390X void cpu_loop(CPUS390XState *env) { - int trapnr; + int trapnr, n, sig; target_siginfo_t info; + target_ulong addr; while (1) { - trapnr = cpu_s390x_exec (env); - + trapnr = cpu_s390x_exec(env); switch (trapnr) { case EXCP_INTERRUPT: - /* just indicate that signals should be handled asap */ + /* Just indicate that signals should be handled asap. */ break; - case EXCP_DEBUG: - { - int sig; - sig = gdb_handlesig (env, TARGET_SIGTRAP); - if (sig) { - info.si_signo = sig; - info.si_errno = 0; - info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); - } + case EXCP_SVC: + n = env->int_svc_code; + if (!n) { + /* syscalls > 255 */ + n = env->regs[1]; } + env->psw.addr += env->int_svc_ilen; + env->regs[2] = do_syscall(env, n, env->regs[2], env->regs[3], + env->regs[4], env->regs[5], + env->regs[6], env->regs[7], 0, 0); break; - case EXCP_SVC: - { - int n = env->int_svc_code; - if (!n) { - /* syscalls > 255 */ - n = env->regs[1]; - } - env->psw.addr += env->int_svc_ilc; - env->regs[2] = do_syscall(env, n, - env->regs[2], - env->regs[3], - env->regs[4], - env->regs[5], - env->regs[6], - env->regs[7], - 0, 0); + + case EXCP_DEBUG: + sig = gdb_handlesig(env, TARGET_SIGTRAP); + if (sig) { + n = TARGET_TRAP_BRKPT; + goto do_signal_pc; } break; - case EXCP_ADDR: - { - info.si_signo = SIGSEGV; - info.si_errno = 0; + case EXCP_PGM: + n = env->int_pgm_code; + switch (n) { + case PGM_OPERATION: + case PGM_PRIVILEGED: + sig = SIGILL; + n = TARGET_ILL_ILLOPC; + goto do_signal_pc; + case PGM_PROTECTION: + case PGM_ADDRESSING: + sig = SIGSEGV; /* XXX: check env->error_code */ - info.si_code = TARGET_SEGV_MAPERR; - info._sifields._sigfault._addr = env->__excp_addr; - queue_signal(env, info.si_signo, &info); + n = TARGET_SEGV_MAPERR; + addr = env->__excp_addr; + goto do_signal; + case PGM_EXECUTE: + case PGM_SPECIFICATION: + case PGM_SPECIAL_OP: + case PGM_OPERAND: + do_sigill_opn: + sig = SIGILL; + n = TARGET_ILL_ILLOPN; + goto do_signal_pc; + + case PGM_FIXPT_OVERFLOW: + sig = SIGFPE; + n = TARGET_FPE_INTOVF; + goto do_signal_pc; + case PGM_FIXPT_DIVIDE: + sig = SIGFPE; + n = TARGET_FPE_INTDIV; + goto do_signal_pc; + + case PGM_DATA: + n = (env->fpc >> 8) & 0xff; + if (n == 0xff) { + /* compare-and-trap */ + goto do_sigill_opn; + } else { + /* An IEEE exception, simulated or otherwise. */ + if (n & 0x80) { + n = TARGET_FPE_FLTINV; + } else if (n & 0x40) { + n = TARGET_FPE_FLTDIV; + } else if (n & 0x20) { + n = TARGET_FPE_FLTOVF; + } else if (n & 0x10) { + n = TARGET_FPE_FLTUND; + } else if (n & 0x08) { + n = TARGET_FPE_FLTRES; + } else { + /* ??? Quantum exception; BFP, DFP error. */ + goto do_sigill_opn; + } + sig = SIGFPE; + goto do_signal_pc; + } + + default: + fprintf(stderr, "Unhandled program exception: %#x\n", n); + cpu_dump_state(env, stderr, fprintf, 0); + exit(1); } break; - case EXCP_SPEC: - { - fprintf(stderr,"specification exception insn 0x%08x%04x\n", ldl(env->psw.addr), lduw(env->psw.addr + 4)); - info.si_signo = SIGILL; - info.si_errno = 0; - info.si_code = TARGET_ILL_ILLOPC; - info._sifields._sigfault._addr = env->__excp_addr; - queue_signal(env, info.si_signo, &info); - } + + do_signal_pc: + addr = env->psw.addr; + do_signal: + info.si_signo = sig; + info.si_errno = 0; + info.si_code = n; + info._sifields._sigfault._addr = addr; + queue_signal(env, info.si_signo, &info); break; + default: - printf ("Unhandled trap: 0x%x\n", trapnr); + fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr); cpu_dump_state(env, stderr, fprintf, 0); - exit (1); + exit(1); } process_pending_signals (env); } diff --git a/linux-user/s390x/syscall.h b/linux-user/s390x/syscall.h index c2ea151ea5..e4603b79c3 100644 --- a/linux-user/s390x/syscall.h +++ b/linux-user/s390x/syscall.h @@ -16,7 +16,7 @@ struct target_pt_regs { target_psw_t psw; abi_ulong gprs[TARGET_NUM_GPRS]; abi_ulong orig_gpr2; - unsigned short ilc; + unsigned short ilen; unsigned short trap; }; -- cgit v1.2.1