diff options
author | Laurent Vivier <laurent@vivier.eu> | 2018-04-11 20:56:47 +0200 |
---|---|---|
committer | Laurent Vivier <laurent@vivier.eu> | 2018-04-30 09:48:24 +0200 |
commit | a5fd8ee1f7e8e4d62c0362c04834bb9267810311 (patch) | |
tree | 651746bbd6fe0bf86fa18d199edfb3a31509f881 /linux-user/s390x | |
parent | e256aefe0ddefca4618d75951f948890f9b1f186 (diff) |
linux-user: move s390x cpu loop to s390x directory
No code change, only move code from main.c to
s390x/cpu_loop.c.
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Acked-by: Cornelia Huck <cohuck@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Message-Id: <20180411185651.21351-16-laurent@vivier.eu>
Diffstat (limited to 'linux-user/s390x')
-rw-r--r-- | linux-user/s390x/cpu_loop.c | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/linux-user/s390x/cpu_loop.c b/linux-user/s390x/cpu_loop.c index b7700a5561..99f5f1594f 100644 --- a/linux-user/s390x/cpu_loop.c +++ b/linux-user/s390x/cpu_loop.c @@ -21,6 +21,145 @@ #include "qemu.h" #include "cpu_loop-common.h" +/* s390x masks the fault address it reports in si_addr for SIGSEGV and SIGBUS */ +#define S390X_FAIL_ADDR_MASK -4096LL + +void cpu_loop(CPUS390XState *env) +{ + CPUState *cs = CPU(s390_env_get_cpu(env)); + int trapnr, n, sig; + target_siginfo_t info; + target_ulong addr; + abi_long ret; + + while (1) { + cpu_exec_start(cs); + trapnr = cpu_exec(cs); + cpu_exec_end(cs); + process_queued_cpu_work(cs); + + switch (trapnr) { + case EXCP_INTERRUPT: + /* Just indicate that signals should be handled asap. */ + break; + + case EXCP_SVC: + n = env->int_svc_code; + if (!n) { + /* syscalls > 255 */ + n = env->regs[1]; + } + env->psw.addr += env->int_svc_ilen; + ret = do_syscall(env, n, env->regs[2], env->regs[3], + env->regs[4], env->regs[5], + env->regs[6], env->regs[7], 0, 0); + if (ret == -TARGET_ERESTARTSYS) { + env->psw.addr -= env->int_svc_ilen; + } else if (ret != -TARGET_QEMU_ESIGRETURN) { + env->regs[2] = ret; + } + break; + + case EXCP_DEBUG: + sig = gdb_handlesig(cs, TARGET_SIGTRAP); + if (sig) { + n = TARGET_TRAP_BRKPT; + goto do_signal_pc; + } + break; + case EXCP_PGM: + n = env->int_pgm_code; + switch (n) { + case PGM_OPERATION: + case PGM_PRIVILEGED: + sig = TARGET_SIGILL; + n = TARGET_ILL_ILLOPC; + goto do_signal_pc; + case PGM_PROTECTION: + case PGM_ADDRESSING: + sig = TARGET_SIGSEGV; + /* XXX: check env->error_code */ + n = TARGET_SEGV_MAPERR; + addr = env->__excp_addr & S390X_FAIL_ADDR_MASK; + goto do_signal; + case PGM_EXECUTE: + case PGM_SPECIFICATION: + case PGM_SPECIAL_OP: + case PGM_OPERAND: + do_sigill_opn: + sig = TARGET_SIGILL; + n = TARGET_ILL_ILLOPN; + goto do_signal_pc; + + case PGM_FIXPT_OVERFLOW: + sig = TARGET_SIGFPE; + n = TARGET_FPE_INTOVF; + goto do_signal_pc; + case PGM_FIXPT_DIVIDE: + sig = TARGET_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 = TARGET_SIGFPE; + goto do_signal_pc; + } + + default: + fprintf(stderr, "Unhandled program exception: %#x\n", n); + cpu_dump_state(cs, stderr, fprintf, 0); + exit(EXIT_FAILURE); + } + break; + + 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, QEMU_SI_FAULT, &info); + break; + + case EXCP_ATOMIC: + cpu_exec_step_atomic(cs); + break; + default: + fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr); + cpu_dump_state(cs, stderr, fprintf, 0); + exit(EXIT_FAILURE); + } + process_pending_signals (env); + } +} + void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) { + int i; + for (i = 0; i < 16; i++) { + env->regs[i] = regs->gprs[i]; + } + env->psw.mask = regs->psw.mask; + env->psw.addr = regs->psw.addr; } |