diff options
80 files changed, 1097 insertions, 930 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 9a8d1bdf72..1de6ce6e44 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3077,8 +3077,9 @@ Usermode Emulation Overall usermode emulation M: Riku Voipio <riku.voipio@iki.fi> S: Maintained -F: thunk.c F: accel/tcg/user-exec*.c +F: include/user/ +F: common-user/ BSD user M: Warner Losh <imp@bsdimp.com> diff --git a/bsd-user/errno_defs.h b/bsd-user/errno_defs.h index 832671354f..73cfa24b7f 100644 --- a/bsd-user/errno_defs.h +++ b/bsd-user/errno_defs.h @@ -151,6 +151,10 @@ /* Internal errors: */ #define TARGET_EJUSTRETURN 254 /* Just return without modifing regs */ #define TARGET_ERESTART 255 /* Restart syscall */ -#define TARGET_ERESTARTSYS TARGET_ERESTART /* Linux compat */ + +#include "special-errno.h" + +_Static_assert(TARGET_ERESTART == QEMU_ERESTARTSYS, + "TARGET_ERESTART and QEMU_ERESTARTSYS expected to match"); #endif /* ! _ERRNO_DEFS_H_ */ diff --git a/bsd-user/meson.build b/bsd-user/meson.build index 87885d91ed..9fcb80c3fa 100644 --- a/bsd-user/meson.build +++ b/bsd-user/meson.build @@ -2,6 +2,10 @@ if not have_bsd_user subdir_done() endif +bsd_user_ss = ss.source_set() + +common_user_inc += include_directories('.') + bsd_user_ss.add(files( 'bsdload.c', 'elfload.c', @@ -15,3 +19,5 @@ bsd_user_ss.add(files( # Pull in the OS-specific build glue, if any subdir(targetos) + +specific_ss.add_all(when: 'CONFIG_BSD_USER', if_true: bsd_user_ss) diff --git a/bsd-user/special-errno.h b/bsd-user/special-errno.h new file mode 100644 index 0000000000..03599d9b5a --- /dev/null +++ b/bsd-user/special-errno.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * QEMU internal errno values for implementing user-only POSIX. + * + * Copyright (c) 2021 Linaro, Ltd. + */ + +#ifndef SPECIAL_ERRNO_H +#define SPECIAL_ERRNO_H + +/* + * All of these are QEMU internal, not visible to the guest. + * They should be chosen so as to not overlap with any host + * or guest errno. + */ + +/* + * This is returned when a system call should be restarted, to tell the + * main loop that it should wind the guest PC backwards so it will + * re-execute the syscall after handling any pending signals. + */ +#define QEMU_ERESTARTSYS 255 + +#endif /* SPECIAL_ERRNO_H */ diff --git a/common-user/host/aarch64/safe-syscall.inc.S b/common-user/host/aarch64/safe-syscall.inc.S new file mode 100644 index 0000000000..b8fd5b553e --- /dev/null +++ b/common-user/host/aarch64/safe-syscall.inc.S @@ -0,0 +1,88 @@ +/* + * 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 common-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'). + */ +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, 2f + svc 0x0 +safe_syscall_end: + + /* code path for having successfully executed the syscall */ +#if defined(__linux__) + /* Linux kernel returns (small) negative errno. */ + cmp x0, #-4096 + b.hi 0f +#elif defined(__FreeBSD__) + /* FreeBSD kernel returns positive errno and C bit set. */ + b.cs 1f +#else +#error "unsupported os" +#endif + ret + +#if defined(__linux__) + /* code path setting errno */ +0: neg w0, w0 + b safe_syscall_set_errno_tail +#endif + + /* code path when we didn't execute the syscall */ +2: mov w0, #QEMU_ERESTARTSYS +1: b safe_syscall_set_errno_tail + + .cfi_endproc + .size safe_syscall_base, .-safe_syscall_base diff --git a/common-user/host/arm/safe-syscall.inc.S b/common-user/host/arm/safe-syscall.inc.S new file mode 100644 index 0000000000..bbfb89634e --- /dev/null +++ b/common-user/host/arm/safe-syscall.inc.S @@ -0,0 +1,108 @@ +/* + * 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 common-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'). + */ +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 2f + swi 0 +safe_syscall_end: + + /* code path for having successfully executed the syscall */ +#if defined(__linux__) + /* Linux kernel returns (small) negative errno. */ + cmp r0, #-4096 + neghi r0, r0 + bhi 1f +#elif defined(__FreeBSD__) + /* FreeBSD kernel returns positive errno and C bit set. */ + bcs 1f +#else +#error "unsupported os" +#endif + pop { r4, r5, r6, r7, r8, pc } + + /* code path when we didn't execute the syscall */ +2: mov r0, #QEMU_ERESTARTSYS + + /* code path setting errno */ +1: pop { r4, r5, r6, r7, r8, lr } + .cfi_adjust_cfa_offset -24 + .cfi_restore r4 + .cfi_restore r5 + .cfi_restore r6 + .cfi_restore r7 + .cfi_restore r8 + .cfi_restore lr + b safe_syscall_set_errno_tail + + .fnend + .cfi_endproc + .size safe_syscall_base, .-safe_syscall_base diff --git a/common-user/host/i386/safe-syscall.inc.S b/common-user/host/i386/safe-syscall.inc.S new file mode 100644 index 0000000000..baf5400a29 --- /dev/null +++ b/common-user/host/i386/safe-syscall.inc.S @@ -0,0 +1,126 @@ +/* + * 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 common-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'). + */ +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 2f + mov 8+16(%esp), %eax /* syscall number */ + int $0x80 +safe_syscall_end: + + /* code path for having successfully executed the syscall */ +#if defined(__linux__) + /* Linux kernel returns (small) negative errno. */ + cmp $-4095, %eax + jae 0f +#elif defined(__FreeBSD__) + /* FreeBSD kernel returns positive errno and C bit set. */ + jc 1f +#else +#error "unsupported os" +#endif + 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 + .cfi_restore_state + +#if defined(__linux__) +0: neg %eax + jmp 1f +#endif + + /* code path when we didn't execute the syscall */ +2: mov $QEMU_ERESTARTSYS, %eax + + /* code path setting errno */ +1: pop %ebx + .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 + jmp safe_syscall_set_errno_tail + + .cfi_endproc + .size safe_syscall_base, .-safe_syscall_base diff --git a/common-user/host/mips/safe-syscall.inc.S b/common-user/host/mips/safe-syscall.inc.S new file mode 100644 index 0000000000..fc75a337d1 --- /dev/null +++ b/common-user/host/mips/safe-syscall.inc.S @@ -0,0 +1,148 @@ +/* + * 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 common-user/safe-syscall.S + * + * Written by Richard Henderson <richard.henderson@linaro.org> + * Copyright (C) 2021 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. + */ + +#include "sys/regdef.h" +#include "sys/asm.h" + + .text + .set nomips16 + .set reorder + + .global safe_syscall_start + .global safe_syscall_end + .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'). + */ + +#if _MIPS_SIM == _ABIO32 +/* 8 * 4 = 32 for outgoing parameters; 1 * 4 for s0 save; 1 * 4 for align. */ +#define FRAME 40 +#define OFS_S0 32 +#else +/* 1 * 8 for s0 save; 1 * 8 for align. */ +#define FRAME 16 +#define OFS_S0 0 +#endif + + +NESTED(safe_syscall_base, FRAME, ra) + .cfi_startproc + PTR_ADDIU sp, sp, -FRAME + .cfi_adjust_cfa_offset FRAME + REG_S s0, OFS_S0(sp) + .cfi_rel_offset s0, OFS_S0 +#if _MIPS_SIM == _ABIO32 + /* + * The syscall calling convention is nearly the same as C: + * we enter with a0 == &signal_pending + * a1 == syscall number + * a2, a3, stack == syscall arguments + * and return the result in a0 + * and the syscall instruction needs + * v0 == syscall number + * a0 ... a3, stack == syscall arguments + * and returns the result in v0 + * Shuffle everything around appropriately. + */ + move s0, a0 /* signal_pending pointer */ + move v0, a1 /* syscall number */ + move a0, a2 /* syscall arguments */ + move a1, a3 + lw a2, FRAME+16(sp) + lw a3, FRAME+20(sp) + lw t4, FRAME+24(sp) + lw t5, FRAME+28(sp) + lw t6, FRAME+32(sp) + lw t7, FRAME+40(sp) + sw t4, 16(sp) + sw t5, 20(sp) + sw t6, 24(sp) + sw t7, 28(sp) +#else + /* + * 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 + * v0 == syscall number + * a0 ... a5 == syscall arguments + * and returns the result in v0 + * Shuffle everything around appropriately. + */ + move s0, a0 /* signal_pending pointer */ + move v0, a1 /* syscall number */ + move a0, a2 /* syscall arguments */ + move a1, a3 + move a2, a4 + move a3, a5 + move a4, a6 + move a5, a7 +#endif + + /* + * 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(s0) + bnez t1, 2f + syscall +safe_syscall_end: + + /* code path for having successfully executed the syscall */ + REG_L s0, OFS_S0(sp) + PTR_ADDIU sp, sp, FRAME + .cfi_remember_state + .cfi_adjust_cfa_offset -FRAME + .cfi_restore s0 + bnez a3, 1f + jr ra + .cfi_restore_state + + /* code path when we didn't execute the syscall */ +2: REG_L s0, OFS_S0(sp) + PTR_ADDIU sp, sp, FRAME + .cfi_adjust_cfa_offset -FRAME + .cfi_restore s0 + li v0, QEMU_ERESTARTSYS + + /* code path setting errno */ + /* + * We didn't setup GP on entry, optimistic of the syscall success. + * We must do so now to load the address of the helper, as required + * by the ABI, into t9. + * + * Note that SETUP_GPX and SETUP_GPX64 are themselves conditional, + * so we can simply let the one that's not empty succeed. + */ +1: USE_ALT_CP(t0) + SETUP_GPX(t1) + SETUP_GPX64(t0, t1) + PTR_LA t9, safe_syscall_set_errno_tail + jr t9 + + .cfi_endproc +END(safe_syscall_base) diff --git a/common-user/host/ppc64/safe-syscall.inc.S b/common-user/host/ppc64/safe-syscall.inc.S new file mode 100644 index 0000000000..947a850dfd --- /dev/null +++ b/common-user/host/ppc64/safe-syscall.inc.S @@ -0,0 +1,94 @@ +/* + * 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 common-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'). + */ +#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- 2f + sc +safe_syscall_end: + /* code path when we did execute the syscall */ + ld 14, 16(1) /* restore r14 */ + bso- 1f + blr + + /* code path when we didn't execute the syscall */ +2: ld 14, 16(1) /* restore r14 */ + addi 3, 0, QEMU_ERESTARTSYS + + /* code path setting errno */ +1: b safe_syscall_set_errno_tail + nop /* per abi, for the linker to modify */ + + .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/common-user/host/riscv/safe-syscall.inc.S b/common-user/host/riscv/safe-syscall.inc.S new file mode 100644 index 0000000000..dfe83c300e --- /dev/null +++ b/common-user/host/riscv/safe-syscall.inc.S @@ -0,0 +1,79 @@ +/* + * 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 common-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'). + */ +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, 2f + scall +safe_syscall_end: + /* code path for having successfully executed the syscall */ + li t2, -4096 + bgtu a0, t2, 0f + ret + + /* code path setting errno */ +0: neg a0, a0 + j safe_syscall_set_errno_tail + + /* code path when we didn't execute the syscall */ +2: li a0, QEMU_ERESTARTSYS + j safe_syscall_set_errno_tail + + .cfi_endproc + .size safe_syscall_base, .-safe_syscall_base diff --git a/common-user/host/s390x/safe-syscall.inc.S b/common-user/host/s390x/safe-syscall.inc.S new file mode 100644 index 0000000000..2ccbaa2402 --- /dev/null +++ b/common-user/host/s390x/safe-syscall.inc.S @@ -0,0 +1,98 @@ +/* + * 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 common-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'). + */ +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: + + /* code path for having successfully executed the syscall */ + lg %r15,0(%r15) /* load back chain */ + .cfi_remember_state + .cfi_adjust_cfa_offset -160 + lmg %r6,%r15,48(%r15) /* load saved registers */ + + lghi %r0, -4095 /* check for syscall error */ + clgr %r2, %r0 + blr %r14 /* return on success */ + lcr %r2, %r2 /* create positive errno */ + jg safe_syscall_set_errno_tail + .cfi_restore_state + + /* code path when we didn't execute the syscall */ +2: lg %r15,0(%r15) /* load back chain */ + .cfi_adjust_cfa_offset -160 + lmg %r6,%r15,48(%r15) /* load saved registers */ + lghi %r2, QEMU_ERESTARTSYS + jg safe_syscall_set_errno_tail + + .cfi_endproc + .size safe_syscall_base, .-safe_syscall_base diff --git a/common-user/host/sparc64/safe-syscall.inc.S b/common-user/host/sparc64/safe-syscall.inc.S new file mode 100644 index 0000000000..a2f2b9c967 --- /dev/null +++ b/common-user/host/sparc64/safe-syscall.inc.S @@ -0,0 +1,89 @@ +/* + * 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 common-user/safe-syscall.S + * + * Written by Richard Henderson <richard.henderson@linaro.org> + * Copyright (C) 2021 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. + */ + + .text + .balign 4 + + .register %g2, #scratch + .register %g3, #scratch + + .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 + +#define STACK_BIAS 2047 +#define PARAM(N) STACK_BIAS + N*8 + + /* + * 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'). + */ +safe_syscall_base: + .cfi_startproc + /* + * The syscall calling convention isn't the same as the C one: + * we enter with o0 == &signal_pending + * o1 == syscall number + * o2 ... o5, (stack) == syscall arguments + * and return the result in x0 + * and the syscall instruction needs + * g1 == syscall number + * o0 ... o5 == syscall arguments + * and returns the result in o0 + * Shuffle everything around appropriately. + */ + mov %o0, %g2 /* signal_pending pointer */ + mov %o1, %g1 /* syscall number */ + mov %o2, %o0 /* syscall arguments */ + mov %o3, %o1 + mov %o4, %o2 + mov %o5, %o3 + ldx [%sp + PARAM(6)], %o4 + ldx [%sp + PARAM(7)], %o5 + + /* + * 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 */ + lduw [%g2], %g3 + brnz,pn %g3, 2f + nop + ta 0x6d +safe_syscall_end: + /* code path for having successfully executed the syscall */ + bcs,pn %xcc, 1f + nop + ret + nop + + /* code path when we didn't execute the syscall */ +2: set QEMU_ERESTARTSYS, %o0 + + /* code path setting errno */ +1: mov %o7, %g1 + call safe_syscall_set_errno_tail + mov %g1, %o7 + + .cfi_endproc + .size safe_syscall_base, .-safe_syscall_base diff --git a/linux-user/host/x86_64/safe-syscall.inc.S b/common-user/host/x86_64/safe-syscall.inc.S index f36992daa3..a20927a783 100644 --- a/linux-user/host/x86_64/safe-syscall.inc.S +++ b/common-user/host/x86_64/safe-syscall.inc.S @@ -1,7 +1,7 @@ /* * 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 + * This is intended to be included by common-user/safe-syscall.S * * Copyright (C) 2015 Timothy Edward Baldwin <T.E.Baldwin99@members.leeds.ac.uk> * @@ -19,9 +19,6 @@ * 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 @@ -35,9 +32,9 @@ safe_syscall_base: .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 + /* + * 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 @@ -67,25 +64,42 @@ safe_syscall_base: */ safe_syscall_start: /* if signal_pending is non-zero, don't do the call */ - cmpl $0, (%rbp) - jnz 1f + cmpl $0, (%rbp) + jnz 2f syscall safe_syscall_end: + /* code path for having successfully executed the syscall */ +#if defined(__linux__) + /* Linux kernel returns (small) negative errno. */ + cmp $-4095, %rax + jae 0f +#elif defined(__FreeBSD__) + /* FreeBSD kernel returns positive errno and C bit set. */ + jc 1f +#else +#error "unsupported os" +#endif pop %rbp .cfi_remember_state .cfi_def_cfa_offset 8 .cfi_restore rbp ret + .cfi_restore_state + +#if defined(__linux__) +0: neg %eax + jmp 1f +#endif -1: /* code path when we didn't execute the syscall */ - .cfi_restore_state - mov $-TARGET_ERESTARTSYS, %rax - pop %rbp +2: mov $QEMU_ERESTARTSYS, %eax + + /* code path setting errno */ +1: pop %rbp .cfi_def_cfa_offset 8 .cfi_restore rbp - ret + jmp safe_syscall_set_errno_tail .cfi_endproc .size safe_syscall_base, .-safe_syscall_base diff --git a/common-user/meson.build b/common-user/meson.build new file mode 100644 index 0000000000..5cb42bc664 --- /dev/null +++ b/common-user/meson.build @@ -0,0 +1,6 @@ +common_user_inc += include_directories('host/' / host_arch) + +common_user_ss.add(files( + 'safe-syscall.S', + 'safe-syscall-error.c', +)) diff --git a/common-user/safe-syscall-error.c b/common-user/safe-syscall-error.c new file mode 100644 index 0000000000..cf74b504f8 --- /dev/null +++ b/common-user/safe-syscall-error.c @@ -0,0 +1,25 @@ +/* + * safe-syscall-error.c: errno setting fragment + * This is intended to be invoked by safe-syscall.S + * + * Written by Richard Henderson <rth@twiddle.net> + * Copyright (C) 2021 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. + */ + +#include "qemu/osdep.h" +#include "user/safe-syscall.h" + +/* + * This is intended to be invoked via tail-call on the error path + * from the assembly in host/arch/safe-syscall.inc.S. This takes + * care of the host specific addressing of errno. + * Return -1 to finalize the return value for safe_syscall_base. + */ +long safe_syscall_set_errno_tail(int value) +{ + errno = value; + return -1; +} diff --git a/linux-user/safe-syscall.S b/common-user/safe-syscall.S index 42ea7c40ba..74f7e35694 100644 --- a/linux-user/safe-syscall.S +++ b/common-user/safe-syscall.S @@ -10,15 +10,12 @@ * See the COPYING file in the top-level directory. */ -#include "hostdep.h" -#include "target_errno_defs.h" +#include "special-errno.h" /* We have the correct host directory on our include path * so that this will pull in the right fragment for the architecture. */ -#ifdef HAVE_SAFE_SYSCALL #include "safe-syscall.inc.S" -#endif /* We must specifically say that we're happy for the stack to not be * executable, otherwise the toolchain will default to assuming our diff --git a/linux-user/safe-syscall.h b/include/user/safe-syscall.h index aaa9ffc0e2..61a04e2b5a 100644 --- a/linux-user/safe-syscall.h +++ b/include/user/safe-syscall.h @@ -25,10 +25,10 @@ * * Call a system call if guest signal not pending. * This has the same API as the libc syscall() function, except that it - * may return -1 with errno == TARGET_ERESTARTSYS if a signal was pending. + * may return -1 with errno == QEMU_ERESTARTSYS if a signal was pending. * * Returns: the system call result, or -1 with an error code in errno - * (Errnos are host errnos; we rely on TARGET_ERESTARTSYS not clashing + * (Errnos are host errnos; we rely on QEMU_ERESTARTSYS not clashing * with any of the host errno values.) */ @@ -81,7 +81,7 @@ * which are only technically blocking (ie which we know in practice won't * stay in the host kernel indefinitely) it's OK to use libc if necessary. * You must be able to cope with backing out correctly if some safe_syscall - * you make in the implementation returns either -TARGET_ERESTARTSYS or + * you make in the implementation returns either -QEMU_ERESTARTSYS or * EINTR though.) * * block_signals() cannot be used for interruptible syscalls. @@ -94,7 +94,7 @@ * handler checks the interrupted host PC against the addresse of that * known section. If the PC is before or at the address of the syscall * instruction then we change the PC to point at a "return - * -TARGET_ERESTARTSYS" code path instead, and then exit the signal handler + * -QEMU_ERESTARTSYS" code path instead, and then exit the signal handler * (causing the safe_syscall() call to immediately return that value). * Then in the main.c loop if we see this magic return value we adjust * the guest PC to wind it back to before the system call, and invoke @@ -124,34 +124,17 @@ * need to check SA_RESTART flags in QEMU or distinguish the various * kinds of restartability. */ -#ifdef HAVE_SAFE_SYSCALL + /* The core part of this function is implemented in assembly */ extern long safe_syscall_base(int *pending, long number, ...); +extern long safe_syscall_set_errno_tail(int value); + /* These are defined by the safe-syscall.inc.S file */ extern char safe_syscall_start[]; extern char safe_syscall_end[]; -#define safe_syscall(...) \ - ({ \ - long ret_; \ - int *psp_ = &((TaskState *)thread_cpu->opaque)->signal_pending; \ - ret_ = safe_syscall_base(psp_, __VA_ARGS__); \ - if (is_error(ret_)) { \ - errno = -ret_; \ - ret_ = -1; \ - } \ - ret_; \ - }) - -#else - -/* - * Fallback for architectures which don't yet provide a safe-syscall assembly - * fragment; note that this is racy! - * This should go away when all host architectures have been updated. - */ -#define safe_syscall syscall - -#endif +#define safe_syscall(...) \ + safe_syscall_base(&((TaskState *)thread_cpu->opaque)->signal_pending, \ + __VA_ARGS__) #endif diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c index f9f3473288..1737e2ea65 100644 --- a/linux-user/aarch64/cpu_loop.c +++ b/linux-user/aarch64/cpu_loop.c @@ -99,9 +99,9 @@ void cpu_loop(CPUARMState *env) env->xregs[4], env->xregs[5], 0, 0); - if (ret == -TARGET_ERESTARTSYS) { + if (ret == -QEMU_ERESTARTSYS) { env->pc -= 4; - } else if (ret != -TARGET_QEMU_ESIGRETURN) { + } else if (ret != -QEMU_ESIGRETURN) { env->xregs[0] = ret; } break; diff --git a/linux-user/aarch64/signal.c b/linux-user/aarch64/signal.c index 29c52db3f1..df9e39a4ba 100644 --- a/linux-user/aarch64/signal.c +++ b/linux-user/aarch64/signal.c @@ -556,12 +556,12 @@ long do_rt_sigreturn(CPUARMState *env) target_restore_altstack(&frame->uc.tuc_stack, env); unlock_user_struct(frame, frame_addr, 0); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; } long do_sigreturn(CPUARMState *env) diff --git a/linux-user/alpha/cpu_loop.c b/linux-user/alpha/cpu_loop.c index 4029849d5c..37c33f0ccd 100644 --- a/linux-user/alpha/cpu_loop.c +++ b/linux-user/alpha/cpu_loop.c @@ -98,11 +98,11 @@ void cpu_loop(CPUAlphaState *env) env->ir[IR_A2], env->ir[IR_A3], env->ir[IR_A4], env->ir[IR_A5], 0, 0); - if (sysret == -TARGET_ERESTARTSYS) { + if (sysret == -QEMU_ERESTARTSYS) { env->pc -= 4; break; } - if (sysret == -TARGET_QEMU_ESIGRETURN) { + if (sysret == -QEMU_ESIGRETURN) { break; } /* Syscall writes 0 to V0 to bypass error check, similar diff --git a/linux-user/alpha/signal.c b/linux-user/alpha/signal.c index bbe3dd175a..4ec42994d4 100644 --- a/linux-user/alpha/signal.c +++ b/linux-user/alpha/signal.c @@ -225,11 +225,11 @@ long do_sigreturn(CPUAlphaState *env) restore_sigcontext(env, sc); unlock_user_struct(sc, sc_addr, 0); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; badframe: force_sig(TARGET_SIGSEGV); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUAlphaState *env) @@ -249,13 +249,13 @@ long do_rt_sigreturn(CPUAlphaState *env) target_restore_altstack(&frame->uc.tuc_stack, env); unlock_user_struct(frame, frame_addr, 0); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; } void setup_sigtramp(abi_ulong sigtramp_page) diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c index 01cb6eb534..f153ab503a 100644 --- a/linux-user/arm/cpu_loop.c +++ b/linux-user/arm/cpu_loop.c @@ -407,9 +407,9 @@ void cpu_loop(CPUARMState *env) env->regs[4], env->regs[5], 0, 0); - if (ret == -TARGET_ERESTARTSYS) { + if (ret == -QEMU_ERESTARTSYS) { env->regs[15] -= env->thumb ? 2 : 4; - } else if (ret != -TARGET_QEMU_ESIGRETURN) { + } else if (ret != -QEMU_ESIGRETURN) { env->regs[0] = ret; } } diff --git a/linux-user/arm/signal.c b/linux-user/arm/signal.c index df9f8e8eb2..cf99fd7b8a 100644 --- a/linux-user/arm/signal.c +++ b/linux-user/arm/signal.c @@ -511,12 +511,12 @@ long do_sigreturn(CPUARMState *env) } unlock_user_struct(frame, frame_addr, 0); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUARMState *env) @@ -546,12 +546,12 @@ long do_rt_sigreturn(CPUARMState *env) } unlock_user_struct(frame, frame_addr, 0); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; } /* diff --git a/linux-user/cpu_loop-common.h b/linux-user/cpu_loop-common.h index 8828af28a4..dc0042e4de 100644 --- a/linux-user/cpu_loop-common.h +++ b/linux-user/cpu_loop-common.h @@ -21,6 +21,7 @@ #define CPU_LOOP_COMMON_H #include "exec/log.h" +#include "special-errno.h" #define EXCP_DUMP(env, fmt, ...) \ do { \ diff --git a/linux-user/cris/cpu_loop.c b/linux-user/cris/cpu_loop.c index 0d5d268609..5213aebf55 100644 --- a/linux-user/cris/cpu_loop.c +++ b/linux-user/cris/cpu_loop.c @@ -50,9 +50,9 @@ void cpu_loop(CPUCRISState *env) env->pregs[7], env->pregs[11], 0, 0); - if (ret == -TARGET_ERESTARTSYS) { + if (ret == -QEMU_ERESTARTSYS) { env->pc -= 2; - } else if (ret != -TARGET_QEMU_ESIGRETURN) { + } else if (ret != -QEMU_ESIGRETURN) { env->regs[10] = ret; } break; diff --git a/linux-user/cris/signal.c b/linux-user/cris/signal.c index 7f6aca934e..4f532b2903 100644 --- a/linux-user/cris/signal.c +++ b/linux-user/cris/signal.c @@ -177,10 +177,10 @@ long do_sigreturn(CPUCRISState *env) restore_sigcontext(&frame->sc, env); unlock_user_struct(frame, frame_addr, 0); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; badframe: force_sig(TARGET_SIGSEGV); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUCRISState *env) diff --git a/linux-user/generic/target_errno_defs.h b/linux-user/generic/target_errno_defs.h index 17d85e0b61..c2f9d403e7 100644 --- a/linux-user/generic/target_errno_defs.h +++ b/linux-user/generic/target_errno_defs.h @@ -147,21 +147,4 @@ #define TARGET_ERFKILL 132 /* Operation not possible due to RF-kill */ #define TARGET_EHWPOISON 133 /* Memory page has hardware error */ -/* QEMU internal, not visible to the guest. This is returned when a - * system call should be restarted, to tell the main loop that it - * should wind the guest PC backwards so it will re-execute the syscall - * after handling any pending signals. They match with the ones the guest - * kernel uses for the same purpose. - */ -#define TARGET_ERESTARTSYS 512 /* Restart system call (if SA_RESTART) */ - -/* QEMU internal, not visible to the guest. This is returned by the - * do_sigreturn() code after a successful sigreturn syscall, to indicate - * that it has correctly set the guest registers and so the main loop - * should not touch them. We use the value the guest would use for - * ERESTART_NOINTR (which is kernel internal) to guarantee that we won't - * clash with a valid guest errno now or in the future. - */ -#define TARGET_QEMU_ESIGRETURN 513 /* Return from signal */ - #endif diff --git a/linux-user/hexagon/cpu_loop.c b/linux-user/hexagon/cpu_loop.c index e47f8348d5..0d73934d31 100644 --- a/linux-user/hexagon/cpu_loop.c +++ b/linux-user/hexagon/cpu_loop.c @@ -55,9 +55,9 @@ void cpu_loop(CPUHexagonState *env) env->gpr[4], env->gpr[5], 0, 0); - if (ret == -TARGET_ERESTARTSYS) { + if (ret == -QEMU_ERESTARTSYS) { env->gpr[HEX_REG_PC] -= 4; - } else if (ret != -TARGET_QEMU_ESIGRETURN) { + } else if (ret != -QEMU_ESIGRETURN) { env->gpr[0] = ret; } break; diff --git a/linux-user/hexagon/signal.c b/linux-user/hexagon/signal.c index 74e61739a0..ad4e3822d5 100644 --- a/linux-user/hexagon/signal.c +++ b/linux-user/hexagon/signal.c @@ -268,7 +268,7 @@ long do_rt_sigreturn(CPUHexagonState *env) target_restore_altstack(&frame->uc.uc_stack, env); unlock_user_struct(frame, frame_addr, 0); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; badframe: unlock_user_struct(frame, frame_addr, 0); diff --git a/linux-user/host/aarch64/hostdep.h b/linux-user/host/aarch64/hostdep.h deleted file mode 100644 index 39299d798a..0000000000 --- a/linux-user/host/aarch64/hostdep.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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 deleted file mode 100644 index bc1f5a9792..0000000000 --- a/linux-user/host/aarch64/safe-syscall.inc.S +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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/arm/hostdep.h b/linux-user/host/arm/hostdep.h deleted file mode 100644 index 86b137875a..0000000000 --- a/linux-user/host/arm/hostdep.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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 deleted file mode 100644 index 88c4958504..0000000000 --- a/linux-user/host/arm/safe-syscall.inc.S +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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/hostdep.h b/linux-user/host/i386/hostdep.h deleted file mode 100644 index ce7136501f..0000000000 --- a/linux-user/host/i386/hostdep.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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 deleted file mode 100644 index 9e58fc6504..0000000000 --- a/linux-user/host/i386/safe-syscall.inc.S +++ /dev/null @@ -1,100 +0,0 @@ -/* - * 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 deleted file mode 100644 index 263bf7658e..0000000000 --- a/linux-user/host/ia64/hostdep.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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/hostdep.h b/linux-user/host/mips/hostdep.h deleted file mode 100644 index ba111d75c3..0000000000 --- a/linux-user/host/mips/hostdep.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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/hostdep.h b/linux-user/host/ppc/hostdep.h deleted file mode 100644 index 23d8bd9d47..0000000000 --- a/linux-user/host/ppc/hostdep.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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/hostdep.h b/linux-user/host/ppc64/hostdep.h deleted file mode 100644 index 0c290dd904..0000000000 --- a/linux-user/host/ppc64/hostdep.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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 deleted file mode 100644 index 875133173b..0000000000 --- a/linux-user/host/ppc64/safe-syscall.inc.S +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 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/hostdep.h b/linux-user/host/riscv/hostdep.h deleted file mode 100644 index 7f67c22868..0000000000 --- a/linux-user/host/riscv/hostdep.h +++ /dev/null @@ -1,14 +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 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 deleted file mode 100644 index 9ca3fbfd1e..0000000000 --- a/linux-user/host/riscv/safe-syscall.inc.S +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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/hostdep.h b/linux-user/host/s390/hostdep.h deleted file mode 100644 index afcba5a16a..0000000000 --- a/linux-user/host/s390/hostdep.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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/hostdep.h b/linux-user/host/s390x/hostdep.h deleted file mode 100644 index d801145854..0000000000 --- a/linux-user/host/s390x/hostdep.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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 deleted file mode 100644 index 414b44ad38..0000000000 --- a/linux-user/host/s390x/safe-syscall.inc.S +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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/hostdep.h b/linux-user/host/sparc/hostdep.h deleted file mode 100644 index 391ad923cf..0000000000 --- a/linux-user/host/sparc/hostdep.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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/hostdep.h b/linux-user/host/sparc64/hostdep.h deleted file mode 100644 index ce3968fca0..0000000000 --- a/linux-user/host/sparc64/hostdep.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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/hostdep.h b/linux-user/host/x32/hostdep.h deleted file mode 100644 index 2c2d6d37da..0000000000 --- a/linux-user/host/x32/hostdep.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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/hostdep.h b/linux-user/host/x86_64/hostdep.h deleted file mode 100644 index 9c62bd26bd..0000000000 --- a/linux-user/host/x86_64/hostdep.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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/hppa/cpu_loop.c b/linux-user/hppa/cpu_loop.c index 375576c8f0..a47a63176b 100644 --- a/linux-user/hppa/cpu_loop.c +++ b/linux-user/hppa/cpu_loop.c @@ -133,8 +133,8 @@ void cpu_loop(CPUHPPAState *env) env->iaoq_f = env->gr[31]; env->iaoq_b = env->gr[31] + 4; break; - case -TARGET_ERESTARTSYS: - case -TARGET_QEMU_ESIGRETURN: + case -QEMU_ERESTARTSYS: + case -QEMU_ESIGRETURN: break; } break; diff --git a/linux-user/hppa/signal.c b/linux-user/hppa/signal.c index c2fbc26ebb..962f551c04 100644 --- a/linux-user/hppa/signal.c +++ b/linux-user/hppa/signal.c @@ -191,9 +191,9 @@ long do_rt_sigreturn(CPUArchState *env) target_restore_altstack(&frame->uc.tuc_stack, env); unlock_user_struct(frame, frame_addr, 0); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; badframe: force_sig(TARGET_SIGSEGV); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; } diff --git a/linux-user/i386/cpu_loop.c b/linux-user/i386/cpu_loop.c index f6a1cc632b..9aaae93e2f 100644 --- a/linux-user/i386/cpu_loop.c +++ b/linux-user/i386/cpu_loop.c @@ -180,8 +180,8 @@ static void emulate_vsyscall(CPUX86State *env) ret = do_syscall(env, syscall, env->regs[R_EDI], env->regs[R_ESI], env->regs[R_EDX], env->regs[10], env->regs[8], env->regs[9], 0, 0); - g_assert(ret != -TARGET_ERESTARTSYS); - g_assert(ret != -TARGET_QEMU_ESIGRETURN); + g_assert(ret != -QEMU_ERESTARTSYS); + g_assert(ret != -QEMU_ESIGRETURN); if (ret == -TARGET_EFAULT) { goto sigsegv; } @@ -223,9 +223,9 @@ void cpu_loop(CPUX86State *env) env->regs[R_EDI], env->regs[R_EBP], 0, 0); - if (ret == -TARGET_ERESTARTSYS) { + if (ret == -QEMU_ERESTARTSYS) { env->eip -= 2; - } else if (ret != -TARGET_QEMU_ESIGRETURN) { + } else if (ret != -QEMU_ESIGRETURN) { env->regs[R_EAX] = ret; } break; @@ -241,9 +241,9 @@ void cpu_loop(CPUX86State *env) env->regs[8], env->regs[9], 0, 0); - if (ret == -TARGET_ERESTARTSYS) { + if (ret == -QEMU_ERESTARTSYS) { env->eip -= 2; - } else if (ret != -TARGET_QEMU_ESIGRETURN) { + } else if (ret != -QEMU_ESIGRETURN) { env->regs[R_EAX] = ret; } break; diff --git a/linux-user/i386/signal.c b/linux-user/i386/signal.c index 433efa3d69..4372621a4d 100644 --- a/linux-user/i386/signal.c +++ b/linux-user/i386/signal.c @@ -559,12 +559,12 @@ long do_sigreturn(CPUX86State *env) if (restore_sigcontext(env, &frame->sc)) goto badframe; unlock_user_struct(frame, frame_addr, 0); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; } #endif @@ -588,12 +588,12 @@ long do_rt_sigreturn(CPUX86State *env) target_restore_altstack(&frame->uc.tuc_stack, env); unlock_user_struct(frame, frame_addr, 0); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; } #ifndef TARGET_X86_64 diff --git a/linux-user/m68k/cpu_loop.c b/linux-user/m68k/cpu_loop.c index 790bd558c3..3181594414 100644 --- a/linux-user/m68k/cpu_loop.c +++ b/linux-user/m68k/cpu_loop.c @@ -80,9 +80,9 @@ void cpu_loop(CPUM68KState *env) env->dregs[5], env->aregs[0], 0, 0); - if (ret == -TARGET_ERESTARTSYS) { + if (ret == -QEMU_ERESTARTSYS) { env->pc -= 2; - } else if (ret != -TARGET_QEMU_ESIGRETURN) { + } else if (ret != -QEMU_ESIGRETURN) { env->dregs[0] = ret; } } diff --git a/linux-user/m68k/signal.c b/linux-user/m68k/signal.c index ec33482e14..5f35354487 100644 --- a/linux-user/m68k/signal.c +++ b/linux-user/m68k/signal.c @@ -353,11 +353,11 @@ long do_sigreturn(CPUM68KState *env) restore_sigcontext(env, &frame->sc); unlock_user_struct(frame, frame_addr, 0); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; badframe: force_sig(TARGET_SIGSEGV); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUM68KState *env) @@ -381,12 +381,12 @@ long do_rt_sigreturn(CPUM68KState *env) target_restore_altstack(&frame->uc.tuc_stack, env); unlock_user_struct(frame, frame_addr, 0); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; } void setup_sigtramp(abi_ulong sigtramp_page) diff --git a/linux-user/meson.build b/linux-user/meson.build index bf62c13e37..b2f4afd5e7 100644 --- a/linux-user/meson.build +++ b/linux-user/meson.build @@ -2,6 +2,11 @@ if not have_linux_user subdir_done() endif +linux_user_ss = ss.source_set() + +common_user_inc += include_directories('host/' / host_arch) +common_user_inc += include_directories('.') + linux_user_ss.add(files( 'elfload.c', 'exit.c', @@ -9,10 +14,10 @@ linux_user_ss.add(files( 'linuxload.c', 'main.c', 'mmap.c', - 'safe-syscall.S', 'signal.c', 'strace.c', 'syscall.c', + 'thunk.c', 'uaccess.c', 'uname.c', )) @@ -39,3 +44,5 @@ subdir('sh4') subdir('sparc') subdir('x86_64') subdir('xtensa') + +specific_ss.add_all(when: 'CONFIG_LINUX_USER', if_true: linux_user_ss) diff --git a/linux-user/microblaze/cpu_loop.c b/linux-user/microblaze/cpu_loop.c index a94467dd2d..ff1fb26c8b 100644 --- a/linux-user/microblaze/cpu_loop.c +++ b/linux-user/microblaze/cpu_loop.c @@ -53,10 +53,10 @@ void cpu_loop(CPUMBState *env) env->regs[9], env->regs[10], 0, 0); - if (ret == -TARGET_ERESTARTSYS) { + if (ret == -QEMU_ERESTARTSYS) { /* Wind back to before the syscall. */ env->pc -= 4; - } else if (ret != -TARGET_QEMU_ESIGRETURN) { + } else if (ret != -QEMU_ESIGRETURN) { env->regs[3] = ret; } /* All syscall exits result in guest r14 being equal to the diff --git a/linux-user/microblaze/signal.c b/linux-user/microblaze/signal.c index 8ebb6a1b7d..5188d74025 100644 --- a/linux-user/microblaze/signal.c +++ b/linux-user/microblaze/signal.c @@ -207,12 +207,12 @@ long do_rt_sigreturn(CPUMBState *env) target_restore_altstack(&frame->uc.tuc_stack, env); unlock_user_struct(frame, frame_addr, 0); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; } void setup_sigtramp(abi_ulong sigtramp_page) diff --git a/linux-user/mips/cpu_loop.c b/linux-user/mips/cpu_loop.c index b735c99a24..32f9fc1c1c 100644 --- a/linux-user/mips/cpu_loop.c +++ b/linux-user/mips/cpu_loop.c @@ -141,11 +141,11 @@ done_syscall: env->active_tc.gpr[8], env->active_tc.gpr[9], env->active_tc.gpr[10], env->active_tc.gpr[11]); # endif /* O32 */ - if (ret == -TARGET_ERESTARTSYS) { + if (ret == -QEMU_ERESTARTSYS) { env->active_tc.PC -= 4; break; } - if (ret == -TARGET_QEMU_ESIGRETURN) { + if (ret == -QEMU_ESIGRETURN) { /* Returning from a successful sigreturn syscall. Avoid clobbering register state. */ break; diff --git a/linux-user/mips/signal.c b/linux-user/mips/signal.c index 8f79e405ec..58a9d7a8a3 100644 --- a/linux-user/mips/signal.c +++ b/linux-user/mips/signal.c @@ -281,11 +281,11 @@ long do_sigreturn(CPUMIPSState *regs) /* I am not sure this is right, but it seems to work * maybe a problem with nested signals ? */ regs->CP0_EPC = 0; - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; badframe: force_sig(TARGET_SIGSEGV); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; } # endif /* O32 */ @@ -371,11 +371,11 @@ long do_rt_sigreturn(CPUMIPSState *env) /* I am not sure this is right, but it seems to work * maybe a problem with nested signals ? */ env->CP0_EPC = 0; - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; badframe: force_sig(TARGET_SIGSEGV); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; } void setup_sigtramp(abi_ulong sigtramp_page) diff --git a/linux-user/openrisc/cpu_loop.c b/linux-user/openrisc/cpu_loop.c index 3cfdbbf037..592901a68b 100644 --- a/linux-user/openrisc/cpu_loop.c +++ b/linux-user/openrisc/cpu_loop.c @@ -48,9 +48,9 @@ void cpu_loop(CPUOpenRISCState *env) cpu_get_gpr(env, 6), cpu_get_gpr(env, 7), cpu_get_gpr(env, 8), 0, 0); - if (ret == -TARGET_ERESTARTSYS) { + if (ret == -QEMU_ERESTARTSYS) { env->pc -= 4; - } else if (ret != -TARGET_QEMU_ESIGRETURN) { + } else if (ret != -QEMU_ESIGRETURN) { cpu_set_gpr(env, 11, ret); } break; diff --git a/linux-user/ppc/cpu_loop.c b/linux-user/ppc/cpu_loop.c index 483e669300..30c82f2354 100644 --- a/linux-user/ppc/cpu_loop.c +++ b/linux-user/ppc/cpu_loop.c @@ -428,11 +428,11 @@ void cpu_loop(CPUPPCState *env) ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4], env->gpr[5], env->gpr[6], env->gpr[7], env->gpr[8], 0, 0); - if (ret == -TARGET_ERESTARTSYS) { + if (ret == -QEMU_ERESTARTSYS) { env->nip -= 4; break; } - if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) { + if (ret == (target_ulong)(-QEMU_ESIGRETURN)) { /* Returning from a successful sigreturn syscall. Avoid corrupting register state. */ break; diff --git a/linux-user/ppc/signal.c b/linux-user/ppc/signal.c index 90a0369632..176c9d8503 100644 --- a/linux-user/ppc/signal.c +++ b/linux-user/ppc/signal.c @@ -591,13 +591,13 @@ long do_sigreturn(CPUPPCState *env) unlock_user_struct(sr, sr_addr, 1); unlock_user_struct(sc, sc_addr, 1); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; sigsegv: unlock_user_struct(sr, sr_addr, 1); unlock_user_struct(sc, sc_addr, 1); force_sig(TARGET_SIGSEGV); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; } #endif /* !defined(TARGET_PPC64) */ @@ -646,12 +646,12 @@ long do_rt_sigreturn(CPUPPCState *env) target_restore_altstack(&rt_sf->uc.tuc_stack, env); unlock_user_struct(rt_sf, rt_sf_addr, 1); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; sigsegv: unlock_user_struct(rt_sf, rt_sf_addr, 1); force_sig(TARGET_SIGSEGV); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; } /* This syscall implements {get,set,swap}context for userland. */ @@ -704,7 +704,7 @@ abi_long do_swapcontext(CPUArchState *env, abi_ulong uold_ctx, /* We cannot return to a partially updated context. */ force_sig(TARGET_SIGSEGV); } - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; } return 0; diff --git a/linux-user/riscv/cpu_loop.c b/linux-user/riscv/cpu_loop.c index b301dac802..0cd8985cb8 100644 --- a/linux-user/riscv/cpu_loop.c +++ b/linux-user/riscv/cpu_loop.c @@ -69,9 +69,9 @@ void cpu_loop(CPURISCVState *env) env->gpr[xA5], 0, 0); } - if (ret == -TARGET_ERESTARTSYS) { + if (ret == -QEMU_ERESTARTSYS) { env->pc -= 4; - } else if (ret != -TARGET_QEMU_ESIGRETURN) { + } else if (ret != -QEMU_ESIGRETURN) { env->gpr[xA0] = ret; } if (cs->singlestep_enabled) { diff --git a/linux-user/riscv/signal.c b/linux-user/riscv/signal.c index a0f9542ce3..296e39fbf0 100644 --- a/linux-user/riscv/signal.c +++ b/linux-user/riscv/signal.c @@ -188,7 +188,7 @@ long do_rt_sigreturn(CPURISCVState *env) target_restore_altstack(&frame->uc.uc_stack, env); unlock_user_struct(frame, frame_addr, 0); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; badframe: unlock_user_struct(frame, frame_addr, 0); diff --git a/linux-user/s390x/cpu_loop.c b/linux-user/s390x/cpu_loop.c index d089c8417e..ad0c3cd263 100644 --- a/linux-user/s390x/cpu_loop.c +++ b/linux-user/s390x/cpu_loop.c @@ -83,9 +83,9 @@ 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; diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c index 676b948147..f47713e04a 100644 --- a/linux-user/s390x/signal.c +++ b/linux-user/s390x/signal.c @@ -359,7 +359,7 @@ long do_sigreturn(CPUS390XState *env) trace_user_do_sigreturn(env, frame_addr); if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { force_sig(TARGET_SIGSEGV); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; } /* Make sure that we're initializing all of target_set. */ @@ -373,7 +373,7 @@ long do_sigreturn(CPUS390XState *env) restore_sigregs_ext(env, &frame->sregs_ext); unlock_user_struct(frame, frame_addr, 0); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUS390XState *env) @@ -385,7 +385,7 @@ long do_rt_sigreturn(CPUS390XState *env) trace_user_do_rt_sigreturn(env, frame_addr); if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { force_sig(TARGET_SIGSEGV); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; } target_to_host_sigset(&set, &frame->uc.tuc_sigmask); @@ -397,7 +397,7 @@ long do_rt_sigreturn(CPUS390XState *env) target_restore_altstack(&frame->uc.tuc_stack, env); unlock_user_struct(frame, frame_addr, 0); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; } void setup_sigtramp(abi_ulong sigtramp_page) diff --git a/linux-user/sh4/cpu_loop.c b/linux-user/sh4/cpu_loop.c index ac9b01840c..3290f6445c 100644 --- a/linux-user/sh4/cpu_loop.c +++ b/linux-user/sh4/cpu_loop.c @@ -50,9 +50,9 @@ void cpu_loop(CPUSH4State *env) env->gregs[0], env->gregs[1], 0, 0); - if (ret == -TARGET_ERESTARTSYS) { + if (ret == -QEMU_ERESTARTSYS) { env->pc -= 2; - } else if (ret != -TARGET_QEMU_ESIGRETURN) { + } else if (ret != -QEMU_ESIGRETURN) { env->gregs[0] = ret; } break; diff --git a/linux-user/sh4/signal.c b/linux-user/sh4/signal.c index faa869fb19..f6a18bc6b5 100644 --- a/linux-user/sh4/signal.c +++ b/linux-user/sh4/signal.c @@ -286,12 +286,12 @@ long do_sigreturn(CPUSH4State *regs) restore_sigcontext(regs, &frame->sc); unlock_user_struct(frame, frame_addr, 0); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUSH4State *regs) @@ -313,12 +313,12 @@ long do_rt_sigreturn(CPUSH4State *regs) target_restore_altstack(&frame->uc.tuc_stack, regs); unlock_user_struct(frame, frame_addr, 0); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; } void setup_sigtramp(abi_ulong sigtramp_page) diff --git a/linux-user/signal-common.h b/linux-user/signal-common.h index 7457f8025c..42aa479080 100644 --- a/linux-user/signal-common.h +++ b/linux-user/signal-common.h @@ -20,6 +20,8 @@ #ifndef SIGNAL_COMMON_H #define SIGNAL_COMMON_H +#include "special-errno.h" + /* Fallback addresses into sigtramp page. */ extern abi_ulong default_sigreturn; extern abi_ulong default_rt_sigreturn; @@ -76,7 +78,7 @@ abi_long do_swapcontext(CPUArchState *env, abi_ulong uold_ctx, * Block all signals, and arrange that the signal mask is returned to * its correct value for the guest before we resume execution of guest code. * If this function returns non-zero, then the caller should immediately - * return -TARGET_ERESTARTSYS to the main loop, which will take the pending + * return -QEMU_ERESTARTSYS to the main loop, which will take the pending * signal and restart execution of the syscall. * If block_signals() returns zero, then the caller can continue with * emulation of the system call knowing that no signals can be taken diff --git a/linux-user/signal.c b/linux-user/signal.c index 6d5e5b698c..510db73c34 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -31,7 +31,7 @@ #include "trace.h" #include "signal-common.h" #include "host-signal.h" -#include "safe-syscall.h" +#include "user/safe-syscall.h" static struct target_sigaction sigact_table[TARGET_NSIG]; @@ -213,7 +213,7 @@ int block_signals(void) /* Wrapper for sigprocmask function * Emulates a sigprocmask in a safe way for the guest. Note that set and oldset - * are host signal set, not guest ones. Returns -TARGET_ERESTARTSYS if + * are host signal set, not guest ones. Returns -QEMU_ERESTARTSYS if * a signal was already pending and the syscall must be restarted, or * 0 on success. * If set is NULL, this is guaranteed not to fail. @@ -230,7 +230,7 @@ int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset) int i; if (block_signals()) { - return -TARGET_ERESTARTSYS; + return -QEMU_ERESTARTSYS; } switch (how) { @@ -798,7 +798,6 @@ int queue_signal(CPUArchState *env, int sig, int si_type, /* Adjust the signal context to rewind out of safe-syscall if we're in it */ static inline void rewind_if_in_safe_syscall(void *puc) { -#ifdef HAVE_SAFE_SYSCALL ucontext_t *uc = (ucontext_t *)puc; uintptr_t pcreg = host_signal_pc(uc); @@ -806,7 +805,6 @@ static inline void rewind_if_in_safe_syscall(void *puc) && pcreg < (uintptr_t)safe_syscall_end) { host_signal_set_pc(uc, (uintptr_t)safe_syscall_start); } -#endif } static void host_signal_handler(int host_sig, siginfo_t *info, void *puc) @@ -987,7 +985,7 @@ int do_sigaction(int sig, const struct target_sigaction *act, } if (block_signals()) { - return -TARGET_ERESTARTSYS; + return -QEMU_ERESTARTSYS; } k = &sigact_table[sig - 1]; diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index 0ba65e431c..8765ab6020 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -181,7 +181,7 @@ void cpu_loop (CPUSPARCState *env) env->regwptr[2], env->regwptr[3], env->regwptr[4], env->regwptr[5], 0, 0); - if (ret == -TARGET_ERESTARTSYS || ret == -TARGET_QEMU_ESIGRETURN) { + if (ret == -QEMU_ERESTARTSYS || ret == -QEMU_ESIGRETURN) { break; } if ((abi_ulong)ret >= (abi_ulong)(-515)) { diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c index 23e1e761de..b501750fe0 100644 --- a/linux-user/sparc/signal.c +++ b/linux-user/sparc/signal.c @@ -431,12 +431,12 @@ long do_sigreturn(CPUSPARCState *env) set_sigmask(&host_set); unlock_user_struct(sf, sf_addr, 0); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; segv_and_exit: unlock_user_struct(sf, sf_addr, 0); force_sig(TARGET_SIGSEGV); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; #else return -TARGET_ENOSYS; #endif @@ -495,12 +495,12 @@ long do_rt_sigreturn(CPUSPARCState *env) env->npc = tnpc; unlock_user_struct(sf, sf_addr, 0); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; segv_and_exit: unlock_user_struct(sf, sf_addr, 0); force_sig(TARGET_SIGSEGV); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; } #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) diff --git a/linux-user/special-errno.h b/linux-user/special-errno.h new file mode 100644 index 0000000000..4120455baa --- /dev/null +++ b/linux-user/special-errno.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU internal errno values for implementing user-only POSIX. + * + * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2021 Linaro, Ltd. + */ + +#ifndef SPECIAL_ERRNO_H +#define SPECIAL_ERRNO_H + +/* + * All of these are QEMU internal, not visible to the guest. + * They should be chosen so as to not overlap with any host + * or guest errno. + */ + +/* + * This is returned when a system call should be restarted, to tell the + * main loop that it should wind the guest PC backwards so it will + * re-execute the syscall after handling any pending signals. + */ +#define QEMU_ERESTARTSYS 512 + +/* + * This is returned after a successful sigreturn syscall, to indicate + * that it has correctly set the guest registers and so the main loop + * should not touch them. + */ +#define QEMU_ESIGRETURN 513 + +#endif /* SPECIAL_ERRNO_H */ diff --git a/linux-user/syscall.c b/linux-user/syscall.c index f1cfcc8104..56a3e17183 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -132,10 +132,11 @@ #include "signal-common.h" #include "loader.h" #include "user-mmap.h" -#include "safe-syscall.h" +#include "user/safe-syscall.h" #include "qemu/guest-random.h" #include "qemu/selfmap.h" #include "user/syscall-trace.h" +#include "special-errno.h" #include "qapi/error.h" #include "fd-trans.h" #include "tcg/tcg.h" @@ -547,10 +548,10 @@ static inline abi_long get_errno(abi_long ret) const char *target_strerror(int err) { - if (err == TARGET_ERESTARTSYS) { + if (err == QEMU_ERESTARTSYS) { return "To be restarted"; } - if (err == TARGET_QEMU_ESIGRETURN) { + if (err == QEMU_ESIGRETURN) { return "Successful exit from sigreturn"; } @@ -6458,7 +6459,7 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, } if (block_signals()) { - return -TARGET_ERESTARTSYS; + return -QEMU_ERESTARTSYS; } fork_start(); @@ -8328,7 +8329,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, Do thread termination if we have more then one thread. */ if (block_signals()) { - return -TARGET_ERESTARTSYS; + return -QEMU_ERESTARTSYS; } pthread_mutex_lock(&clone_lock); @@ -9317,7 +9318,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, #endif ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask, SIGSET_T_SIZE)); - if (ret != -TARGET_ERESTARTSYS) { + if (ret != -QEMU_ERESTARTSYS) { ts->in_sigsuspend = 1; } } @@ -9336,7 +9337,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, unlock_user(p, arg1, 0); ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask, SIGSET_T_SIZE)); - if (ret != -TARGET_ERESTARTSYS) { + if (ret != -QEMU_ERESTARTSYS) { ts->in_sigsuspend = 1; } } @@ -9452,13 +9453,13 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, #ifdef TARGET_NR_sigreturn case TARGET_NR_sigreturn: if (block_signals()) { - return -TARGET_ERESTARTSYS; + return -QEMU_ERESTARTSYS; } return do_sigreturn(cpu_env); #endif case TARGET_NR_rt_sigreturn: if (block_signals()) { - return -TARGET_ERESTARTSYS; + return -QEMU_ERESTARTSYS; } return do_rt_sigreturn(cpu_env); case TARGET_NR_sethostname: @@ -13145,7 +13146,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, static bool flag; flag = !flag; if (flag) { - return -TARGET_ERESTARTSYS; + return -QEMU_ERESTARTSYS; } } #endif diff --git a/thunk.c b/linux-user/thunk.c index dac4bf11c6..dac4bf11c6 100644 --- a/thunk.c +++ b/linux-user/thunk.c diff --git a/linux-user/user-internals.h b/linux-user/user-internals.h index 661612a088..f71f372829 100644 --- a/linux-user/user-internals.h +++ b/linux-user/user-internals.h @@ -18,7 +18,6 @@ #ifndef LINUX_USER_USER_INTERNALS_H #define LINUX_USER_USER_INTERNALS_H -#include "hostdep.h" #include "exec/user/thunk.h" #include "exec/exec-all.h" #include "qemu/log.h" diff --git a/linux-user/xtensa/cpu_loop.c b/linux-user/xtensa/cpu_loop.c index a83490ab35..6bc6d6dee6 100644 --- a/linux-user/xtensa/cpu_loop.c +++ b/linux-user/xtensa/cpu_loop.c @@ -184,11 +184,11 @@ void cpu_loop(CPUXtensaState *env) env->regs[2] = ret; break; - case -TARGET_ERESTARTSYS: + case -QEMU_ERESTARTSYS: env->pc -= 3; break; - case -TARGET_QEMU_ESIGRETURN: + case -QEMU_ESIGRETURN: break; } break; diff --git a/linux-user/xtensa/signal.c b/linux-user/xtensa/signal.c index 81572a5fc7..06d91a37ec 100644 --- a/linux-user/xtensa/signal.c +++ b/linux-user/xtensa/signal.c @@ -263,12 +263,12 @@ long do_rt_sigreturn(CPUXtensaState *env) target_restore_altstack(&frame->uc.tuc_stack, env); unlock_user_struct(frame, frame_addr, 0); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return -TARGET_QEMU_ESIGRETURN; + return -QEMU_ESIGRETURN; } void setup_sigtramp(abi_ulong sigtramp_page) diff --git a/meson.build b/meson.build index 2495360fd0..f45ecf31bd 100644 --- a/meson.build +++ b/meson.build @@ -2375,13 +2375,12 @@ genh += hxdep authz_ss = ss.source_set() blockdev_ss = ss.source_set() block_ss = ss.source_set() -bsd_user_ss = ss.source_set() chardev_ss = ss.source_set() common_ss = ss.source_set() +common_user_ss = ss.source_set() crypto_ss = ss.source_set() hwcore_ss = ss.source_set() io_ss = ss.source_set() -linux_user_ss = ss.source_set() qmp_ss = ss.source_set() qom_ss = ss.source_set() softmmu_ss = ss.source_set() @@ -2622,14 +2621,24 @@ subdir('tcg') subdir('fpu') subdir('accel') subdir('plugins') +subdir('ebpf') + +common_user_inc = [] + +subdir('common-user') subdir('bsd-user') subdir('linux-user') -subdir('ebpf') -specific_ss.add_all(when: 'CONFIG_BSD_USER', if_true: bsd_user_ss) +common_user_ss = common_user_ss.apply(config_all, strict: false) +common_user = static_library('common-user', + sources: common_user_ss.sources(), + dependencies: common_user_ss.dependencies(), + include_directories: common_user_inc, + name_suffix: 'fa', + build_by_default: false) +common_user = declare_dependency(link_with: common_user) -linux_user_ss.add(files('thunk.c')) -specific_ss.add_all(when: 'CONFIG_LINUX_USER', if_true: linux_user_ss) +user_ss.add(common_user) # needed for fuzzing binaries subdir('tests/qtest/libqos') |