aboutsummaryrefslogtreecommitdiff
path: root/linux-user/s390x/cpu_loop.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux-user/s390x/cpu_loop.c')
-rw-r--r--linux-user/s390x/cpu_loop.c114
1 files changed, 70 insertions, 44 deletions
diff --git a/linux-user/s390x/cpu_loop.c b/linux-user/s390x/cpu_loop.c
index 99f5f1594f..8b7ac2879e 100644
--- a/linux-user/s390x/cpu_loop.c
+++ b/linux-user/s390x/cpu_loop.c
@@ -19,16 +19,44 @@
#include "qemu/osdep.h"
#include "qemu.h"
+#include "user-internals.h"
#include "cpu_loop-common.h"
+#include "signal-common.h"
-/* s390x masks the fault address it reports in si_addr for SIGSEGV and SIGBUS */
-#define S390X_FAIL_ADDR_MASK -4096LL
+
+static int get_pgm_data_si_code(int dxc_code)
+{
+ switch (dxc_code) {
+ /* Non-simulated IEEE exceptions */
+ case 0x80:
+ return TARGET_FPE_FLTINV;
+ case 0x40:
+ return TARGET_FPE_FLTDIV;
+ case 0x20:
+ case 0x28:
+ case 0x2c:
+ return TARGET_FPE_FLTOVF;
+ case 0x10:
+ case 0x18:
+ case 0x1c:
+ return TARGET_FPE_FLTUND;
+ case 0x08:
+ case 0x0c:
+ return TARGET_FPE_FLTRES;
+ }
+ /*
+ * Non-IEEE and simulated IEEE:
+ * Includes compare-and-trap, quantum exception, etc.
+ * Simulated IEEE are included here to match current
+ * s390x linux kernel.
+ */
+ return 0;
+}
void cpu_loop(CPUS390XState *env)
{
- CPUState *cs = CPU(s390_env_get_cpu(env));
+ CPUState *cs = env_cpu(env);
int trapnr, n, sig;
- target_siginfo_t info;
target_ulong addr;
abi_long ret;
@@ -53,20 +81,32 @@ void cpu_loop(CPUS390XState *env)
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) {
+ if (ret == -QEMU_ERESTARTSYS) {
env->psw.addr -= env->int_svc_ilen;
- } else if (ret != -TARGET_QEMU_ESIGRETURN) {
+ } else if (ret != -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;
+ if (unlikely(cs->singlestep_enabled)) {
+ /*
+ * cpu_tb_exec() did not raise EXCP_DEBUG, because it has seen
+ * that EXCP_SVC was already pending.
+ */
+ cs->exception_index = EXCP_DEBUG;
}
+
break;
+
+ case EXCP_DEBUG:
+ sig = TARGET_SIGTRAP;
+ n = TARGET_TRAP_BRKPT;
+ /*
+ * For SIGTRAP the PSW must point after the instruction, which it
+ * already does thanks to s390x_tr_tb_stop(). si_addr doesn't need
+ * to be filled.
+ */
+ addr = 0;
+ goto do_signal;
case EXCP_PGM:
n = env->int_pgm_code;
switch (n) {
@@ -76,12 +116,13 @@ void cpu_loop(CPUS390XState *env)
n = TARGET_ILL_ILLOPC;
goto do_signal_pc;
case PGM_PROTECTION:
+ force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_ACCERR,
+ env->__excp_addr);
+ break;
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;
+ force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_MAPERR,
+ env->__excp_addr);
+ break;
case PGM_EXECUTE:
case PGM_SPECIFICATION:
case PGM_SPECIAL_OP:
@@ -102,44 +143,29 @@ void cpu_loop(CPUS390XState *env)
case PGM_DATA:
n = (env->fpc >> 8) & 0xff;
- if (n == 0xff) {
- /* compare-and-trap */
+ if (n == 0) {
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;
}
+ sig = TARGET_SIGFPE;
+ n = get_pgm_data_si_code(n);
+ goto do_signal_pc;
+
default:
fprintf(stderr, "Unhandled program exception: %#x\n", n);
- cpu_dump_state(cs, stderr, fprintf, 0);
+ cpu_dump_state(cs, stderr, 0);
exit(EXIT_FAILURE);
}
break;
do_signal_pc:
addr = env->psw.addr;
+ /*
+ * For SIGILL and SIGFPE the PSW must point after the instruction.
+ */
+ env->psw.addr += env->int_pgm_ilen;
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);
+ force_sig_fault(sig, n, addr);
break;
case EXCP_ATOMIC:
@@ -147,7 +173,7 @@ void cpu_loop(CPUS390XState *env)
break;
default:
fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr);
- cpu_dump_state(cs, stderr, fprintf, 0);
+ cpu_dump_state(cs, stderr, 0);
exit(EXIT_FAILURE);
}
process_pending_signals (env);