aboutsummaryrefslogtreecommitdiffstats
path: root/linux-user/host
diff options
context:
space:
mode:
Diffstat (limited to 'linux-user/host')
-rw-r--r--linux-user/host/aarch64/host-signal.h79
-rw-r--r--linux-user/host/aarch64/hostdep.h18
-rw-r--r--linux-user/host/aarch64/safe-syscall.inc.S75
-rw-r--r--linux-user/host/alpha/host-signal.h47
-rw-r--r--linux-user/host/arm/host-signal.h35
-rw-r--r--linux-user/host/arm/hostdep.h18
-rw-r--r--linux-user/host/arm/safe-syscall.inc.S90
-rw-r--r--linux-user/host/i386/host-signal.h30
-rw-r--r--linux-user/host/i386/hostdep.h18
-rw-r--r--linux-user/host/i386/safe-syscall.inc.S100
-rw-r--r--linux-user/host/ia64/hostdep.h15
-rw-r--r--linux-user/host/mips/host-signal.h67
-rw-r--r--linux-user/host/mips/hostdep.h15
-rw-r--r--linux-user/host/ppc/host-signal.h30
-rw-r--r--linux-user/host/ppc/hostdep.h15
-rw-r--r--linux-user/host/ppc64/host-signal.h1
-rw-r--r--linux-user/host/ppc64/hostdep.h18
-rw-r--r--linux-user/host/ppc64/safe-syscall.inc.S96
-rw-r--r--linux-user/host/riscv/host-signal.h63
-rw-r--r--linux-user/host/riscv/hostdep.h14
-rw-r--r--linux-user/host/riscv/safe-syscall.inc.S77
-rw-r--r--linux-user/host/s390/host-signal.h98
-rw-r--r--linux-user/host/s390/hostdep.h15
-rw-r--r--linux-user/host/s390x/host-signal.h1
-rw-r--r--linux-user/host/s390x/hostdep.h18
-rw-r--r--linux-user/host/s390x/safe-syscall.inc.S90
-rw-r--r--linux-user/host/sparc/host-signal.h63
-rw-r--r--linux-user/host/sparc/hostdep.h15
-rw-r--r--linux-user/host/sparc64/host-signal.h1
-rw-r--r--linux-user/host/sparc64/hostdep.h15
-rw-r--r--linux-user/host/x32/host-signal.h1
-rw-r--r--linux-user/host/x32/hostdep.h15
-rw-r--r--linux-user/host/x86_64/host-signal.h29
-rw-r--r--linux-user/host/x86_64/hostdep.h18
-rw-r--r--linux-user/host/x86_64/safe-syscall.inc.S91
35 files changed, 1391 insertions, 0 deletions
diff --git a/linux-user/host/aarch64/host-signal.h b/linux-user/host/aarch64/host-signal.h
new file mode 100644
index 000000000..9770b36dc
--- /dev/null
+++ b/linux-user/host/aarch64/host-signal.h
@@ -0,0 +1,79 @@
+/*
+ * 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 void host_signal_set_pc(ucontext_t *uc, uintptr_t pc)
+{
+ uc->uc_mcontext.pc = 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/aarch64/hostdep.h b/linux-user/host/aarch64/hostdep.h
new file mode 100644
index 000000000..39299d798
--- /dev/null
+++ b/linux-user/host/aarch64/hostdep.h
@@ -0,0 +1,18 @@
+/*
+ * hostdep.h : things which are dependent on the host architecture
+ *
+ * * Written by Peter Maydell <peter.maydell@linaro.org>
+ *
+ * Copyright (C) 2016 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 AARCH64_HOSTDEP_H
+#define AARCH64_HOSTDEP_H
+
+/* We have a safe-syscall.inc.S */
+#define HAVE_SAFE_SYSCALL
+
+#endif
diff --git a/linux-user/host/aarch64/safe-syscall.inc.S b/linux-user/host/aarch64/safe-syscall.inc.S
new file mode 100644
index 000000000..bc1f5a979
--- /dev/null
+++ b/linux-user/host/aarch64/safe-syscall.inc.S
@@ -0,0 +1,75 @@
+/*
+ * safe-syscall.inc.S : host-specific assembly fragment
+ * to handle signals occurring at the same time as system calls.
+ * This is intended to be included by linux-user/safe-syscall.S
+ *
+ * Written by Richard Henderson <rth@twiddle.net>
+ * Copyright (C) 2016 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+ .global safe_syscall_base
+ .global safe_syscall_start
+ .global safe_syscall_end
+ .type safe_syscall_base, #function
+ .type safe_syscall_start, #function
+ .type safe_syscall_end, #function
+
+ /* This is the entry point for making a system call. The calling
+ * convention here is that of a C varargs function with the
+ * first argument an 'int *' to the signal_pending flag, the
+ * second one the system call number (as a 'long'), and all further
+ * arguments being syscall arguments (also 'long').
+ * We return a long which is the syscall's return value, which
+ * may be negative-errno on failure. Conversion to the
+ * -1-and-errno-set convention is done by the calling wrapper.
+ */
+safe_syscall_base:
+ .cfi_startproc
+ /* The syscall calling convention isn't the same as the
+ * C one:
+ * we enter with x0 == *signal_pending
+ * x1 == syscall number
+ * x2 ... x7, (stack) == syscall arguments
+ * and return the result in x0
+ * and the syscall instruction needs
+ * x8 == syscall number
+ * x0 ... x6 == syscall arguments
+ * and returns the result in x0
+ * Shuffle everything around appropriately.
+ */
+ mov x9, x0 /* signal_pending pointer */
+ mov x8, x1 /* syscall number */
+ mov x0, x2 /* syscall arguments */
+ mov x1, x3
+ mov x2, x4
+ mov x3, x5
+ mov x4, x6
+ mov x5, x7
+ ldr x6, [sp]
+
+ /* This next sequence of code works in conjunction with the
+ * rewind_if_safe_syscall_function(). If a signal is taken
+ * and the interrupted PC is anywhere between 'safe_syscall_start'
+ * and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
+ * The code sequence must therefore be able to cope with this, and
+ * the syscall instruction must be the final one in the sequence.
+ */
+safe_syscall_start:
+ /* if signal_pending is non-zero, don't do the call */
+ ldr w10, [x9]
+ cbnz w10, 0f
+ svc 0x0
+safe_syscall_end:
+ /* code path for having successfully executed the syscall */
+ ret
+
+0:
+ /* code path when we didn't execute the syscall */
+ mov x0, #-TARGET_ERESTARTSYS
+ ret
+ .cfi_endproc
+
+ .size safe_syscall_base, .-safe_syscall_base
diff --git a/linux-user/host/alpha/host-signal.h b/linux-user/host/alpha/host-signal.h
new file mode 100644
index 000000000..f4c942948
--- /dev/null
+++ b/linux-user/host/alpha/host-signal.h
@@ -0,0 +1,47 @@
+/*
+ * 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 void host_signal_set_pc(ucontext_t *uc, uintptr_t pc)
+{
+ uc->uc_mcontext.sc_pc = 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 000000000..6c095773c
--- /dev/null
+++ b/linux-user/host/arm/host-signal.h
@@ -0,0 +1,35 @@
+/*
+ * 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 void host_signal_set_pc(ucontext_t *uc, uintptr_t pc)
+{
+ uc->uc_mcontext.arm_pc = 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/arm/hostdep.h b/linux-user/host/arm/hostdep.h
new file mode 100644
index 000000000..86b137875
--- /dev/null
+++ b/linux-user/host/arm/hostdep.h
@@ -0,0 +1,18 @@
+/*
+ * hostdep.h : things which are dependent on the host architecture
+ *
+ * * Written by Peter Maydell <peter.maydell@linaro.org>
+ *
+ * Copyright (C) 2016 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 ARM_HOSTDEP_H
+#define ARM_HOSTDEP_H
+
+/* We have a safe-syscall.inc.S */
+#define HAVE_SAFE_SYSCALL
+
+#endif
diff --git a/linux-user/host/arm/safe-syscall.inc.S b/linux-user/host/arm/safe-syscall.inc.S
new file mode 100644
index 000000000..88c495850
--- /dev/null
+++ b/linux-user/host/arm/safe-syscall.inc.S
@@ -0,0 +1,90 @@
+/*
+ * safe-syscall.inc.S : host-specific assembly fragment
+ * to handle signals occurring at the same time as system calls.
+ * This is intended to be included by linux-user/safe-syscall.S
+ *
+ * Written by Richard Henderson <rth@twiddle.net>
+ * Copyright (C) 2016 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+ .global safe_syscall_base
+ .global safe_syscall_start
+ .global safe_syscall_end
+ .type safe_syscall_base, %function
+
+ .cfi_sections .debug_frame
+
+ .text
+ .syntax unified
+ .arm
+ .align 2
+
+ /* This is the entry point for making a system call. The calling
+ * convention here is that of a C varargs function with the
+ * first argument an 'int *' to the signal_pending flag, the
+ * second one the system call number (as a 'long'), and all further
+ * arguments being syscall arguments (also 'long').
+ * We return a long which is the syscall's return value, which
+ * may be negative-errno on failure. Conversion to the
+ * -1-and-errno-set convention is done by the calling wrapper.
+ */
+safe_syscall_base:
+ .fnstart
+ .cfi_startproc
+ mov r12, sp /* save entry stack */
+ push { r4, r5, r6, r7, r8, lr }
+ .save { r4, r5, r6, r7, r8, lr }
+ .cfi_adjust_cfa_offset 24
+ .cfi_rel_offset r4, 0
+ .cfi_rel_offset r5, 4
+ .cfi_rel_offset r6, 8
+ .cfi_rel_offset r7, 12
+ .cfi_rel_offset r8, 16
+ .cfi_rel_offset lr, 20
+
+ /* The syscall calling convention isn't the same as the C one:
+ * we enter with r0 == *signal_pending
+ * r1 == syscall number
+ * r2, r3, [sp+0] ... [sp+12] == syscall arguments
+ * and return the result in r0
+ * and the syscall instruction needs
+ * r7 == syscall number
+ * r0 ... r6 == syscall arguments
+ * and returns the result in r0
+ * Shuffle everything around appropriately.
+ * Note the 16 bytes that we pushed to save registers.
+ */
+ mov r8, r0 /* copy signal_pending */
+ mov r7, r1 /* syscall number */
+ mov r0, r2 /* syscall args */
+ mov r1, r3
+ ldm r12, { r2, r3, r4, r5, r6 }
+
+ /* This next sequence of code works in conjunction with the
+ * rewind_if_safe_syscall_function(). If a signal is taken
+ * and the interrupted PC is anywhere between 'safe_syscall_start'
+ * and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
+ * The code sequence must therefore be able to cope with this, and
+ * the syscall instruction must be the final one in the sequence.
+ */
+safe_syscall_start:
+ /* if signal_pending is non-zero, don't do the call */
+ ldr r12, [r8] /* signal_pending */
+ tst r12, r12
+ bne 1f
+ swi 0
+safe_syscall_end:
+ /* code path for having successfully executed the syscall */
+ pop { r4, r5, r6, r7, r8, pc }
+
+1:
+ /* code path when we didn't execute the syscall */
+ ldr r0, =-TARGET_ERESTARTSYS
+ pop { r4, r5, r6, r7, r8, pc }
+ .fnend
+ .cfi_endproc
+
+ .size safe_syscall_base, .-safe_syscall_base
diff --git a/linux-user/host/i386/host-signal.h b/linux-user/host/i386/host-signal.h
new file mode 100644
index 000000000..abe1ece5c
--- /dev/null
+++ b/linux-user/host/i386/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 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 void host_signal_set_pc(ucontext_t *uc, uintptr_t pc)
+{
+ uc->uc_mcontext.gregs[REG_EIP] = pc;
+}
+
+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/i386/hostdep.h b/linux-user/host/i386/hostdep.h
new file mode 100644
index 000000000..ce7136501
--- /dev/null
+++ b/linux-user/host/i386/hostdep.h
@@ -0,0 +1,18 @@
+/*
+ * hostdep.h : things which are dependent on the host architecture
+ *
+ * * Written by Peter Maydell <peter.maydell@linaro.org>
+ *
+ * Copyright (C) 2016 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 I386_HOSTDEP_H
+#define I386_HOSTDEP_H
+
+/* We have a safe-syscall.inc.S */
+#define HAVE_SAFE_SYSCALL
+
+#endif
diff --git a/linux-user/host/i386/safe-syscall.inc.S b/linux-user/host/i386/safe-syscall.inc.S
new file mode 100644
index 000000000..9e58fc650
--- /dev/null
+++ b/linux-user/host/i386/safe-syscall.inc.S
@@ -0,0 +1,100 @@
+/*
+ * safe-syscall.inc.S : host-specific assembly fragment
+ * to handle signals occurring at the same time as system calls.
+ * This is intended to be included by linux-user/safe-syscall.S
+ *
+ * Written by Richard Henderson <rth@twiddle.net>
+ * Copyright (C) 2016 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+ .global safe_syscall_base
+ .global safe_syscall_start
+ .global safe_syscall_end
+ .type safe_syscall_base, @function
+
+ /* This is the entry point for making a system call. The calling
+ * convention here is that of a C varargs function with the
+ * first argument an 'int *' to the signal_pending flag, the
+ * second one the system call number (as a 'long'), and all further
+ * arguments being syscall arguments (also 'long').
+ * We return a long which is the syscall's return value, which
+ * may be negative-errno on failure. Conversion to the
+ * -1-and-errno-set convention is done by the calling wrapper.
+ */
+safe_syscall_base:
+ .cfi_startproc
+ push %ebp
+ .cfi_adjust_cfa_offset 4
+ .cfi_rel_offset ebp, 0
+ push %esi
+ .cfi_adjust_cfa_offset 4
+ .cfi_rel_offset esi, 0
+ push %edi
+ .cfi_adjust_cfa_offset 4
+ .cfi_rel_offset edi, 0
+ push %ebx
+ .cfi_adjust_cfa_offset 4
+ .cfi_rel_offset ebx, 0
+
+ /* The syscall calling convention isn't the same as the C one:
+ * we enter with 0(%esp) == return address
+ * 4(%esp) == *signal_pending
+ * 8(%esp) == syscall number
+ * 12(%esp) ... 32(%esp) == syscall arguments
+ * and return the result in eax
+ * and the syscall instruction needs
+ * eax == syscall number
+ * ebx, ecx, edx, esi, edi, ebp == syscall arguments
+ * and returns the result in eax
+ * Shuffle everything around appropriately.
+ * Note the 16 bytes that we pushed to save registers.
+ */
+ mov 12+16(%esp), %ebx /* the syscall arguments */
+ mov 16+16(%esp), %ecx
+ mov 20+16(%esp), %edx
+ mov 24+16(%esp), %esi
+ mov 28+16(%esp), %edi
+ mov 32+16(%esp), %ebp
+
+ /* This next sequence of code works in conjunction with the
+ * rewind_if_safe_syscall_function(). If a signal is taken
+ * and the interrupted PC is anywhere between 'safe_syscall_start'
+ * and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
+ * The code sequence must therefore be able to cope with this, and
+ * the syscall instruction must be the final one in the sequence.
+ */
+safe_syscall_start:
+ /* if signal_pending is non-zero, don't do the call */
+ mov 4+16(%esp), %eax /* signal_pending */
+ cmpl $0, (%eax)
+ jnz 1f
+ mov 8+16(%esp), %eax /* syscall number */
+ int $0x80
+safe_syscall_end:
+ /* code path for having successfully executed the syscall */
+ pop %ebx
+ .cfi_remember_state
+ .cfi_adjust_cfa_offset -4
+ .cfi_restore ebx
+ pop %edi
+ .cfi_adjust_cfa_offset -4
+ .cfi_restore edi
+ pop %esi
+ .cfi_adjust_cfa_offset -4
+ .cfi_restore esi
+ pop %ebp
+ .cfi_adjust_cfa_offset -4
+ .cfi_restore ebp
+ ret
+
+1:
+ /* code path when we didn't execute the syscall */
+ .cfi_restore_state
+ mov $-TARGET_ERESTARTSYS, %eax
+ jmp safe_syscall_end
+ .cfi_endproc
+
+ .size safe_syscall_base, .-safe_syscall_base
diff --git a/linux-user/host/ia64/hostdep.h b/linux-user/host/ia64/hostdep.h
new file mode 100644
index 000000000..263bf7658
--- /dev/null
+++ b/linux-user/host/ia64/hostdep.h
@@ -0,0 +1,15 @@
+/*
+ * hostdep.h : things which are dependent on the host architecture
+ *
+ * * Written by Peter Maydell <peter.maydell@linaro.org>
+ *
+ * Copyright (C) 2016 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 IA64_HOSTDEP_H
+#define IA64_HOSTDEP_H
+
+#endif
diff --git a/linux-user/host/mips/host-signal.h b/linux-user/host/mips/host-signal.h
new file mode 100644
index 000000000..c666ed8c3
--- /dev/null
+++ b/linux-user/host/mips/host-signal.h
@@ -0,0 +1,67 @@
+/*
+ * 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;
+}
+
+static inline void host_signal_set_pc(ucontext_t *uc, uintptr_t pc)
+{
+ uc->uc_mcontext.pc = 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/mips/hostdep.h b/linux-user/host/mips/hostdep.h
new file mode 100644
index 000000000..ba111d75c
--- /dev/null
+++ b/linux-user/host/mips/hostdep.h
@@ -0,0 +1,15 @@
+/*
+ * hostdep.h : things which are dependent on the host architecture
+ *
+ * * Written by Peter Maydell <peter.maydell@linaro.org>
+ *
+ * Copyright (C) 2016 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 MIPS_HOSTDEP_H
+#define MIPS_HOSTDEP_H
+
+#endif
diff --git a/linux-user/host/ppc/host-signal.h b/linux-user/host/ppc/host-signal.h
new file mode 100644
index 000000000..1d8e658ff
--- /dev/null
+++ b/linux-user/host/ppc/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 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 void host_signal_set_pc(ucontext_t *uc, uintptr_t pc)
+{
+ uc->uc_mcontext.regs->nip = pc;
+}
+
+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/ppc/hostdep.h b/linux-user/host/ppc/hostdep.h
new file mode 100644
index 000000000..23d8bd9d4
--- /dev/null
+++ b/linux-user/host/ppc/hostdep.h
@@ -0,0 +1,15 @@
+/*
+ * hostdep.h : things which are dependent on the host architecture
+ *
+ * * Written by Peter Maydell <peter.maydell@linaro.org>
+ *
+ * Copyright (C) 2016 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 PPC_HOSTDEP_H
+#define PPC_HOSTDEP_H
+
+#endif
diff --git a/linux-user/host/ppc64/host-signal.h b/linux-user/host/ppc64/host-signal.h
new file mode 100644
index 000000000..a353c22a9
--- /dev/null
+++ b/linux-user/host/ppc64/host-signal.h
@@ -0,0 +1 @@
+#include "../ppc/host-signal.h"
diff --git a/linux-user/host/ppc64/hostdep.h b/linux-user/host/ppc64/hostdep.h
new file mode 100644
index 000000000..0c290dd90
--- /dev/null
+++ b/linux-user/host/ppc64/hostdep.h
@@ -0,0 +1,18 @@
+/*
+ * hostdep.h : things which are dependent on the host architecture
+ *
+ * * Written by Peter Maydell <peter.maydell@linaro.org>
+ *
+ * Copyright (C) 2016 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 PPC64_HOSTDEP_H
+#define PPC64_HOSTDEP_H
+
+/* We have a safe-syscall.inc.S */
+#define HAVE_SAFE_SYSCALL
+
+#endif
diff --git a/linux-user/host/ppc64/safe-syscall.inc.S b/linux-user/host/ppc64/safe-syscall.inc.S
new file mode 100644
index 000000000..875133173
--- /dev/null
+++ b/linux-user/host/ppc64/safe-syscall.inc.S
@@ -0,0 +1,96 @@
+/*
+ * safe-syscall.inc.S : host-specific assembly fragment
+ * to handle signals occurring at the same time as system calls.
+ * This is intended to be included by linux-user/safe-syscall.S
+ *
+ * Written by Richard Henderson <rth@twiddle.net>
+ * Copyright (C) 2016 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+ .global safe_syscall_base
+ .global safe_syscall_start
+ .global safe_syscall_end
+ .type safe_syscall_base, @function
+
+ .text
+
+ /* This is the entry point for making a system call. The calling
+ * convention here is that of a C varargs function with the
+ * first argument an 'int *' to the signal_pending flag, the
+ * second one the system call number (as a 'long'), and all further
+ * arguments being syscall arguments (also 'long').
+ * We return a long which is the syscall's return value, which
+ * may be negative-errno on failure. Conversion to the
+ * -1-and-errno-set convention is done by the calling wrapper.
+ */
+#if _CALL_ELF == 2
+safe_syscall_base:
+ .cfi_startproc
+ .localentry safe_syscall_base,0
+#else
+ .section ".opd","aw"
+ .align 3
+safe_syscall_base:
+ .quad .L.safe_syscall_base,.TOC.@tocbase,0
+ .previous
+.L.safe_syscall_base:
+ .cfi_startproc
+#endif
+ /* We enter with r3 == *signal_pending
+ * r4 == syscall number
+ * r5 ... r10 == syscall arguments
+ * and return the result in r3
+ * and the syscall instruction needs
+ * r0 == syscall number
+ * r3 ... r8 == syscall arguments
+ * and returns the result in r3
+ * Shuffle everything around appropriately.
+ */
+ std 14, 16(1) /* Preserve r14 in SP+16 */
+ .cfi_offset 14, 16
+ mr 14, 3 /* signal_pending */
+ mr 0, 4 /* syscall number */
+ mr 3, 5 /* syscall arguments */
+ mr 4, 6
+ mr 5, 7
+ mr 6, 8
+ mr 7, 9
+ mr 8, 10
+
+ /* This next sequence of code works in conjunction with the
+ * rewind_if_safe_syscall_function(). If a signal is taken
+ * and the interrupted PC is anywhere between 'safe_syscall_start'
+ * and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
+ * The code sequence must therefore be able to cope with this, and
+ * the syscall instruction must be the final one in the sequence.
+ */
+safe_syscall_start:
+ /* if signal_pending is non-zero, don't do the call */
+ lwz 12, 0(14)
+ cmpwi 0, 12, 0
+ bne- 0f
+ sc
+safe_syscall_end:
+ /* code path when we did execute the syscall */
+ ld 14, 16(1) /* restore r14 to its original value */
+ bnslr+
+
+ /* syscall failed; return negative errno */
+ neg 3, 3
+ blr
+
+ /* code path when we didn't execute the syscall */
+0: addi 3, 0, -TARGET_ERESTARTSYS
+ ld 14, 16(1) /* restore r14 to its original value */
+ blr
+ .cfi_endproc
+
+#if _CALL_ELF == 2
+ .size safe_syscall_base, .-safe_syscall_base
+#else
+ .size safe_syscall_base, .-.L.safe_syscall_base
+ .size .L.safe_syscall_base, .-.L.safe_syscall_base
+#endif
diff --git a/linux-user/host/riscv/host-signal.h b/linux-user/host/riscv/host-signal.h
new file mode 100644
index 000000000..a4f170efb
--- /dev/null
+++ b/linux-user/host/riscv/host-signal.h
@@ -0,0 +1,63 @@
+/*
+ * 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 void host_signal_set_pc(ucontext_t *uc, uintptr_t pc)
+{
+ uc->uc_mcontext.__gregs[REG_PC] = 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/riscv/hostdep.h b/linux-user/host/riscv/hostdep.h
new file mode 100644
index 000000000..7f67c2286
--- /dev/null
+++ b/linux-user/host/riscv/hostdep.h
@@ -0,0 +1,14 @@
+/*
+ * 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 RISCV_HOSTDEP_H
+#define RISCV_HOSTDEP_H
+
+/* We have a safe-syscall.inc.S */
+#define HAVE_SAFE_SYSCALL
+
+#endif
diff --git a/linux-user/host/riscv/safe-syscall.inc.S b/linux-user/host/riscv/safe-syscall.inc.S
new file mode 100644
index 000000000..9ca3fbfd1
--- /dev/null
+++ b/linux-user/host/riscv/safe-syscall.inc.S
@@ -0,0 +1,77 @@
+/*
+ * safe-syscall.inc.S : host-specific assembly fragment
+ * to handle signals occurring at the same time as system calls.
+ * This is intended to be included by linux-user/safe-syscall.S
+ *
+ * Written by Richard Henderson <rth@twiddle.net>
+ * Copyright (C) 2018 Linaro, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+ .global safe_syscall_base
+ .global safe_syscall_start
+ .global safe_syscall_end
+ .type safe_syscall_base, @function
+ .type safe_syscall_start, @function
+ .type safe_syscall_end, @function
+
+ /*
+ * This is the entry point for making a system call. The calling
+ * convention here is that of a C varargs function with the
+ * first argument an 'int *' to the signal_pending flag, the
+ * second one the system call number (as a 'long'), and all further
+ * arguments being syscall arguments (also 'long').
+ * We return a long which is the syscall's return value, which
+ * may be negative-errno on failure. Conversion to the
+ * -1-and-errno-set convention is done by the calling wrapper.
+ */
+safe_syscall_base:
+ .cfi_startproc
+ /*
+ * The syscall calling convention is nearly the same as C:
+ * we enter with a0 == *signal_pending
+ * a1 == syscall number
+ * a2 ... a7 == syscall arguments
+ * and return the result in a0
+ * and the syscall instruction needs
+ * a7 == syscall number
+ * a0 ... a5 == syscall arguments
+ * and returns the result in a0
+ * Shuffle everything around appropriately.
+ */
+ mv t0, a0 /* signal_pending pointer */
+ mv t1, a1 /* syscall number */
+ mv a0, a2 /* syscall arguments */
+ mv a1, a3
+ mv a2, a4
+ mv a3, a5
+ mv a4, a6
+ mv a5, a7
+ mv a7, t1
+
+ /*
+ * This next sequence of code works in conjunction with the
+ * rewind_if_safe_syscall_function(). If a signal is taken
+ * and the interrupted PC is anywhere between 'safe_syscall_start'
+ * and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
+ * The code sequence must therefore be able to cope with this, and
+ * the syscall instruction must be the final one in the sequence.
+ */
+safe_syscall_start:
+ /* If signal_pending is non-zero, don't do the call */
+ lw t1, 0(t0)
+ bnez t1, 0f
+ scall
+safe_syscall_end:
+ /* code path for having successfully executed the syscall */
+ ret
+
+0:
+ /* code path when we didn't execute the syscall */
+ li a0, -TARGET_ERESTARTSYS
+ ret
+ .cfi_endproc
+
+ .size safe_syscall_base, .-safe_syscall_base
diff --git a/linux-user/host/s390/host-signal.h b/linux-user/host/s390/host-signal.h
new file mode 100644
index 000000000..a524f2ab0
--- /dev/null
+++ b/linux-user/host/s390/host-signal.h
@@ -0,0 +1,98 @@
+/*
+ * 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 void host_signal_set_pc(ucontext_t *uc, uintptr_t pc)
+{
+ uc->uc_mcontext.psw.addr = pc;
+}
+
+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/s390/hostdep.h b/linux-user/host/s390/hostdep.h
new file mode 100644
index 000000000..afcba5a16
--- /dev/null
+++ b/linux-user/host/s390/hostdep.h
@@ -0,0 +1,15 @@
+/*
+ * hostdep.h : things which are dependent on the host architecture
+ *
+ * * Written by Peter Maydell <peter.maydell@linaro.org>
+ *
+ * Copyright (C) 2016 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 S390_HOSTDEP_H
+#define S390_HOSTDEP_H
+
+#endif
diff --git a/linux-user/host/s390x/host-signal.h b/linux-user/host/s390x/host-signal.h
new file mode 100644
index 000000000..0e83f9358
--- /dev/null
+++ b/linux-user/host/s390x/host-signal.h
@@ -0,0 +1 @@
+#include "../s390/host-signal.h"
diff --git a/linux-user/host/s390x/hostdep.h b/linux-user/host/s390x/hostdep.h
new file mode 100644
index 000000000..d80114585
--- /dev/null
+++ b/linux-user/host/s390x/hostdep.h
@@ -0,0 +1,18 @@
+/*
+ * hostdep.h : things which are dependent on the host architecture
+ *
+ * * Written by Peter Maydell <peter.maydell@linaro.org>
+ *
+ * Copyright (C) 2016 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 S390X_HOSTDEP_H
+#define S390X_HOSTDEP_H
+
+/* We have a safe-syscall.inc.S */
+#define HAVE_SAFE_SYSCALL
+
+#endif
diff --git a/linux-user/host/s390x/safe-syscall.inc.S b/linux-user/host/s390x/safe-syscall.inc.S
new file mode 100644
index 000000000..414b44ad3
--- /dev/null
+++ b/linux-user/host/s390x/safe-syscall.inc.S
@@ -0,0 +1,90 @@
+/*
+ * safe-syscall.inc.S : host-specific assembly fragment
+ * to handle signals occurring at the same time as system calls.
+ * This is intended to be included by linux-user/safe-syscall.S
+ *
+ * Written by Richard Henderson <rth@twiddle.net>
+ * Copyright (C) 2016 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+ .global safe_syscall_base
+ .global safe_syscall_start
+ .global safe_syscall_end
+ .type safe_syscall_base, @function
+
+ /* This is the entry point for making a system call. The calling
+ * convention here is that of a C varargs function with the
+ * first argument an 'int *' to the signal_pending flag, the
+ * second one the system call number (as a 'long'), and all further
+ * arguments being syscall arguments (also 'long').
+ * We return a long which is the syscall's return value, which
+ * may be negative-errno on failure. Conversion to the
+ * -1-and-errno-set convention is done by the calling wrapper.
+ */
+safe_syscall_base:
+ .cfi_startproc
+ stmg %r6,%r15,48(%r15) /* save all call-saved registers */
+ .cfi_offset %r15,-40
+ .cfi_offset %r14,-48
+ .cfi_offset %r13,-56
+ .cfi_offset %r12,-64
+ .cfi_offset %r11,-72
+ .cfi_offset %r10,-80
+ .cfi_offset %r9,-88
+ .cfi_offset %r8,-96
+ .cfi_offset %r7,-104
+ .cfi_offset %r6,-112
+ lgr %r1,%r15
+ lg %r0,8(%r15) /* load eos */
+ aghi %r15,-160
+ .cfi_adjust_cfa_offset 160
+ stg %r1,0(%r15) /* store back chain */
+ stg %r0,8(%r15) /* store eos */
+
+ /* The syscall calling convention isn't the same as the
+ * C one:
+ * we enter with r2 == *signal_pending
+ * r3 == syscall number
+ * r4, r5, r6, (stack) == syscall arguments
+ * and return the result in r2
+ * and the syscall instruction needs
+ * r1 == syscall number
+ * r2 ... r7 == syscall arguments
+ * and returns the result in r2
+ * Shuffle everything around appropriately.
+ */
+ lgr %r8,%r2 /* signal_pending pointer */
+ lgr %r1,%r3 /* syscall number */
+ lgr %r2,%r4 /* syscall args */
+ lgr %r3,%r5
+ lgr %r4,%r6
+ lmg %r5,%r7,320(%r15)
+
+ /* This next sequence of code works in conjunction with the
+ * rewind_if_safe_syscall_function(). If a signal is taken
+ * and the interrupted PC is anywhere between 'safe_syscall_start'
+ * and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
+ * The code sequence must therefore be able to cope with this, and
+ * the syscall instruction must be the final one in the sequence.
+ */
+safe_syscall_start:
+ /* if signal_pending is non-zero, don't do the call */
+ icm %r0,15,0(%r8)
+ jne 2f
+ svc 0
+safe_syscall_end:
+
+1: lg %r15,0(%r15) /* load back chain */
+ .cfi_remember_state
+ .cfi_adjust_cfa_offset -160
+ lmg %r6,%r15,48(%r15) /* load saved registers */
+ br %r14
+ .cfi_restore_state
+2: lghi %r2, -TARGET_ERESTARTSYS
+ j 1b
+ .cfi_endproc
+
+ .size safe_syscall_base, .-safe_syscall_base
diff --git a/linux-user/host/sparc/host-signal.h b/linux-user/host/sparc/host-signal.h
new file mode 100644
index 000000000..734293607
--- /dev/null
+++ b/linux-user/host/sparc/host-signal.h
@@ -0,0 +1,63 @@
+/*
+ * 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 void host_signal_set_pc(ucontext_t *uc, uintptr_t pc)
+{
+#ifdef __arch64__
+ uc->uc_mcontext.mc_gregs[MC_PC] = pc;
+#else
+ uc->uc_mcontext.gregs[REG_PC] = 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/sparc/hostdep.h b/linux-user/host/sparc/hostdep.h
new file mode 100644
index 000000000..391ad923c
--- /dev/null
+++ b/linux-user/host/sparc/hostdep.h
@@ -0,0 +1,15 @@
+/*
+ * hostdep.h : things which are dependent on the host architecture
+ *
+ * * Written by Peter Maydell <peter.maydell@linaro.org>
+ *
+ * Copyright (C) 2016 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 SPARC_HOSTDEP_H
+#define SPARC_HOSTDEP_H
+
+#endif
diff --git a/linux-user/host/sparc64/host-signal.h b/linux-user/host/sparc64/host-signal.h
new file mode 100644
index 000000000..1191fe2d4
--- /dev/null
+++ b/linux-user/host/sparc64/host-signal.h
@@ -0,0 +1 @@
+#include "../sparc/host-signal.h"
diff --git a/linux-user/host/sparc64/hostdep.h b/linux-user/host/sparc64/hostdep.h
new file mode 100644
index 000000000..ce3968fca
--- /dev/null
+++ b/linux-user/host/sparc64/hostdep.h
@@ -0,0 +1,15 @@
+/*
+ * hostdep.h : things which are dependent on the host architecture
+ *
+ * * Written by Peter Maydell <peter.maydell@linaro.org>
+ *
+ * Copyright (C) 2016 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 SPARC64_HOSTDEP_H
+#define SPARC64_HOSTDEP_H
+
+#endif
diff --git a/linux-user/host/x32/host-signal.h b/linux-user/host/x32/host-signal.h
new file mode 100644
index 000000000..26800591d
--- /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/x32/hostdep.h b/linux-user/host/x32/hostdep.h
new file mode 100644
index 000000000..2c2d6d37d
--- /dev/null
+++ b/linux-user/host/x32/hostdep.h
@@ -0,0 +1,15 @@
+/*
+ * hostdep.h : things which are dependent on the host architecture
+ *
+ * * Written by Peter Maydell <peter.maydell@linaro.org>
+ *
+ * Copyright (C) 2016 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 X32_HOSTDEP_H
+#define X32_HOSTDEP_H
+
+#endif
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 000000000..c71d597eb
--- /dev/null
+++ b/linux-user/host/x86_64/host-signal.h
@@ -0,0 +1,29 @@
+/*
+ * 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 void host_signal_set_pc(ucontext_t *uc, uintptr_t pc)
+{
+ uc->uc_mcontext.gregs[REG_RIP] = pc;
+}
+
+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/x86_64/hostdep.h b/linux-user/host/x86_64/hostdep.h
new file mode 100644
index 000000000..9c62bd26b
--- /dev/null
+++ b/linux-user/host/x86_64/hostdep.h
@@ -0,0 +1,18 @@
+/*
+ * hostdep.h : things which are dependent on the host architecture
+ *
+ * * Written by Peter Maydell <peter.maydell@linaro.org>
+ *
+ * Copyright (C) 2016 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_HOSTDEP_H
+#define X86_64_HOSTDEP_H
+
+/* We have a safe-syscall.inc.S */
+#define HAVE_SAFE_SYSCALL
+
+#endif
diff --git a/linux-user/host/x86_64/safe-syscall.inc.S b/linux-user/host/x86_64/safe-syscall.inc.S
new file mode 100644
index 000000000..f36992daa
--- /dev/null
+++ b/linux-user/host/x86_64/safe-syscall.inc.S
@@ -0,0 +1,91 @@
+/*
+ * safe-syscall.inc.S : host-specific assembly fragment
+ * to handle signals occurring at the same time as system calls.
+ * This is intended to be included by linux-user/safe-syscall.S
+ *
+ * Copyright (C) 2015 Timothy Edward Baldwin <T.E.Baldwin99@members.leeds.ac.uk>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+ .global safe_syscall_base
+ .global safe_syscall_start
+ .global safe_syscall_end
+ .type safe_syscall_base, @function
+
+ /* This is the entry point for making a system call. The calling
+ * convention here is that of a C varargs function with the
+ * first argument an 'int *' to the signal_pending flag, the
+ * second one the system call number (as a 'long'), and all further
+ * arguments being syscall arguments (also 'long').
+ * We return a long which is the syscall's return value, which
+ * may be negative-errno on failure. Conversion to the
+ * -1-and-errno-set convention is done by the calling wrapper.
+ */
+safe_syscall_base:
+ .cfi_startproc
+ /* This saves a frame pointer and aligns the stack for the syscall.
+ * (It's unclear if the syscall ABI has the same stack alignment
+ * requirements as the userspace function call ABI, but better safe than
+ * sorry. Appendix A2 of http://www.x86-64.org/documentation/abi.pdf
+ * does not list any ABI differences regarding stack alignment.)
+ */
+ push %rbp
+ .cfi_adjust_cfa_offset 8
+ .cfi_rel_offset rbp, 0
+
+ /* The syscall calling convention isn't the same as the
+ * C one:
+ * we enter with rdi == *signal_pending
+ * rsi == syscall number
+ * rdx, rcx, r8, r9, (stack), (stack) == syscall arguments
+ * and return the result in rax
+ * and the syscall instruction needs
+ * rax == syscall number
+ * rdi, rsi, rdx, r10, r8, r9 == syscall arguments
+ * and returns the result in rax
+ * Shuffle everything around appropriately.
+ * Note that syscall will trash rcx and r11.
+ */
+ mov %rsi, %rax /* syscall number */
+ mov %rdi, %rbp /* signal_pending pointer */
+ /* and the syscall arguments */
+ mov %rdx, %rdi
+ mov %rcx, %rsi
+ mov %r8, %rdx
+ mov %r9, %r10
+ mov 16(%rsp), %r8
+ mov 24(%rsp), %r9
+
+ /* This next sequence of code works in conjunction with the
+ * rewind_if_safe_syscall_function(). If a signal is taken
+ * and the interrupted PC is anywhere between 'safe_syscall_start'
+ * and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
+ * The code sequence must therefore be able to cope with this, and
+ * the syscall instruction must be the final one in the sequence.
+ */
+safe_syscall_start:
+ /* if signal_pending is non-zero, don't do the call */
+ cmpl $0, (%rbp)
+ jnz 1f
+ syscall
+safe_syscall_end:
+ /* code path for having successfully executed the syscall */
+ pop %rbp
+ .cfi_remember_state
+ .cfi_def_cfa_offset 8
+ .cfi_restore rbp
+ ret
+
+1:
+ /* code path when we didn't execute the syscall */
+ .cfi_restore_state
+ mov $-TARGET_ERESTARTSYS, %rax
+ pop %rbp
+ .cfi_def_cfa_offset 8
+ .cfi_restore rbp
+ ret
+ .cfi_endproc
+
+ .size safe_syscall_base, .-safe_syscall_base