aboutsummaryrefslogtreecommitdiff
path: root/linux-user
diff options
context:
space:
mode:
Diffstat (limited to 'linux-user')
-rw-r--r--linux-user/aarch64/cpu_loop.c12
-rw-r--r--linux-user/alpha/cpu_loop.c15
-rw-r--r--linux-user/arm/cpu_loop.c30
-rw-r--r--linux-user/cris/cpu_loop.c10
-rw-r--r--linux-user/hexagon/cpu_loop.c24
-rw-r--r--linux-user/host/aarch64/host-signal.h74
-rw-r--r--linux-user/host/alpha/host-signal.h42
-rw-r--r--linux-user/host/arm/host-signal.h30
-rw-r--r--linux-user/host/i386/host-signal.h25
-rw-r--r--linux-user/host/mips/host-signal.h62
-rw-r--r--linux-user/host/ppc/host-signal.h25
-rw-r--r--linux-user/host/ppc64/host-signal.h1
-rw-r--r--linux-user/host/riscv/host-signal.h58
-rw-r--r--linux-user/host/riscv/hostdep.h (renamed from linux-user/host/riscv64/hostdep.h)4
-rw-r--r--linux-user/host/riscv/safe-syscall.inc.S (renamed from linux-user/host/riscv64/safe-syscall.inc.S)0
-rw-r--r--linux-user/host/riscv32/hostdep.h11
-rw-r--r--linux-user/host/s390/host-signal.h93
-rw-r--r--linux-user/host/s390x/host-signal.h1
-rw-r--r--linux-user/host/sparc/host-signal.h54
-rw-r--r--linux-user/host/sparc64/host-signal.h1
-rw-r--r--linux-user/host/x32/host-signal.h1
-rw-r--r--linux-user/host/x86_64/host-signal.h24
-rw-r--r--linux-user/hppa/cpu_loop.c23
-rw-r--r--linux-user/m68k/cpu_loop.c10
-rw-r--r--linux-user/microblaze/cpu_loop.c10
-rw-r--r--linux-user/mips/cpu_loop.c11
-rw-r--r--linux-user/openrisc/cpu_loop.c25
-rw-r--r--linux-user/ppc/cpu_loop.c8
-rw-r--r--linux-user/riscv/cpu_loop.c7
-rw-r--r--linux-user/s390x/cpu_loop.c13
-rw-r--r--linux-user/sh4/cpu_loop.c8
-rw-r--r--linux-user/signal.c129
-rw-r--r--linux-user/sparc/cpu_loop.c25
-rw-r--r--linux-user/xtensa/cpu_loop.c9
34 files changed, 654 insertions, 221 deletions
diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c
index 034b737435..97e0728b67 100644
--- a/linux-user/aarch64/cpu_loop.c
+++ b/linux-user/aarch64/cpu_loop.c
@@ -79,7 +79,7 @@
void cpu_loop(CPUARMState *env)
{
CPUState *cs = env_cpu(env);
- int trapnr, ec, fsc, si_code;
+ int trapnr, ec, fsc, si_code, si_signo;
abi_long ret;
for (;;) {
@@ -121,20 +121,26 @@ void cpu_loop(CPUARMState *env)
fsc = extract32(env->exception.syndrome, 0, 6);
switch (fsc) {
case 0x04 ... 0x07: /* Translation fault, level {0-3} */
+ si_signo = TARGET_SIGSEGV;
si_code = TARGET_SEGV_MAPERR;
break;
case 0x09 ... 0x0b: /* Access flag fault, level {1-3} */
case 0x0d ... 0x0f: /* Permission fault, level {1-3} */
+ si_signo = TARGET_SIGSEGV;
si_code = TARGET_SEGV_ACCERR;
break;
case 0x11: /* Synchronous Tag Check Fault */
+ si_signo = TARGET_SIGSEGV;
si_code = TARGET_SEGV_MTESERR;
break;
+ case 0x21: /* Alignment fault */
+ si_signo = TARGET_SIGBUS;
+ si_code = TARGET_BUS_ADRALN;
+ break;
default:
g_assert_not_reached();
}
-
- force_sig_fault(TARGET_SIGSEGV, si_code, env->exception.vaddress);
+ force_sig_fault(si_signo, si_code, env->exception.vaddress);
break;
case EXCP_DEBUG:
case EXCP_BKPT:
diff --git a/linux-user/alpha/cpu_loop.c b/linux-user/alpha/cpu_loop.c
index 1b00a81385..4029849d5c 100644
--- a/linux-user/alpha/cpu_loop.c
+++ b/linux-user/alpha/cpu_loop.c
@@ -54,21 +54,6 @@ void cpu_loop(CPUAlphaState *env)
fprintf(stderr, "External interrupt. Exit\n");
exit(EXIT_FAILURE);
break;
- case EXCP_MMFAULT:
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = (page_get_flags(env->trap_arg0) & PAGE_VALID
- ? TARGET_SEGV_ACCERR : TARGET_SEGV_MAPERR);
- info._sifields._sigfault._addr = env->trap_arg0;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case EXCP_UNALIGN:
- info.si_signo = TARGET_SIGBUS;
- info.si_errno = 0;
- info.si_code = TARGET_BUS_ADRALN;
- info._sifields._sigfault._addr = env->trap_arg0;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
case EXCP_OPCDEC:
do_sigill:
info.si_signo = TARGET_SIGILL;
diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c
index ae09adcb95..01cb6eb534 100644
--- a/linux-user/arm/cpu_loop.c
+++ b/linux-user/arm/cpu_loop.c
@@ -25,6 +25,7 @@
#include "cpu_loop-common.h"
#include "signal-common.h"
#include "semihosting/common-semi.h"
+#include "target/arm/syndrome.h"
#define get_user_code_u32(x, gaddr, env) \
({ abi_long __r = get_user_u32((x), (gaddr)); \
@@ -280,7 +281,7 @@ static bool emulate_arm_fpa11(CPUARMState *env, uint32_t opcode)
void cpu_loop(CPUARMState *env)
{
CPUState *cs = env_cpu(env);
- int trapnr;
+ int trapnr, si_signo, si_code;
unsigned int n, insn;
abi_ulong ret;
@@ -423,9 +424,30 @@ void cpu_loop(CPUARMState *env)
break;
case EXCP_PREFETCH_ABORT:
case EXCP_DATA_ABORT:
- /* XXX: check env->error_code */
- force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_MAPERR,
- env->exception.vaddress);
+ /* For user-only we don't set TTBCR_EAE, so look at the FSR. */
+ switch (env->exception.fsr & 0x1f) {
+ case 0x1: /* Alignment */
+ si_signo = TARGET_SIGBUS;
+ si_code = TARGET_BUS_ADRALN;
+ break;
+ case 0x3: /* Access flag fault, level 1 */
+ case 0x6: /* Access flag fault, level 2 */
+ case 0x9: /* Domain fault, level 1 */
+ case 0xb: /* Domain fault, level 2 */
+ case 0xd: /* Permision fault, level 1 */
+ case 0xf: /* Permision fault, level 2 */
+ si_signo = TARGET_SIGSEGV;
+ si_code = TARGET_SEGV_ACCERR;
+ break;
+ case 0x5: /* Translation fault, level 1 */
+ case 0x7: /* Translation fault, level 2 */
+ si_signo = TARGET_SIGSEGV;
+ si_code = TARGET_SEGV_MAPERR;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ force_sig_fault(si_signo, si_code, env->exception.vaddress);
break;
case EXCP_DEBUG:
case EXCP_BKPT:
diff --git a/linux-user/cris/cpu_loop.c b/linux-user/cris/cpu_loop.c
index b9085619c4..0d5d268609 100644
--- a/linux-user/cris/cpu_loop.c
+++ b/linux-user/cris/cpu_loop.c
@@ -37,16 +37,6 @@ void cpu_loop(CPUCRISState *env)
process_queued_cpu_work(cs);
switch (trapnr) {
- case 0xaa:
- {
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- /* XXX: check env->error_code */
- info.si_code = TARGET_SEGV_MAPERR;
- info._sifields._sigfault._addr = env->pregs[PR_EDA];
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- break;
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
break;
diff --git a/linux-user/hexagon/cpu_loop.c b/linux-user/hexagon/cpu_loop.c
index bee2a9e4ea..6b24cbaba9 100644
--- a/linux-user/hexagon/cpu_loop.c
+++ b/linux-user/hexagon/cpu_loop.c
@@ -28,8 +28,7 @@
void cpu_loop(CPUHexagonState *env)
{
CPUState *cs = env_cpu(env);
- int trapnr, signum, sigcode;
- target_ulong sigaddr;
+ int trapnr;
target_ulong syscallnum;
target_ulong ret;
@@ -39,10 +38,6 @@ void cpu_loop(CPUHexagonState *env)
cpu_exec_end(cs);
process_queued_cpu_work(cs);
- signum = 0;
- sigcode = 0;
- sigaddr = 0;
-
switch (trapnr) {
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
@@ -65,12 +60,6 @@ void cpu_loop(CPUHexagonState *env)
env->gpr[0] = ret;
}
break;
- case HEX_EXCP_FETCH_NO_UPAGE:
- case HEX_EXCP_PRIV_NO_UREAD:
- case HEX_EXCP_PRIV_NO_UWRITE:
- signum = TARGET_SIGSEGV;
- sigcode = TARGET_SEGV_MAPERR;
- break;
case EXCP_ATOMIC:
cpu_exec_step_atomic(cs);
break;
@@ -79,17 +68,6 @@ void cpu_loop(CPUHexagonState *env)
trapnr);
exit(EXIT_FAILURE);
}
-
- if (signum) {
- target_siginfo_t info = {
- .si_signo = signum,
- .si_errno = 0,
- .si_code = sigcode,
- ._sifields._sigfault._addr = sigaddr
- };
- queue_signal(env, info.si_signo, QEMU_SI_KILL, &info);
- }
-
process_pending_signals(env);
}
}
diff --git a/linux-user/host/aarch64/host-signal.h b/linux-user/host/aarch64/host-signal.h
new file mode 100644
index 0000000000..0c0b08383a
--- /dev/null
+++ b/linux-user/host/aarch64/host-signal.h
@@ -0,0 +1,74 @@
+/*
+ * host-signal.h: signal info dependent on the host architecture
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2021 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef AARCH64_HOST_SIGNAL_H
+#define AARCH64_HOST_SIGNAL_H
+
+/* Pre-3.16 kernel headers don't have these, so provide fallback definitions */
+#ifndef ESR_MAGIC
+#define ESR_MAGIC 0x45535201
+struct esr_context {
+ struct _aarch64_ctx head;
+ uint64_t esr;
+};
+#endif
+
+static inline struct _aarch64_ctx *first_ctx(ucontext_t *uc)
+{
+ return (struct _aarch64_ctx *)&uc->uc_mcontext.__reserved;
+}
+
+static inline struct _aarch64_ctx *next_ctx(struct _aarch64_ctx *hdr)
+{
+ return (struct _aarch64_ctx *)((char *)hdr + hdr->size);
+}
+
+static inline uintptr_t host_signal_pc(ucontext_t *uc)
+{
+ return uc->uc_mcontext.pc;
+}
+
+static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
+{
+ struct _aarch64_ctx *hdr;
+ uint32_t insn;
+
+ /* Find the esr_context, which has the WnR bit in it */
+ for (hdr = first_ctx(uc); hdr->magic; hdr = next_ctx(hdr)) {
+ if (hdr->magic == ESR_MAGIC) {
+ struct esr_context const *ec = (struct esr_context const *)hdr;
+ uint64_t esr = ec->esr;
+
+ /* For data aborts ESR.EC is 0b10010x: then bit 6 is the WnR bit */
+ return extract32(esr, 27, 5) == 0x12 && extract32(esr, 6, 1) == 1;
+ }
+ }
+
+ /*
+ * Fall back to parsing instructions; will only be needed
+ * for really ancient (pre-3.16) kernels.
+ */
+ insn = *(uint32_t *)host_signal_pc(uc);
+
+ return (insn & 0xbfff0000) == 0x0c000000 /* C3.3.1 */
+ || (insn & 0xbfe00000) == 0x0c800000 /* C3.3.2 */
+ || (insn & 0xbfdf0000) == 0x0d000000 /* C3.3.3 */
+ || (insn & 0xbfc00000) == 0x0d800000 /* C3.3.4 */
+ || (insn & 0x3f400000) == 0x08000000 /* C3.3.6 */
+ || (insn & 0x3bc00000) == 0x39000000 /* C3.3.13 */
+ || (insn & 0x3fc00000) == 0x3d800000 /* ... 128bit */
+ /* Ignore bits 10, 11 & 21, controlling indexing. */
+ || (insn & 0x3bc00000) == 0x38000000 /* C3.3.8-12 */
+ || (insn & 0x3fe00000) == 0x3c800000 /* ... 128bit */
+ /* Ignore bits 23 & 24, controlling indexing. */
+ || (insn & 0x3a400000) == 0x28000000; /* C3.3.7,14-16 */
+}
+
+#endif
diff --git a/linux-user/host/alpha/host-signal.h b/linux-user/host/alpha/host-signal.h
new file mode 100644
index 0000000000..e080be412f
--- /dev/null
+++ b/linux-user/host/alpha/host-signal.h
@@ -0,0 +1,42 @@
+/*
+ * host-signal.h: signal info dependent on the host architecture
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2021 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef ALPHA_HOST_SIGNAL_H
+#define ALPHA_HOST_SIGNAL_H
+
+static inline uintptr_t host_signal_pc(ucontext_t *uc)
+{
+ return uc->uc_mcontext.sc_pc;
+}
+
+static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
+{
+ uint32_t *pc = (uint32_t *)host_signal_pc(uc);
+ uint32_t insn = *pc;
+
+ /* XXX: need kernel patch to get write flag faster */
+ switch (insn >> 26) {
+ case 0x0d: /* stw */
+ case 0x0e: /* stb */
+ case 0x0f: /* stq_u */
+ case 0x24: /* stf */
+ case 0x25: /* stg */
+ case 0x26: /* sts */
+ case 0x27: /* stt */
+ case 0x2c: /* stl */
+ case 0x2d: /* stq */
+ case 0x2e: /* stl_c */
+ case 0x2f: /* stq_c */
+ return true;
+ }
+ return false;
+}
+
+#endif
diff --git a/linux-user/host/arm/host-signal.h b/linux-user/host/arm/host-signal.h
new file mode 100644
index 0000000000..efb165c0c5
--- /dev/null
+++ b/linux-user/host/arm/host-signal.h
@@ -0,0 +1,30 @@
+/*
+ * host-signal.h: signal info dependent on the host architecture
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2021 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef ARM_HOST_SIGNAL_H
+#define ARM_HOST_SIGNAL_H
+
+static inline uintptr_t host_signal_pc(ucontext_t *uc)
+{
+ return uc->uc_mcontext.arm_pc;
+}
+
+static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
+{
+ /*
+ * In the FSR, bit 11 is WnR, assuming a v6 or
+ * later processor. On v5 we will always report
+ * this as a read, which will fail later.
+ */
+ uint32_t fsr = uc->uc_mcontext.error_code;
+ return extract32(fsr, 11, 1);
+}
+
+#endif
diff --git a/linux-user/host/i386/host-signal.h b/linux-user/host/i386/host-signal.h
new file mode 100644
index 0000000000..4c8eef99ce
--- /dev/null
+++ b/linux-user/host/i386/host-signal.h
@@ -0,0 +1,25 @@
+/*
+ * host-signal.h: signal info dependent on the host architecture
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2021 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef I386_HOST_SIGNAL_H
+#define I386_HOST_SIGNAL_H
+
+static inline uintptr_t host_signal_pc(ucontext_t *uc)
+{
+ return uc->uc_mcontext.gregs[REG_EIP];
+}
+
+static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
+{
+ return uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe
+ && (uc->uc_mcontext.gregs[REG_ERR] & 0x2);
+}
+
+#endif
diff --git a/linux-user/host/mips/host-signal.h b/linux-user/host/mips/host-signal.h
new file mode 100644
index 0000000000..ef341f7c20
--- /dev/null
+++ b/linux-user/host/mips/host-signal.h
@@ -0,0 +1,62 @@
+/*
+ * host-signal.h: signal info dependent on the host architecture
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2021 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef MIPS_HOST_SIGNAL_H
+#define MIPS_HOST_SIGNAL_H
+
+static inline uintptr_t host_signal_pc(ucontext_t *uc)
+{
+ return uc->uc_mcontext.pc;
+}
+
+#if defined(__misp16) || defined(__mips_micromips)
+#error "Unsupported encoding"
+#endif
+
+static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
+{
+ uint32_t insn = *(uint32_t *)host_signal_pc(uc);
+
+ /* Detect all store instructions at program counter. */
+ switch ((insn >> 26) & 077) {
+ case 050: /* SB */
+ case 051: /* SH */
+ case 052: /* SWL */
+ case 053: /* SW */
+ case 054: /* SDL */
+ case 055: /* SDR */
+ case 056: /* SWR */
+ case 070: /* SC */
+ case 071: /* SWC1 */
+ case 074: /* SCD */
+ case 075: /* SDC1 */
+ case 077: /* SD */
+#if !defined(__mips_isa_rev) || __mips_isa_rev < 6
+ case 072: /* SWC2 */
+ case 076: /* SDC2 */
+#endif
+ return true;
+ case 023: /* COP1X */
+ /*
+ * Required in all versions of MIPS64 since
+ * MIPS64r1 and subsequent versions of MIPS32r2.
+ */
+ switch (insn & 077) {
+ case 010: /* SWXC1 */
+ case 011: /* SDXC1 */
+ case 015: /* SUXC1 */
+ return true;
+ }
+ break;
+ }
+ return false;
+}
+
+#endif
diff --git a/linux-user/host/ppc/host-signal.h b/linux-user/host/ppc/host-signal.h
new file mode 100644
index 0000000000..a491c413dc
--- /dev/null
+++ b/linux-user/host/ppc/host-signal.h
@@ -0,0 +1,25 @@
+/*
+ * host-signal.h: signal info dependent on the host architecture
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2021 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef PPC_HOST_SIGNAL_H
+#define PPC_HOST_SIGNAL_H
+
+static inline uintptr_t host_signal_pc(ucontext_t *uc)
+{
+ return uc->uc_mcontext.regs->nip;
+}
+
+static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
+{
+ return uc->uc_mcontext.regs->trap != 0x400
+ && (uc->uc_mcontext.regs->dsisr & 0x02000000);
+}
+
+#endif
diff --git a/linux-user/host/ppc64/host-signal.h b/linux-user/host/ppc64/host-signal.h
new file mode 100644
index 0000000000..a353c22a90
--- /dev/null
+++ b/linux-user/host/ppc64/host-signal.h
@@ -0,0 +1 @@
+#include "../ppc/host-signal.h"
diff --git a/linux-user/host/riscv/host-signal.h b/linux-user/host/riscv/host-signal.h
new file mode 100644
index 0000000000..3b168cb58b
--- /dev/null
+++ b/linux-user/host/riscv/host-signal.h
@@ -0,0 +1,58 @@
+/*
+ * host-signal.h: signal info dependent on the host architecture
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2021 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef RISCV_HOST_SIGNAL_H
+#define RISCV_HOST_SIGNAL_H
+
+static inline uintptr_t host_signal_pc(ucontext_t *uc)
+{
+ return uc->uc_mcontext.__gregs[REG_PC];
+}
+
+static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
+{
+ /*
+ * Detect store by reading the instruction at the program counter.
+ * Do not read more than 16 bits, because we have not yet determined
+ * the size of the instruction.
+ */
+ const uint16_t *pinsn = (const uint16_t *)host_signal_pc(uc);
+ uint16_t insn = pinsn[0];
+
+ /* 16-bit instructions */
+ switch (insn & 0xe003) {
+ case 0xa000: /* c.fsd */
+ case 0xc000: /* c.sw */
+ case 0xe000: /* c.sd (rv64) / c.fsw (rv32) */
+ case 0xa002: /* c.fsdsp */
+ case 0xc002: /* c.swsp */
+ case 0xe002: /* c.sdsp (rv64) / c.fswsp (rv32) */
+ return true;
+ }
+
+ /* 32-bit instructions, major opcodes */
+ switch (insn & 0x7f) {
+ case 0x23: /* store */
+ case 0x27: /* store-fp */
+ return true;
+ case 0x2f: /* amo */
+ /*
+ * The AMO function code is in bits 25-31, unread as yet.
+ * The AMO functions are LR (read), SC (write), and the
+ * rest are all read-modify-write.
+ */
+ insn = pinsn[1];
+ return (insn >> 11) != 2; /* LR */
+ }
+
+ return false;
+}
+
+#endif
diff --git a/linux-user/host/riscv64/hostdep.h b/linux-user/host/riscv/hostdep.h
index 865f0fb9ff..2ba07456ae 100644
--- a/linux-user/host/riscv64/hostdep.h
+++ b/linux-user/host/riscv/hostdep.h
@@ -5,8 +5,8 @@
* See the COPYING file in the top-level directory.
*/
-#ifndef RISCV64_HOSTDEP_H
-#define RISCV64_HOSTDEP_H
+#ifndef RISCV_HOSTDEP_H
+#define RISCV_HOSTDEP_H
/* We have a safe-syscall.inc.S */
#define HAVE_SAFE_SYSCALL
diff --git a/linux-user/host/riscv64/safe-syscall.inc.S b/linux-user/host/riscv/safe-syscall.inc.S
index 9ca3fbfd1e..9ca3fbfd1e 100644
--- a/linux-user/host/riscv64/safe-syscall.inc.S
+++ b/linux-user/host/riscv/safe-syscall.inc.S
diff --git a/linux-user/host/riscv32/hostdep.h b/linux-user/host/riscv32/hostdep.h
deleted file mode 100644
index adf9edbf2d..0000000000
--- a/linux-user/host/riscv32/hostdep.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- * hostdep.h : things which are dependent on the host architecture
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#ifndef RISCV32_HOSTDEP_H
-#define RISCV32_HOSTDEP_H
-
-#endif
diff --git a/linux-user/host/s390/host-signal.h b/linux-user/host/s390/host-signal.h
new file mode 100644
index 0000000000..26990e4893
--- /dev/null
+++ b/linux-user/host/s390/host-signal.h
@@ -0,0 +1,93 @@
+/*
+ * host-signal.h: signal info dependent on the host architecture
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2021 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef S390_HOST_SIGNAL_H
+#define S390_HOST_SIGNAL_H
+
+static inline uintptr_t host_signal_pc(ucontext_t *uc)
+{
+ return uc->uc_mcontext.psw.addr;
+}
+
+static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
+{
+ uint16_t *pinsn = (uint16_t *)host_signal_pc(uc);
+
+ /*
+ * ??? On linux, the non-rt signal handler has 4 (!) arguments instead
+ * of the normal 2 arguments. The 4th argument contains the "Translation-
+ * Exception Identification for DAT Exceptions" from the hardware (aka
+ * "int_parm_long"), which does in fact contain the is_write value.
+ * The rt signal handler, as far as I can tell, does not give this value
+ * at all. Not that we could get to it from here even if it were.
+ * So fall back to parsing instructions. Treat read-modify-write ones as
+ * writes, which is not fully correct, but for tracking self-modifying code
+ * this is better than treating them as reads. Checking si_addr page flags
+ * might be a viable improvement, albeit a racy one.
+ */
+ /* ??? This is not even close to complete. */
+ switch (pinsn[0] >> 8) {
+ case 0x50: /* ST */
+ case 0x42: /* STC */
+ case 0x40: /* STH */
+ case 0xba: /* CS */
+ case 0xbb: /* CDS */
+ return true;
+ case 0xc4: /* RIL format insns */
+ switch (pinsn[0] & 0xf) {
+ case 0xf: /* STRL */
+ case 0xb: /* STGRL */
+ case 0x7: /* STHRL */
+ return true;
+ }
+ break;
+ case 0xc8: /* SSF format insns */
+ switch (pinsn[0] & 0xf) {
+ case 0x2: /* CSST */
+ return true;
+ }
+ break;
+ case 0xe3: /* RXY format insns */
+ switch (pinsn[2] & 0xff) {
+ case 0x50: /* STY */
+ case 0x24: /* STG */
+ case 0x72: /* STCY */
+ case 0x70: /* STHY */
+ case 0x8e: /* STPQ */
+ case 0x3f: /* STRVH */
+ case 0x3e: /* STRV */
+ case 0x2f: /* STRVG */
+ return true;
+ }
+ break;
+ case 0xeb: /* RSY format insns */
+ switch (pinsn[2] & 0xff) {
+ case 0x14: /* CSY */
+ case 0x30: /* CSG */
+ case 0x31: /* CDSY */
+ case 0x3e: /* CDSG */
+ case 0xe4: /* LANG */
+ case 0xe6: /* LAOG */
+ case 0xe7: /* LAXG */
+ case 0xe8: /* LAAG */
+ case 0xea: /* LAALG */
+ case 0xf4: /* LAN */
+ case 0xf6: /* LAO */
+ case 0xf7: /* LAX */
+ case 0xfa: /* LAAL */
+ case 0xf8: /* LAA */
+ return true;
+ }
+ break;
+ }
+ return false;
+}
+
+#endif
diff --git a/linux-user/host/s390x/host-signal.h b/linux-user/host/s390x/host-signal.h
new file mode 100644
index 0000000000..0e83f9358d
--- /dev/null
+++ b/linux-user/host/s390x/host-signal.h
@@ -0,0 +1 @@
+#include "../s390/host-signal.h"
diff --git a/linux-user/host/sparc/host-signal.h b/linux-user/host/sparc/host-signal.h
new file mode 100644
index 0000000000..5e71d33f8e
--- /dev/null
+++ b/linux-user/host/sparc/host-signal.h
@@ -0,0 +1,54 @@
+/*
+ * host-signal.h: signal info dependent on the host architecture
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2021 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef SPARC_HOST_SIGNAL_H
+#define SPARC_HOST_SIGNAL_H
+
+static inline uintptr_t host_signal_pc(ucontext_t *uc)
+{
+#ifdef __arch64__
+ return uc->uc_mcontext.mc_gregs[MC_PC];
+#else
+ return uc->uc_mcontext.gregs[REG_PC];
+#endif
+}
+
+static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
+{
+ uint32_t insn = *(uint32_t *)host_signal_pc(uc);
+
+ if ((insn >> 30) == 3) {
+ switch ((insn >> 19) & 0x3f) {
+ case 0x05: /* stb */
+ case 0x15: /* stba */
+ case 0x06: /* sth */
+ case 0x16: /* stha */
+ case 0x04: /* st */
+ case 0x14: /* sta */
+ case 0x07: /* std */
+ case 0x17: /* stda */
+ case 0x0e: /* stx */
+ case 0x1e: /* stxa */
+ case 0x24: /* stf */
+ case 0x34: /* stfa */
+ case 0x27: /* stdf */
+ case 0x37: /* stdfa */
+ case 0x26: /* stqf */
+ case 0x36: /* stqfa */
+ case 0x25: /* stfsr */
+ case 0x3c: /* casa */
+ case 0x3e: /* casxa */
+ return true;
+ }
+ }
+ return false;
+}
+
+#endif
diff --git a/linux-user/host/sparc64/host-signal.h b/linux-user/host/sparc64/host-signal.h
new file mode 100644
index 0000000000..1191fe2d40
--- /dev/null
+++ b/linux-user/host/sparc64/host-signal.h
@@ -0,0 +1 @@
+#include "../sparc/host-signal.h"
diff --git a/linux-user/host/x32/host-signal.h b/linux-user/host/x32/host-signal.h
new file mode 100644
index 0000000000..26800591d3
--- /dev/null
+++ b/linux-user/host/x32/host-signal.h
@@ -0,0 +1 @@
+#include "../x86_64/host-signal.h"
diff --git a/linux-user/host/x86_64/host-signal.h b/linux-user/host/x86_64/host-signal.h
new file mode 100644
index 0000000000..883d2fcf65
--- /dev/null
+++ b/linux-user/host/x86_64/host-signal.h
@@ -0,0 +1,24 @@
+/*
+ * host-signal.h: signal info dependent on the host architecture
+ *
+ * Copyright (C) 2021 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef X86_64_HOST_SIGNAL_H
+#define X86_64_HOST_SIGNAL_H
+
+static inline uintptr_t host_signal_pc(ucontext_t *uc)
+{
+ return uc->uc_mcontext.gregs[REG_RIP];
+}
+
+static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
+{
+ return uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe
+ && (uc->uc_mcontext.gregs[REG_ERR] & 0x2);
+}
+
+#endif
diff --git a/linux-user/hppa/cpu_loop.c b/linux-user/hppa/cpu_loop.c
index 81607a9b27..375576c8f0 100644
--- a/linux-user/hppa/cpu_loop.c
+++ b/linux-user/hppa/cpu_loop.c
@@ -144,29 +144,6 @@ void cpu_loop(CPUHPPAState *env)
env->iaoq_f = env->gr[31];
env->iaoq_b = env->gr[31] + 4;
break;
- case EXCP_ITLB_MISS:
- case EXCP_DTLB_MISS:
- case EXCP_NA_ITLB_MISS:
- case EXCP_NA_DTLB_MISS:
- case EXCP_IMP:
- case EXCP_DMP:
- case EXCP_DMB:
- case EXCP_PAGE_REF:
- case EXCP_DMAR:
- case EXCP_DMPI:
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SEGV_ACCERR;
- info._sifields._sigfault._addr = env->cr[CR_IOR];
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case EXCP_UNALIGN:
- info.si_signo = TARGET_SIGBUS;
- info.si_errno = 0;
- info.si_code = 0;
- info._sifields._sigfault._addr = env->cr[CR_IOR];
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
case EXCP_ILL:
case EXCP_PRIV_OPR:
case EXCP_PRIV_REG:
diff --git a/linux-user/m68k/cpu_loop.c b/linux-user/m68k/cpu_loop.c
index ebf32be78f..790bd558c3 100644
--- a/linux-user/m68k/cpu_loop.c
+++ b/linux-user/m68k/cpu_loop.c
@@ -90,16 +90,6 @@ void cpu_loop(CPUM68KState *env)
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
break;
- case EXCP_ACCESS:
- {
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- /* XXX: check env->error_code */
- info.si_code = TARGET_SEGV_MAPERR;
- info._sifields._sigfault._addr = env->mmu.ar;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- break;
case EXCP_DEBUG:
info.si_signo = TARGET_SIGTRAP;
info.si_errno = 0;
diff --git a/linux-user/microblaze/cpu_loop.c b/linux-user/microblaze/cpu_loop.c
index 52222eb93f..a94467dd2d 100644
--- a/linux-user/microblaze/cpu_loop.c
+++ b/linux-user/microblaze/cpu_loop.c
@@ -37,16 +37,6 @@ void cpu_loop(CPUMBState *env)
process_queued_cpu_work(cs);
switch (trapnr) {
- case 0xaa:
- {
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- /* XXX: check env->error_code */
- info.si_code = TARGET_SEGV_MAPERR;
- info._sifields._sigfault._addr = 0;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- break;
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
break;
diff --git a/linux-user/mips/cpu_loop.c b/linux-user/mips/cpu_loop.c
index cb03fb066b..b735c99a24 100644
--- a/linux-user/mips/cpu_loop.c
+++ b/linux-user/mips/cpu_loop.c
@@ -158,17 +158,6 @@ done_syscall:
}
env->active_tc.gpr[2] = ret;
break;
- case EXCP_TLBL:
- case EXCP_TLBS:
- case EXCP_AdEL:
- case EXCP_AdES:
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- /* XXX: check env->error_code */
- info.si_code = TARGET_SEGV_MAPERR;
- info._sifields._sigfault._addr = env->CP0_BadVAddr;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
case EXCP_CpU:
case EXCP_RI:
info.si_signo = TARGET_SIGILL;
diff --git a/linux-user/openrisc/cpu_loop.c b/linux-user/openrisc/cpu_loop.c
index f6360db47c..3cfdbbf037 100644
--- a/linux-user/openrisc/cpu_loop.c
+++ b/linux-user/openrisc/cpu_loop.c
@@ -54,15 +54,6 @@ void cpu_loop(CPUOpenRISCState *env)
cpu_set_gpr(env, 11, ret);
}
break;
- case EXCP_DPF:
- case EXCP_IPF:
- case EXCP_RANGE:
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SEGV_MAPERR;
- info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
case EXCP_ALIGN:
info.si_signo = TARGET_SIGBUS;
info.si_errno = 0;
@@ -77,13 +68,6 @@ void cpu_loop(CPUOpenRISCState *env)
info._sifields._sigfault._addr = env->pc;
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
- case EXCP_FPE:
- info.si_signo = TARGET_SIGFPE;
- info.si_errno = 0;
- info.si_code = 0;
- info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
case EXCP_INTERRUPT:
/* We processed the pending cpu work above. */
break;
@@ -96,6 +80,15 @@ void cpu_loop(CPUOpenRISCState *env)
case EXCP_ATOMIC:
cpu_exec_step_atomic(cs);
break;
+ case EXCP_RANGE:
+ /* Requires SR.OVE set, which linux-user won't do. */
+ cpu_abort(cs, "Unexpected RANGE exception");
+ case EXCP_FPE:
+ /*
+ * Requires FPSCR.FPEE set. Writes to FPSCR from usermode not
+ * yet enabled in kernel ABI, so linux-user does not either.
+ */
+ cpu_abort(cs, "Unexpected FPE exception");
default:
g_assert_not_reached();
}
diff --git a/linux-user/ppc/cpu_loop.c b/linux-user/ppc/cpu_loop.c
index 840b23736b..483e669300 100644
--- a/linux-user/ppc/cpu_loop.c
+++ b/linux-user/ppc/cpu_loop.c
@@ -162,14 +162,6 @@ void cpu_loop(CPUPPCState *env)
cpu_abort(cs, "External interrupt while in user mode. "
"Aborting\n");
break;
- case POWERPC_EXCP_ALIGN: /* Alignment exception */
- /* XXX: check this */
- info.si_signo = TARGET_SIGBUS;
- info.si_errno = 0;
- info.si_code = TARGET_BUS_ADRALN;
- info._sifields._sigfault._addr = env->nip;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
case POWERPC_EXCP_PROGRAM: /* Program exception */
case POWERPC_EXCP_HV_EMU: /* HV emulation */
/* XXX: check this */
diff --git a/linux-user/riscv/cpu_loop.c b/linux-user/riscv/cpu_loop.c
index e5bb6d908a..b301dac802 100644
--- a/linux-user/riscv/cpu_loop.c
+++ b/linux-user/riscv/cpu_loop.c
@@ -87,13 +87,6 @@ void cpu_loop(CPURISCVState *env)
sigcode = TARGET_TRAP_BRKPT;
sigaddr = env->pc;
break;
- case RISCV_EXCP_INST_PAGE_FAULT:
- case RISCV_EXCP_LOAD_PAGE_FAULT:
- case RISCV_EXCP_STORE_PAGE_FAULT:
- signum = TARGET_SIGSEGV;
- sigcode = TARGET_SEGV_MAPERR;
- sigaddr = env->badaddr;
- break;
case RISCV_EXCP_SEMIHOST:
env->gpr[xA0] = do_common_semihosting(cs);
env->pc += 4;
diff --git a/linux-user/s390x/cpu_loop.c b/linux-user/s390x/cpu_loop.c
index 69b69981f6..d089c8417e 100644
--- a/linux-user/s390x/cpu_loop.c
+++ b/linux-user/s390x/cpu_loop.c
@@ -24,8 +24,6 @@
#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)
{
@@ -111,12 +109,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:
diff --git a/linux-user/sh4/cpu_loop.c b/linux-user/sh4/cpu_loop.c
index 65b8972e3c..ac9b01840c 100644
--- a/linux-user/sh4/cpu_loop.c
+++ b/linux-user/sh4/cpu_loop.c
@@ -65,14 +65,6 @@ void cpu_loop(CPUSH4State *env)
info.si_code = TARGET_TRAP_BRKPT;
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
- case 0xa0:
- case 0xc0:
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SEGV_MAPERR;
- info._sifields._sigfault._addr = env->tea;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
case EXCP_ATOMIC:
cpu_exec_step_atomic(cs);
arch_interrupt = false;
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 14d8fdfde1..81c45bfce9 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -19,6 +19,7 @@
#include "qemu/osdep.h"
#include "qemu/bitops.h"
#include "exec/gdbstub.h"
+#include "hw/core/tcg-cpu-ops.h"
#include <sys/ucontext.h>
#include <sys/resource.h>
@@ -29,6 +30,7 @@
#include "loader.h"
#include "trace.h"
#include "signal-common.h"
+#include "host-signal.h"
static struct target_sigaction sigact_table[TARGET_NSIG];
@@ -686,9 +688,38 @@ void force_sigsegv(int oldsig)
}
force_sig(TARGET_SIGSEGV);
}
-
#endif
+void cpu_loop_exit_sigsegv(CPUState *cpu, target_ulong addr,
+ MMUAccessType access_type, bool maperr, uintptr_t ra)
+{
+ const struct TCGCPUOps *tcg_ops = CPU_GET_CLASS(cpu)->tcg_ops;
+
+ if (tcg_ops->record_sigsegv) {
+ tcg_ops->record_sigsegv(cpu, addr, access_type, maperr, ra);
+ }
+
+ force_sig_fault(TARGET_SIGSEGV,
+ maperr ? TARGET_SEGV_MAPERR : TARGET_SEGV_ACCERR,
+ addr);
+ cpu->exception_index = EXCP_INTERRUPT;
+ cpu_loop_exit_restore(cpu, ra);
+}
+
+void cpu_loop_exit_sigbus(CPUState *cpu, target_ulong addr,
+ MMUAccessType access_type, uintptr_t ra)
+{
+ const struct TCGCPUOps *tcg_ops = CPU_GET_CLASS(cpu)->tcg_ops;
+
+ if (tcg_ops->record_sigbus) {
+ tcg_ops->record_sigbus(cpu, addr, access_type, ra);
+ }
+
+ force_sig_fault(TARGET_SIGBUS, TARGET_BUS_ADRALN, addr);
+ cpu->exception_index = EXCP_INTERRUPT;
+ cpu_loop_exit_restore(cpu, ra);
+}
+
/* abort execution with signal */
static void QEMU_NORETURN dump_core_and_abort(int target_sig)
{
@@ -769,41 +800,101 @@ static inline void rewind_if_in_safe_syscall(void *puc)
}
#endif
-static void host_signal_handler(int host_signum, siginfo_t *info,
- void *puc)
+static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
{
CPUArchState *env = thread_cpu->env_ptr;
CPUState *cpu = env_cpu(env);
TaskState *ts = cpu->opaque;
-
- int sig;
target_siginfo_t tinfo;
ucontext_t *uc = puc;
struct emulated_sigtable *k;
+ int guest_sig;
+ uintptr_t pc = 0;
+ bool sync_sig = false;
+
+ /*
+ * Non-spoofed SIGSEGV and SIGBUS are synchronous, and need special
+ * handling wrt signal blocking and unwinding.
+ */
+ if ((host_sig == SIGSEGV || host_sig == SIGBUS) && info->si_code > 0) {
+ MMUAccessType access_type;
+ uintptr_t host_addr;
+ abi_ptr guest_addr;
+ bool is_write;
+
+ host_addr = (uintptr_t)info->si_addr;
+
+ /*
+ * Convert forcefully to guest address space: addresses outside
+ * reserved_va are still valid to report via SEGV_MAPERR.
+ */
+ guest_addr = h2g_nocheck(host_addr);
- /* the CPU emulator uses some host signals to detect exceptions,
- we forward to it some signals */
- if ((host_signum == SIGSEGV || host_signum == SIGBUS)
- && info->si_code > 0) {
- if (cpu_signal_handler(host_signum, info, puc))
- return;
+ pc = host_signal_pc(uc);
+ is_write = host_signal_write(info, uc);
+ access_type = adjust_signal_pc(&pc, is_write);
+
+ if (host_sig == SIGSEGV) {
+ bool maperr = true;
+
+ if (info->si_code == SEGV_ACCERR && h2g_valid(host_addr)) {
+ /* If this was a write to a TB protected page, restart. */
+ if (is_write &&
+ handle_sigsegv_accerr_write(cpu, &uc->uc_sigmask,
+ pc, guest_addr)) {
+ return;
+ }
+
+ /*
+ * With reserved_va, the whole address space is PROT_NONE,
+ * which means that we may get ACCERR when we want MAPERR.
+ */
+ if (page_get_flags(guest_addr) & PAGE_VALID) {
+ maperr = false;
+ } else {
+ info->si_code = SEGV_MAPERR;
+ }
+ }
+
+ sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
+ cpu_loop_exit_sigsegv(cpu, guest_addr, access_type, maperr, pc);
+ } else {
+ sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
+ if (info->si_code == BUS_ADRALN) {
+ cpu_loop_exit_sigbus(cpu, guest_addr, access_type, pc);
+ }
+ }
+
+ sync_sig = true;
}
/* get target signal number */
- sig = host_to_target_signal(host_signum);
- if (sig < 1 || sig > TARGET_NSIG)
+ guest_sig = host_to_target_signal(host_sig);
+ if (guest_sig < 1 || guest_sig > TARGET_NSIG) {
return;
- trace_user_host_signal(env, host_signum, sig);
-
- rewind_if_in_safe_syscall(puc);
+ }
+ trace_user_host_signal(env, host_sig, guest_sig);
host_to_target_siginfo_noswap(&tinfo, info);
- k = &ts->sigtab[sig - 1];
+ k = &ts->sigtab[guest_sig - 1];
k->info = tinfo;
- k->pending = sig;
+ k->pending = guest_sig;
ts->signal_pending = 1;
- /* Block host signals until target signal handler entered. We
+ /*
+ * For synchronous signals, unwind the cpu state to the faulting
+ * insn and then exit back to the main loop so that the signal
+ * is delivered immediately.
+ */
+ if (sync_sig) {
+ cpu->exception_index = EXCP_INTERRUPT;
+ cpu_loop_exit_restore(cpu, pc);
+ }
+
+ rewind_if_in_safe_syscall(puc);
+
+ /*
+ * Block host signals until target signal handler entered. We
* can't block SIGSEGV or SIGBUS while we're executing guest
* code in case the guest code provokes one in the window between
* now and it getting out to the main loop. Signals will be
diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c
index ad29b4eb6a..0ba65e431c 100644
--- a/linux-user/sparc/cpu_loop.c
+++ b/linux-user/sparc/cpu_loop.c
@@ -219,17 +219,6 @@ void cpu_loop (CPUSPARCState *env)
case TT_WIN_UNF: /* window underflow */
restore_window(env);
break;
- case TT_TFAULT:
- case TT_DFAULT:
- {
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- /* XXX: check env->error_code */
- info.si_code = TARGET_SEGV_MAPERR;
- info._sifields._sigfault._addr = env->mmuregs[4];
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- break;
#else
case TT_SPILL: /* window overflow */
save_window(env);
@@ -237,20 +226,6 @@ void cpu_loop (CPUSPARCState *env)
case TT_FILL: /* window underflow */
restore_window(env);
break;
- case TT_TFAULT:
- case TT_DFAULT:
- {
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- /* XXX: check env->error_code */
- info.si_code = TARGET_SEGV_MAPERR;
- if (trapnr == TT_DFAULT)
- info._sifields._sigfault._addr = env->dmmu.mmuregs[4];
- else
- info._sifields._sigfault._addr = cpu_tsptr(env)->tpc;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- break;
#ifndef TARGET_ABI32
case 0x16e:
flush_windows(env);
diff --git a/linux-user/xtensa/cpu_loop.c b/linux-user/xtensa/cpu_loop.c
index 622afbcd34..a83490ab35 100644
--- a/linux-user/xtensa/cpu_loop.c
+++ b/linux-user/xtensa/cpu_loop.c
@@ -226,15 +226,6 @@ void cpu_loop(CPUXtensaState *env)
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
- case LOAD_PROHIBITED_CAUSE:
- case STORE_PROHIBITED_CAUSE:
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SEGV_ACCERR;
- info._sifields._sigfault._addr = env->sregs[EXCVADDR];
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
-
default:
fprintf(stderr, "exccause = %d\n", env->sregs[EXCCAUSE]);
g_assert_not_reached();