Move errno processing from safe_syscall() to safe_syscall_base().
Move safe_syscall() from linux-user to common-user. Add FreeBSD support to safe_syscall_base(). Tidy top-level meson.build wrt {bsd,linux}-user. -----BEGIN PGP SIGNATURE----- iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAmHA3YMdHHJpY2hhcmQu aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV+/XggAqZ2kp/xhmhlVKR8X YzxmeAkPPuJSCQZt8v0UFPye2/HQTpXCboi4Lo+IgjI+6tpY4LhcY48071iiI5Ug uWXIW9Y4+GnHPEDbyU3I1Wxg/OtXOj9B0Fy0ULw8ct0vKBjVgPBkiaQqtn+jCzOZ +7SGdIJMz5hsgW+krP60BHyyXypU/NIDPhCEBRwusZ6Vp5UvkVicNmZaQjh4suZt 5gCFNSq43gw/+KhzjDEZvRTG00LteaCHUDY5nAfbyvE0o8hTDuroO16hCWCb7gZ+ 8MH5NMJMOcKupPLk7YCJ+o5NQlWhR86ygZSiTg+WZyHldfXMPBINiLN1b878kNfT NjcGRA== =i5x2 -----END PGP SIGNATURE----- Merge tag 'pull-user-20211220' of https://gitlab.com/rth7680/qemu into staging Move errno processing from safe_syscall() to safe_syscall_base(). Move safe_syscall() from linux-user to common-user. Add FreeBSD support to safe_syscall_base(). Tidy top-level meson.build wrt {bsd,linux}-user. # gpg: Signature made Mon 20 Dec 2021 11:46:11 AM PST # gpg: using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F # gpg: issuer "richard.henderson@linaro.org" # gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 7A48 1E78 868B 4DB6 A85A 05C0 64DF 38E8 AF7E 215F * tag 'pull-user-20211220' of https://gitlab.com/rth7680/qemu: meson: Move bsd_user_ss to bsd-user/ meson: Move linux_user_ss to linux-user/ linux-user: Move thunk.c from top-level common-user: Adjust system call return on FreeBSD common-user: Move safe-syscall.* from linux-user bsd-user: Create special-errno.h linux-user: Create special-errno.h linux-user: Rename TARGET_QEMU_ESIGRETURN to QEMU_ESIGRETURN bsd-user: Rename TARGET_ERESTARTSYS to QEMU_ERESTARTSYS linux-user: Rename TARGET_ERESTARTSYS to QEMU_ERESTARTSYS linux-user: Remove HAVE_SAFE_SYSCALL and hostdep.h linux-user/host/sparc64: Add safe-syscall.inc.S linux-user/host/mips: Add safe-syscall.inc.S linux-user: Move syscall error detection into safe_syscall_base linux-user: Untabify all safe-syscall.inc.S Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
2bf40d0841
@ -3077,8 +3077,9 @@ Usermode Emulation
|
|||||||
Overall usermode emulation
|
Overall usermode emulation
|
||||||
M: Riku Voipio <riku.voipio@iki.fi>
|
M: Riku Voipio <riku.voipio@iki.fi>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: thunk.c
|
|
||||||
F: accel/tcg/user-exec*.c
|
F: accel/tcg/user-exec*.c
|
||||||
|
F: include/user/
|
||||||
|
F: common-user/
|
||||||
|
|
||||||
BSD user
|
BSD user
|
||||||
M: Warner Losh <imp@bsdimp.com>
|
M: Warner Losh <imp@bsdimp.com>
|
||||||
|
@ -151,6 +151,10 @@
|
|||||||
/* Internal errors: */
|
/* Internal errors: */
|
||||||
#define TARGET_EJUSTRETURN 254 /* Just return without modifing regs */
|
#define TARGET_EJUSTRETURN 254 /* Just return without modifing regs */
|
||||||
#define TARGET_ERESTART 255 /* Restart syscall */
|
#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_ */
|
#endif /* ! _ERRNO_DEFS_H_ */
|
||||||
|
@ -2,6 +2,10 @@ if not have_bsd_user
|
|||||||
subdir_done()
|
subdir_done()
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
bsd_user_ss = ss.source_set()
|
||||||
|
|
||||||
|
common_user_inc += include_directories('.')
|
||||||
|
|
||||||
bsd_user_ss.add(files(
|
bsd_user_ss.add(files(
|
||||||
'bsdload.c',
|
'bsdload.c',
|
||||||
'elfload.c',
|
'elfload.c',
|
||||||
@ -15,3 +19,5 @@ bsd_user_ss.add(files(
|
|||||||
|
|
||||||
# Pull in the OS-specific build glue, if any
|
# Pull in the OS-specific build glue, if any
|
||||||
subdir(targetos)
|
subdir(targetos)
|
||||||
|
|
||||||
|
specific_ss.add_all(when: 'CONFIG_BSD_USER', if_true: bsd_user_ss)
|
||||||
|
24
bsd-user/special-errno.h
Normal file
24
bsd-user/special-errno.h
Normal file
@ -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 */
|
88
common-user/host/aarch64/safe-syscall.inc.S
Normal file
88
common-user/host/aarch64/safe-syscall.inc.S
Normal file
@ -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
|
108
common-user/host/arm/safe-syscall.inc.S
Normal file
108
common-user/host/arm/safe-syscall.inc.S
Normal file
@ -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
|
126
common-user/host/i386/safe-syscall.inc.S
Normal file
126
common-user/host/i386/safe-syscall.inc.S
Normal file
@ -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
|
148
common-user/host/mips/safe-syscall.inc.S
Normal file
148
common-user/host/mips/safe-syscall.inc.S
Normal file
@ -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)
|
94
common-user/host/ppc64/safe-syscall.inc.S
Normal file
94
common-user/host/ppc64/safe-syscall.inc.S
Normal file
@ -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
|
79
common-user/host/riscv/safe-syscall.inc.S
Normal file
79
common-user/host/riscv/safe-syscall.inc.S
Normal file
@ -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
|
98
common-user/host/s390x/safe-syscall.inc.S
Normal file
98
common-user/host/s390x/safe-syscall.inc.S
Normal file
@ -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
|
89
common-user/host/sparc64/safe-syscall.inc.S
Normal file
89
common-user/host/sparc64/safe-syscall.inc.S
Normal file
@ -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
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* safe-syscall.inc.S : host-specific assembly fragment
|
* safe-syscall.inc.S : host-specific assembly fragment
|
||||||
* to handle signals occurring at the same time as system calls.
|
* 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>
|
* 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
|
* first argument an 'int *' to the signal_pending flag, the
|
||||||
* second one the system call number (as a 'long'), and all further
|
* second one the system call number (as a 'long'), and all further
|
||||||
* arguments being syscall arguments (also 'long').
|
* 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:
|
safe_syscall_base:
|
||||||
.cfi_startproc
|
.cfi_startproc
|
||||||
@ -35,9 +32,9 @@ safe_syscall_base:
|
|||||||
.cfi_adjust_cfa_offset 8
|
.cfi_adjust_cfa_offset 8
|
||||||
.cfi_rel_offset rbp, 0
|
.cfi_rel_offset rbp, 0
|
||||||
|
|
||||||
/* The syscall calling convention isn't the same as the
|
/*
|
||||||
* C one:
|
* The syscall calling convention isn't the same as the C one:
|
||||||
* we enter with rdi == *signal_pending
|
* we enter with rdi == &signal_pending
|
||||||
* rsi == syscall number
|
* rsi == syscall number
|
||||||
* rdx, rcx, r8, r9, (stack), (stack) == syscall arguments
|
* rdx, rcx, r8, r9, (stack), (stack) == syscall arguments
|
||||||
* and return the result in rax
|
* and return the result in rax
|
||||||
@ -67,25 +64,42 @@ safe_syscall_base:
|
|||||||
*/
|
*/
|
||||||
safe_syscall_start:
|
safe_syscall_start:
|
||||||
/* if signal_pending is non-zero, don't do the call */
|
/* if signal_pending is non-zero, don't do the call */
|
||||||
cmpl $0, (%rbp)
|
cmpl $0, (%rbp)
|
||||||
jnz 1f
|
jnz 2f
|
||||||
syscall
|
syscall
|
||||||
safe_syscall_end:
|
safe_syscall_end:
|
||||||
|
|
||||||
/* code path for having successfully executed the syscall */
|
/* 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
|
pop %rbp
|
||||||
.cfi_remember_state
|
.cfi_remember_state
|
||||||
.cfi_def_cfa_offset 8
|
.cfi_def_cfa_offset 8
|
||||||
.cfi_restore rbp
|
.cfi_restore rbp
|
||||||
ret
|
ret
|
||||||
|
|
||||||
1:
|
|
||||||
/* code path when we didn't execute the syscall */
|
|
||||||
.cfi_restore_state
|
.cfi_restore_state
|
||||||
mov $-TARGET_ERESTARTSYS, %rax
|
|
||||||
pop %rbp
|
#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 %rbp
|
||||||
.cfi_def_cfa_offset 8
|
.cfi_def_cfa_offset 8
|
||||||
.cfi_restore rbp
|
.cfi_restore rbp
|
||||||
ret
|
jmp safe_syscall_set_errno_tail
|
||||||
.cfi_endproc
|
.cfi_endproc
|
||||||
|
|
||||||
.size safe_syscall_base, .-safe_syscall_base
|
.size safe_syscall_base, .-safe_syscall_base
|
6
common-user/meson.build
Normal file
6
common-user/meson.build
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
common_user_inc += include_directories('host/' / host_arch)
|
||||||
|
|
||||||
|
common_user_ss.add(files(
|
||||||
|
'safe-syscall.S',
|
||||||
|
'safe-syscall-error.c',
|
||||||
|
))
|
25
common-user/safe-syscall-error.c
Normal file
25
common-user/safe-syscall-error.c
Normal file
@ -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;
|
||||||
|
}
|
@ -10,15 +10,12 @@
|
|||||||
* See the COPYING file in the top-level directory.
|
* See the COPYING file in the top-level directory.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "hostdep.h"
|
#include "special-errno.h"
|
||||||
#include "target_errno_defs.h"
|
|
||||||
|
|
||||||
/* We have the correct host directory on our include path
|
/* We have the correct host directory on our include path
|
||||||
* so that this will pull in the right fragment for the architecture.
|
* so that this will pull in the right fragment for the architecture.
|
||||||
*/
|
*/
|
||||||
#ifdef HAVE_SAFE_SYSCALL
|
|
||||||
#include "safe-syscall.inc.S"
|
#include "safe-syscall.inc.S"
|
||||||
#endif
|
|
||||||
|
|
||||||
/* We must specifically say that we're happy for the stack to not be
|
/* We must specifically say that we're happy for the stack to not be
|
||||||
* executable, otherwise the toolchain will default to assuming our
|
* executable, otherwise the toolchain will default to assuming our
|
@ -25,10 +25,10 @@
|
|||||||
*
|
*
|
||||||
* Call a system call if guest signal not pending.
|
* Call a system call if guest signal not pending.
|
||||||
* This has the same API as the libc syscall() function, except that it
|
* 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
|
* 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.)
|
* with any of the host errno values.)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -81,7 +81,7 @@
|
|||||||
* which are only technically blocking (ie which we know in practice won't
|
* 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.
|
* 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 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.)
|
* EINTR though.)
|
||||||
*
|
*
|
||||||
* block_signals() cannot be used for interruptible syscalls.
|
* block_signals() cannot be used for interruptible syscalls.
|
||||||
@ -94,7 +94,7 @@
|
|||||||
* handler checks the interrupted host PC against the addresse of that
|
* 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
|
* 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
|
* 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).
|
* (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
|
* 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
|
* 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
|
* need to check SA_RESTART flags in QEMU or distinguish the various
|
||||||
* kinds of restartability.
|
* kinds of restartability.
|
||||||
*/
|
*/
|
||||||
#ifdef HAVE_SAFE_SYSCALL
|
|
||||||
/* The core part of this function is implemented in assembly */
|
/* The core part of this function is implemented in assembly */
|
||||||
extern long safe_syscall_base(int *pending, long number, ...);
|
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 */
|
/* These are defined by the safe-syscall.inc.S file */
|
||||||
extern char safe_syscall_start[];
|
extern char safe_syscall_start[];
|
||||||
extern char safe_syscall_end[];
|
extern char safe_syscall_end[];
|
||||||
|
|
||||||
#define safe_syscall(...) \
|
#define safe_syscall(...) \
|
||||||
({ \
|
safe_syscall_base(&((TaskState *)thread_cpu->opaque)->signal_pending, \
|
||||||
long ret_; \
|
__VA_ARGS__)
|
||||||
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
|
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -99,9 +99,9 @@ void cpu_loop(CPUARMState *env)
|
|||||||
env->xregs[4],
|
env->xregs[4],
|
||||||
env->xregs[5],
|
env->xregs[5],
|
||||||
0, 0);
|
0, 0);
|
||||||
if (ret == -TARGET_ERESTARTSYS) {
|
if (ret == -QEMU_ERESTARTSYS) {
|
||||||
env->pc -= 4;
|
env->pc -= 4;
|
||||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
} else if (ret != -QEMU_ESIGRETURN) {
|
||||||
env->xregs[0] = ret;
|
env->xregs[0] = ret;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -556,12 +556,12 @@ long do_rt_sigreturn(CPUARMState *env)
|
|||||||
target_restore_altstack(&frame->uc.tuc_stack, env);
|
target_restore_altstack(&frame->uc.tuc_stack, env);
|
||||||
|
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
long do_sigreturn(CPUARMState *env)
|
long do_sigreturn(CPUARMState *env)
|
||||||
|
@ -98,11 +98,11 @@ void cpu_loop(CPUAlphaState *env)
|
|||||||
env->ir[IR_A2], env->ir[IR_A3],
|
env->ir[IR_A2], env->ir[IR_A3],
|
||||||
env->ir[IR_A4], env->ir[IR_A5],
|
env->ir[IR_A4], env->ir[IR_A5],
|
||||||
0, 0);
|
0, 0);
|
||||||
if (sysret == -TARGET_ERESTARTSYS) {
|
if (sysret == -QEMU_ERESTARTSYS) {
|
||||||
env->pc -= 4;
|
env->pc -= 4;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (sysret == -TARGET_QEMU_ESIGRETURN) {
|
if (sysret == -QEMU_ESIGRETURN) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* Syscall writes 0 to V0 to bypass error check, similar
|
/* Syscall writes 0 to V0 to bypass error check, similar
|
||||||
|
@ -225,11 +225,11 @@ long do_sigreturn(CPUAlphaState *env)
|
|||||||
|
|
||||||
restore_sigcontext(env, sc);
|
restore_sigcontext(env, sc);
|
||||||
unlock_user_struct(sc, sc_addr, 0);
|
unlock_user_struct(sc, sc_addr, 0);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
long do_rt_sigreturn(CPUAlphaState *env)
|
long do_rt_sigreturn(CPUAlphaState *env)
|
||||||
@ -249,13 +249,13 @@ long do_rt_sigreturn(CPUAlphaState *env)
|
|||||||
target_restore_altstack(&frame->uc.tuc_stack, env);
|
target_restore_altstack(&frame->uc.tuc_stack, env);
|
||||||
|
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
|
|
||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup_sigtramp(abi_ulong sigtramp_page)
|
void setup_sigtramp(abi_ulong sigtramp_page)
|
||||||
|
@ -407,9 +407,9 @@ void cpu_loop(CPUARMState *env)
|
|||||||
env->regs[4],
|
env->regs[4],
|
||||||
env->regs[5],
|
env->regs[5],
|
||||||
0, 0);
|
0, 0);
|
||||||
if (ret == -TARGET_ERESTARTSYS) {
|
if (ret == -QEMU_ERESTARTSYS) {
|
||||||
env->regs[15] -= env->thumb ? 2 : 4;
|
env->regs[15] -= env->thumb ? 2 : 4;
|
||||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
} else if (ret != -QEMU_ESIGRETURN) {
|
||||||
env->regs[0] = ret;
|
env->regs[0] = ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -511,12 +511,12 @@ long do_sigreturn(CPUARMState *env)
|
|||||||
}
|
}
|
||||||
|
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
long do_rt_sigreturn(CPUARMState *env)
|
long do_rt_sigreturn(CPUARMState *env)
|
||||||
@ -546,12 +546,12 @@ long do_rt_sigreturn(CPUARMState *env)
|
|||||||
}
|
}
|
||||||
|
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#define CPU_LOOP_COMMON_H
|
#define CPU_LOOP_COMMON_H
|
||||||
|
|
||||||
#include "exec/log.h"
|
#include "exec/log.h"
|
||||||
|
#include "special-errno.h"
|
||||||
|
|
||||||
#define EXCP_DUMP(env, fmt, ...) \
|
#define EXCP_DUMP(env, fmt, ...) \
|
||||||
do { \
|
do { \
|
||||||
|
@ -50,9 +50,9 @@ void cpu_loop(CPUCRISState *env)
|
|||||||
env->pregs[7],
|
env->pregs[7],
|
||||||
env->pregs[11],
|
env->pregs[11],
|
||||||
0, 0);
|
0, 0);
|
||||||
if (ret == -TARGET_ERESTARTSYS) {
|
if (ret == -QEMU_ERESTARTSYS) {
|
||||||
env->pc -= 2;
|
env->pc -= 2;
|
||||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
} else if (ret != -QEMU_ESIGRETURN) {
|
||||||
env->regs[10] = ret;
|
env->regs[10] = ret;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -177,10 +177,10 @@ long do_sigreturn(CPUCRISState *env)
|
|||||||
|
|
||||||
restore_sigcontext(&frame->sc, env);
|
restore_sigcontext(&frame->sc, env);
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
badframe:
|
badframe:
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
long do_rt_sigreturn(CPUCRISState *env)
|
long do_rt_sigreturn(CPUCRISState *env)
|
||||||
|
@ -147,21 +147,4 @@
|
|||||||
#define TARGET_ERFKILL 132 /* Operation not possible due to RF-kill */
|
#define TARGET_ERFKILL 132 /* Operation not possible due to RF-kill */
|
||||||
#define TARGET_EHWPOISON 133 /* Memory page has hardware error */
|
#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
|
#endif
|
||||||
|
@ -55,9 +55,9 @@ void cpu_loop(CPUHexagonState *env)
|
|||||||
env->gpr[4],
|
env->gpr[4],
|
||||||
env->gpr[5],
|
env->gpr[5],
|
||||||
0, 0);
|
0, 0);
|
||||||
if (ret == -TARGET_ERESTARTSYS) {
|
if (ret == -QEMU_ERESTARTSYS) {
|
||||||
env->gpr[HEX_REG_PC] -= 4;
|
env->gpr[HEX_REG_PC] -= 4;
|
||||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
} else if (ret != -QEMU_ESIGRETURN) {
|
||||||
env->gpr[0] = ret;
|
env->gpr[0] = ret;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -268,7 +268,7 @@ long do_rt_sigreturn(CPUHexagonState *env)
|
|||||||
target_restore_altstack(&frame->uc.uc_stack, env);
|
target_restore_altstack(&frame->uc.uc_stack, env);
|
||||||
|
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -133,8 +133,8 @@ void cpu_loop(CPUHPPAState *env)
|
|||||||
env->iaoq_f = env->gr[31];
|
env->iaoq_f = env->gr[31];
|
||||||
env->iaoq_b = env->gr[31] + 4;
|
env->iaoq_b = env->gr[31] + 4;
|
||||||
break;
|
break;
|
||||||
case -TARGET_ERESTARTSYS:
|
case -QEMU_ERESTARTSYS:
|
||||||
case -TARGET_QEMU_ESIGRETURN:
|
case -QEMU_ESIGRETURN:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -191,9 +191,9 @@ long do_rt_sigreturn(CPUArchState *env)
|
|||||||
target_restore_altstack(&frame->uc.tuc_stack, env);
|
target_restore_altstack(&frame->uc.tuc_stack, env);
|
||||||
|
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
@ -180,8 +180,8 @@ static void emulate_vsyscall(CPUX86State *env)
|
|||||||
ret = do_syscall(env, syscall, env->regs[R_EDI], env->regs[R_ESI],
|
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[R_EDX], env->regs[10], env->regs[8],
|
||||||
env->regs[9], 0, 0);
|
env->regs[9], 0, 0);
|
||||||
g_assert(ret != -TARGET_ERESTARTSYS);
|
g_assert(ret != -QEMU_ERESTARTSYS);
|
||||||
g_assert(ret != -TARGET_QEMU_ESIGRETURN);
|
g_assert(ret != -QEMU_ESIGRETURN);
|
||||||
if (ret == -TARGET_EFAULT) {
|
if (ret == -TARGET_EFAULT) {
|
||||||
goto sigsegv;
|
goto sigsegv;
|
||||||
}
|
}
|
||||||
@ -223,9 +223,9 @@ void cpu_loop(CPUX86State *env)
|
|||||||
env->regs[R_EDI],
|
env->regs[R_EDI],
|
||||||
env->regs[R_EBP],
|
env->regs[R_EBP],
|
||||||
0, 0);
|
0, 0);
|
||||||
if (ret == -TARGET_ERESTARTSYS) {
|
if (ret == -QEMU_ERESTARTSYS) {
|
||||||
env->eip -= 2;
|
env->eip -= 2;
|
||||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
} else if (ret != -QEMU_ESIGRETURN) {
|
||||||
env->regs[R_EAX] = ret;
|
env->regs[R_EAX] = ret;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -241,9 +241,9 @@ void cpu_loop(CPUX86State *env)
|
|||||||
env->regs[8],
|
env->regs[8],
|
||||||
env->regs[9],
|
env->regs[9],
|
||||||
0, 0);
|
0, 0);
|
||||||
if (ret == -TARGET_ERESTARTSYS) {
|
if (ret == -QEMU_ERESTARTSYS) {
|
||||||
env->eip -= 2;
|
env->eip -= 2;
|
||||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
} else if (ret != -QEMU_ESIGRETURN) {
|
||||||
env->regs[R_EAX] = ret;
|
env->regs[R_EAX] = ret;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -559,12 +559,12 @@ long do_sigreturn(CPUX86State *env)
|
|||||||
if (restore_sigcontext(env, &frame->sc))
|
if (restore_sigcontext(env, &frame->sc))
|
||||||
goto badframe;
|
goto badframe;
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -588,12 +588,12 @@ long do_rt_sigreturn(CPUX86State *env)
|
|||||||
target_restore_altstack(&frame->uc.tuc_stack, env);
|
target_restore_altstack(&frame->uc.tuc_stack, env);
|
||||||
|
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TARGET_X86_64
|
#ifndef TARGET_X86_64
|
||||||
|
@ -80,9 +80,9 @@ void cpu_loop(CPUM68KState *env)
|
|||||||
env->dregs[5],
|
env->dregs[5],
|
||||||
env->aregs[0],
|
env->aregs[0],
|
||||||
0, 0);
|
0, 0);
|
||||||
if (ret == -TARGET_ERESTARTSYS) {
|
if (ret == -QEMU_ERESTARTSYS) {
|
||||||
env->pc -= 2;
|
env->pc -= 2;
|
||||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
} else if (ret != -QEMU_ESIGRETURN) {
|
||||||
env->dregs[0] = ret;
|
env->dregs[0] = ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -353,11 +353,11 @@ long do_sigreturn(CPUM68KState *env)
|
|||||||
restore_sigcontext(env, &frame->sc);
|
restore_sigcontext(env, &frame->sc);
|
||||||
|
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
long do_rt_sigreturn(CPUM68KState *env)
|
long do_rt_sigreturn(CPUM68KState *env)
|
||||||
@ -381,12 +381,12 @@ long do_rt_sigreturn(CPUM68KState *env)
|
|||||||
target_restore_altstack(&frame->uc.tuc_stack, env);
|
target_restore_altstack(&frame->uc.tuc_stack, env);
|
||||||
|
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup_sigtramp(abi_ulong sigtramp_page)
|
void setup_sigtramp(abi_ulong sigtramp_page)
|
||||||
|
@ -2,6 +2,11 @@ if not have_linux_user
|
|||||||
subdir_done()
|
subdir_done()
|
||||||
endif
|
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(
|
linux_user_ss.add(files(
|
||||||
'elfload.c',
|
'elfload.c',
|
||||||
'exit.c',
|
'exit.c',
|
||||||
@ -9,10 +14,10 @@ linux_user_ss.add(files(
|
|||||||
'linuxload.c',
|
'linuxload.c',
|
||||||
'main.c',
|
'main.c',
|
||||||
'mmap.c',
|
'mmap.c',
|
||||||
'safe-syscall.S',
|
|
||||||
'signal.c',
|
'signal.c',
|
||||||
'strace.c',
|
'strace.c',
|
||||||
'syscall.c',
|
'syscall.c',
|
||||||
|
'thunk.c',
|
||||||
'uaccess.c',
|
'uaccess.c',
|
||||||
'uname.c',
|
'uname.c',
|
||||||
))
|
))
|
||||||
@ -39,3 +44,5 @@ subdir('sh4')
|
|||||||
subdir('sparc')
|
subdir('sparc')
|
||||||
subdir('x86_64')
|
subdir('x86_64')
|
||||||
subdir('xtensa')
|
subdir('xtensa')
|
||||||
|
|
||||||
|
specific_ss.add_all(when: 'CONFIG_LINUX_USER', if_true: linux_user_ss)
|
||||||
|
@ -53,10 +53,10 @@ void cpu_loop(CPUMBState *env)
|
|||||||
env->regs[9],
|
env->regs[9],
|
||||||
env->regs[10],
|
env->regs[10],
|
||||||
0, 0);
|
0, 0);
|
||||||
if (ret == -TARGET_ERESTARTSYS) {
|
if (ret == -QEMU_ERESTARTSYS) {
|
||||||
/* Wind back to before the syscall. */
|
/* Wind back to before the syscall. */
|
||||||
env->pc -= 4;
|
env->pc -= 4;
|
||||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
} else if (ret != -QEMU_ESIGRETURN) {
|
||||||
env->regs[3] = ret;
|
env->regs[3] = ret;
|
||||||
}
|
}
|
||||||
/* All syscall exits result in guest r14 being equal to the
|
/* All syscall exits result in guest r14 being equal to the
|
||||||
|
@ -207,12 +207,12 @@ long do_rt_sigreturn(CPUMBState *env)
|
|||||||
target_restore_altstack(&frame->uc.tuc_stack, env);
|
target_restore_altstack(&frame->uc.tuc_stack, env);
|
||||||
|
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup_sigtramp(abi_ulong sigtramp_page)
|
void setup_sigtramp(abi_ulong sigtramp_page)
|
||||||
|
@ -141,11 +141,11 @@ done_syscall:
|
|||||||
env->active_tc.gpr[8], env->active_tc.gpr[9],
|
env->active_tc.gpr[8], env->active_tc.gpr[9],
|
||||||
env->active_tc.gpr[10], env->active_tc.gpr[11]);
|
env->active_tc.gpr[10], env->active_tc.gpr[11]);
|
||||||
# endif /* O32 */
|
# endif /* O32 */
|
||||||
if (ret == -TARGET_ERESTARTSYS) {
|
if (ret == -QEMU_ERESTARTSYS) {
|
||||||
env->active_tc.PC -= 4;
|
env->active_tc.PC -= 4;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (ret == -TARGET_QEMU_ESIGRETURN) {
|
if (ret == -QEMU_ESIGRETURN) {
|
||||||
/* Returning from a successful sigreturn syscall.
|
/* Returning from a successful sigreturn syscall.
|
||||||
Avoid clobbering register state. */
|
Avoid clobbering register state. */
|
||||||
break;
|
break;
|
||||||
|
@ -281,11 +281,11 @@ long do_sigreturn(CPUMIPSState *regs)
|
|||||||
/* I am not sure this is right, but it seems to work
|
/* I am not sure this is right, but it seems to work
|
||||||
* maybe a problem with nested signals ? */
|
* maybe a problem with nested signals ? */
|
||||||
regs->CP0_EPC = 0;
|
regs->CP0_EPC = 0;
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
# endif /* O32 */
|
# endif /* O32 */
|
||||||
|
|
||||||
@ -371,11 +371,11 @@ long do_rt_sigreturn(CPUMIPSState *env)
|
|||||||
/* I am not sure this is right, but it seems to work
|
/* I am not sure this is right, but it seems to work
|
||||||
* maybe a problem with nested signals ? */
|
* maybe a problem with nested signals ? */
|
||||||
env->CP0_EPC = 0;
|
env->CP0_EPC = 0;
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup_sigtramp(abi_ulong sigtramp_page)
|
void setup_sigtramp(abi_ulong sigtramp_page)
|
||||||
|
@ -48,9 +48,9 @@ void cpu_loop(CPUOpenRISCState *env)
|
|||||||
cpu_get_gpr(env, 6),
|
cpu_get_gpr(env, 6),
|
||||||
cpu_get_gpr(env, 7),
|
cpu_get_gpr(env, 7),
|
||||||
cpu_get_gpr(env, 8), 0, 0);
|
cpu_get_gpr(env, 8), 0, 0);
|
||||||
if (ret == -TARGET_ERESTARTSYS) {
|
if (ret == -QEMU_ERESTARTSYS) {
|
||||||
env->pc -= 4;
|
env->pc -= 4;
|
||||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
} else if (ret != -QEMU_ESIGRETURN) {
|
||||||
cpu_set_gpr(env, 11, ret);
|
cpu_set_gpr(env, 11, ret);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -428,11 +428,11 @@ void cpu_loop(CPUPPCState *env)
|
|||||||
ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
|
ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
|
||||||
env->gpr[5], env->gpr[6], env->gpr[7],
|
env->gpr[5], env->gpr[6], env->gpr[7],
|
||||||
env->gpr[8], 0, 0);
|
env->gpr[8], 0, 0);
|
||||||
if (ret == -TARGET_ERESTARTSYS) {
|
if (ret == -QEMU_ERESTARTSYS) {
|
||||||
env->nip -= 4;
|
env->nip -= 4;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) {
|
if (ret == (target_ulong)(-QEMU_ESIGRETURN)) {
|
||||||
/* Returning from a successful sigreturn syscall.
|
/* Returning from a successful sigreturn syscall.
|
||||||
Avoid corrupting register state. */
|
Avoid corrupting register state. */
|
||||||
break;
|
break;
|
||||||
|
@ -591,13 +591,13 @@ long do_sigreturn(CPUPPCState *env)
|
|||||||
|
|
||||||
unlock_user_struct(sr, sr_addr, 1);
|
unlock_user_struct(sr, sr_addr, 1);
|
||||||
unlock_user_struct(sc, sc_addr, 1);
|
unlock_user_struct(sc, sc_addr, 1);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
|
|
||||||
sigsegv:
|
sigsegv:
|
||||||
unlock_user_struct(sr, sr_addr, 1);
|
unlock_user_struct(sr, sr_addr, 1);
|
||||||
unlock_user_struct(sc, sc_addr, 1);
|
unlock_user_struct(sc, sc_addr, 1);
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
#endif /* !defined(TARGET_PPC64) */
|
#endif /* !defined(TARGET_PPC64) */
|
||||||
|
|
||||||
@ -646,12 +646,12 @@ long do_rt_sigreturn(CPUPPCState *env)
|
|||||||
target_restore_altstack(&rt_sf->uc.tuc_stack, env);
|
target_restore_altstack(&rt_sf->uc.tuc_stack, env);
|
||||||
|
|
||||||
unlock_user_struct(rt_sf, rt_sf_addr, 1);
|
unlock_user_struct(rt_sf, rt_sf_addr, 1);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
|
|
||||||
sigsegv:
|
sigsegv:
|
||||||
unlock_user_struct(rt_sf, rt_sf_addr, 1);
|
unlock_user_struct(rt_sf, rt_sf_addr, 1);
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This syscall implements {get,set,swap}context for userland. */
|
/* 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. */
|
/* We cannot return to a partially updated context. */
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
}
|
}
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -69,9 +69,9 @@ void cpu_loop(CPURISCVState *env)
|
|||||||
env->gpr[xA5],
|
env->gpr[xA5],
|
||||||
0, 0);
|
0, 0);
|
||||||
}
|
}
|
||||||
if (ret == -TARGET_ERESTARTSYS) {
|
if (ret == -QEMU_ERESTARTSYS) {
|
||||||
env->pc -= 4;
|
env->pc -= 4;
|
||||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
} else if (ret != -QEMU_ESIGRETURN) {
|
||||||
env->gpr[xA0] = ret;
|
env->gpr[xA0] = ret;
|
||||||
}
|
}
|
||||||
if (cs->singlestep_enabled) {
|
if (cs->singlestep_enabled) {
|
||||||
|
@ -188,7 +188,7 @@ long do_rt_sigreturn(CPURISCVState *env)
|
|||||||
target_restore_altstack(&frame->uc.uc_stack, env);
|
target_restore_altstack(&frame->uc.uc_stack, env);
|
||||||
|
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
|
@ -83,9 +83,9 @@ void cpu_loop(CPUS390XState *env)
|
|||||||
ret = do_syscall(env, n, env->regs[2], env->regs[3],
|
ret = do_syscall(env, n, env->regs[2], env->regs[3],
|
||||||
env->regs[4], env->regs[5],
|
env->regs[4], env->regs[5],
|
||||||
env->regs[6], env->regs[7], 0, 0);
|
env->regs[6], env->regs[7], 0, 0);
|
||||||
if (ret == -TARGET_ERESTARTSYS) {
|
if (ret == -QEMU_ERESTARTSYS) {
|
||||||
env->psw.addr -= env->int_svc_ilen;
|
env->psw.addr -= env->int_svc_ilen;
|
||||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
} else if (ret != -QEMU_ESIGRETURN) {
|
||||||
env->regs[2] = ret;
|
env->regs[2] = ret;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -359,7 +359,7 @@ long do_sigreturn(CPUS390XState *env)
|
|||||||
trace_user_do_sigreturn(env, frame_addr);
|
trace_user_do_sigreturn(env, frame_addr);
|
||||||
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
|
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure that we're initializing all of target_set. */
|
/* 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);
|
restore_sigregs_ext(env, &frame->sregs_ext);
|
||||||
|
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
long do_rt_sigreturn(CPUS390XState *env)
|
long do_rt_sigreturn(CPUS390XState *env)
|
||||||
@ -385,7 +385,7 @@ long do_rt_sigreturn(CPUS390XState *env)
|
|||||||
trace_user_do_rt_sigreturn(env, frame_addr);
|
trace_user_do_rt_sigreturn(env, frame_addr);
|
||||||
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
|
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
|
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);
|
target_restore_altstack(&frame->uc.tuc_stack, env);
|
||||||
|
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup_sigtramp(abi_ulong sigtramp_page)
|
void setup_sigtramp(abi_ulong sigtramp_page)
|
||||||
|
@ -50,9 +50,9 @@ void cpu_loop(CPUSH4State *env)
|
|||||||
env->gregs[0],
|
env->gregs[0],
|
||||||
env->gregs[1],
|
env->gregs[1],
|
||||||
0, 0);
|
0, 0);
|
||||||
if (ret == -TARGET_ERESTARTSYS) {
|
if (ret == -QEMU_ERESTARTSYS) {
|
||||||
env->pc -= 2;
|
env->pc -= 2;
|
||||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
} else if (ret != -QEMU_ESIGRETURN) {
|
||||||
env->gregs[0] = ret;
|
env->gregs[0] = ret;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -286,12 +286,12 @@ long do_sigreturn(CPUSH4State *regs)
|
|||||||
restore_sigcontext(regs, &frame->sc);
|
restore_sigcontext(regs, &frame->sc);
|
||||||
|
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
long do_rt_sigreturn(CPUSH4State *regs)
|
long do_rt_sigreturn(CPUSH4State *regs)
|
||||||
@ -313,12 +313,12 @@ long do_rt_sigreturn(CPUSH4State *regs)
|
|||||||
target_restore_altstack(&frame->uc.tuc_stack, regs);
|
target_restore_altstack(&frame->uc.tuc_stack, regs);
|
||||||
|
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup_sigtramp(abi_ulong sigtramp_page)
|
void setup_sigtramp(abi_ulong sigtramp_page)
|
||||||
|
@ -20,6 +20,8 @@
|
|||||||
#ifndef SIGNAL_COMMON_H
|
#ifndef SIGNAL_COMMON_H
|
||||||
#define SIGNAL_COMMON_H
|
#define SIGNAL_COMMON_H
|
||||||
|
|
||||||
|
#include "special-errno.h"
|
||||||
|
|
||||||
/* Fallback addresses into sigtramp page. */
|
/* Fallback addresses into sigtramp page. */
|
||||||
extern abi_ulong default_sigreturn;
|
extern abi_ulong default_sigreturn;
|
||||||
extern abi_ulong default_rt_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
|
* 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.
|
* its correct value for the guest before we resume execution of guest code.
|
||||||
* If this function returns non-zero, then the caller should immediately
|
* 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.
|
* signal and restart execution of the syscall.
|
||||||
* If block_signals() returns zero, then the caller can continue with
|
* If block_signals() returns zero, then the caller can continue with
|
||||||
* emulation of the system call knowing that no signals can be taken
|
* emulation of the system call knowing that no signals can be taken
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
#include "signal-common.h"
|
#include "signal-common.h"
|
||||||
#include "host-signal.h"
|
#include "host-signal.h"
|
||||||
#include "safe-syscall.h"
|
#include "user/safe-syscall.h"
|
||||||
|
|
||||||
static struct target_sigaction sigact_table[TARGET_NSIG];
|
static struct target_sigaction sigact_table[TARGET_NSIG];
|
||||||
|
|
||||||
@ -213,7 +213,7 @@ int block_signals(void)
|
|||||||
|
|
||||||
/* Wrapper for sigprocmask function
|
/* Wrapper for sigprocmask function
|
||||||
* Emulates a sigprocmask in a safe way for the guest. Note that set and oldset
|
* 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
|
* a signal was already pending and the syscall must be restarted, or
|
||||||
* 0 on success.
|
* 0 on success.
|
||||||
* If set is NULL, this is guaranteed not to fail.
|
* 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;
|
int i;
|
||||||
|
|
||||||
if (block_signals()) {
|
if (block_signals()) {
|
||||||
return -TARGET_ERESTARTSYS;
|
return -QEMU_ERESTARTSYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (how) {
|
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 */
|
/* 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)
|
static inline void rewind_if_in_safe_syscall(void *puc)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_SAFE_SYSCALL
|
|
||||||
ucontext_t *uc = (ucontext_t *)puc;
|
ucontext_t *uc = (ucontext_t *)puc;
|
||||||
uintptr_t pcreg = host_signal_pc(uc);
|
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) {
|
&& pcreg < (uintptr_t)safe_syscall_end) {
|
||||||
host_signal_set_pc(uc, (uintptr_t)safe_syscall_start);
|
host_signal_set_pc(uc, (uintptr_t)safe_syscall_start);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
|
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()) {
|
if (block_signals()) {
|
||||||
return -TARGET_ERESTARTSYS;
|
return -QEMU_ERESTARTSYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
k = &sigact_table[sig - 1];
|
k = &sigact_table[sig - 1];
|
||||||
|
@ -181,7 +181,7 @@ void cpu_loop (CPUSPARCState *env)
|
|||||||
env->regwptr[2], env->regwptr[3],
|
env->regwptr[2], env->regwptr[3],
|
||||||
env->regwptr[4], env->regwptr[5],
|
env->regwptr[4], env->regwptr[5],
|
||||||
0, 0);
|
0, 0);
|
||||||
if (ret == -TARGET_ERESTARTSYS || ret == -TARGET_QEMU_ESIGRETURN) {
|
if (ret == -QEMU_ERESTARTSYS || ret == -QEMU_ESIGRETURN) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ((abi_ulong)ret >= (abi_ulong)(-515)) {
|
if ((abi_ulong)ret >= (abi_ulong)(-515)) {
|
||||||
|
@ -431,12 +431,12 @@ long do_sigreturn(CPUSPARCState *env)
|
|||||||
set_sigmask(&host_set);
|
set_sigmask(&host_set);
|
||||||
|
|
||||||
unlock_user_struct(sf, sf_addr, 0);
|
unlock_user_struct(sf, sf_addr, 0);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
|
|
||||||
segv_and_exit:
|
segv_and_exit:
|
||||||
unlock_user_struct(sf, sf_addr, 0);
|
unlock_user_struct(sf, sf_addr, 0);
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
#else
|
#else
|
||||||
return -TARGET_ENOSYS;
|
return -TARGET_ENOSYS;
|
||||||
#endif
|
#endif
|
||||||
@ -495,12 +495,12 @@ long do_rt_sigreturn(CPUSPARCState *env)
|
|||||||
env->npc = tnpc;
|
env->npc = tnpc;
|
||||||
|
|
||||||
unlock_user_struct(sf, sf_addr, 0);
|
unlock_user_struct(sf, sf_addr, 0);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
|
|
||||||
segv_and_exit:
|
segv_and_exit:
|
||||||
unlock_user_struct(sf, sf_addr, 0);
|
unlock_user_struct(sf, sf_addr, 0);
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
|
#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
|
||||||
|
32
linux-user/special-errno.h
Normal file
32
linux-user/special-errno.h
Normal file
@ -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 */
|
@ -132,10 +132,11 @@
|
|||||||
#include "signal-common.h"
|
#include "signal-common.h"
|
||||||
#include "loader.h"
|
#include "loader.h"
|
||||||
#include "user-mmap.h"
|
#include "user-mmap.h"
|
||||||
#include "safe-syscall.h"
|
#include "user/safe-syscall.h"
|
||||||
#include "qemu/guest-random.h"
|
#include "qemu/guest-random.h"
|
||||||
#include "qemu/selfmap.h"
|
#include "qemu/selfmap.h"
|
||||||
#include "user/syscall-trace.h"
|
#include "user/syscall-trace.h"
|
||||||
|
#include "special-errno.h"
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
#include "fd-trans.h"
|
#include "fd-trans.h"
|
||||||
#include "tcg/tcg.h"
|
#include "tcg/tcg.h"
|
||||||
@ -547,10 +548,10 @@ static inline abi_long get_errno(abi_long ret)
|
|||||||
|
|
||||||
const char *target_strerror(int err)
|
const char *target_strerror(int err)
|
||||||
{
|
{
|
||||||
if (err == TARGET_ERESTARTSYS) {
|
if (err == QEMU_ERESTARTSYS) {
|
||||||
return "To be restarted";
|
return "To be restarted";
|
||||||
}
|
}
|
||||||
if (err == TARGET_QEMU_ESIGRETURN) {
|
if (err == QEMU_ESIGRETURN) {
|
||||||
return "Successful exit from sigreturn";
|
return "Successful exit from sigreturn";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6458,7 +6459,7 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (block_signals()) {
|
if (block_signals()) {
|
||||||
return -TARGET_ERESTARTSYS;
|
return -QEMU_ERESTARTSYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
fork_start();
|
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. */
|
Do thread termination if we have more then one thread. */
|
||||||
|
|
||||||
if (block_signals()) {
|
if (block_signals()) {
|
||||||
return -TARGET_ERESTARTSYS;
|
return -QEMU_ERESTARTSYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_lock(&clone_lock);
|
pthread_mutex_lock(&clone_lock);
|
||||||
@ -9317,7 +9318,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
|
|||||||
#endif
|
#endif
|
||||||
ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
|
ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
|
||||||
SIGSET_T_SIZE));
|
SIGSET_T_SIZE));
|
||||||
if (ret != -TARGET_ERESTARTSYS) {
|
if (ret != -QEMU_ERESTARTSYS) {
|
||||||
ts->in_sigsuspend = 1;
|
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);
|
unlock_user(p, arg1, 0);
|
||||||
ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
|
ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
|
||||||
SIGSET_T_SIZE));
|
SIGSET_T_SIZE));
|
||||||
if (ret != -TARGET_ERESTARTSYS) {
|
if (ret != -QEMU_ERESTARTSYS) {
|
||||||
ts->in_sigsuspend = 1;
|
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
|
#ifdef TARGET_NR_sigreturn
|
||||||
case TARGET_NR_sigreturn:
|
case TARGET_NR_sigreturn:
|
||||||
if (block_signals()) {
|
if (block_signals()) {
|
||||||
return -TARGET_ERESTARTSYS;
|
return -QEMU_ERESTARTSYS;
|
||||||
}
|
}
|
||||||
return do_sigreturn(cpu_env);
|
return do_sigreturn(cpu_env);
|
||||||
#endif
|
#endif
|
||||||
case TARGET_NR_rt_sigreturn:
|
case TARGET_NR_rt_sigreturn:
|
||||||
if (block_signals()) {
|
if (block_signals()) {
|
||||||
return -TARGET_ERESTARTSYS;
|
return -QEMU_ERESTARTSYS;
|
||||||
}
|
}
|
||||||
return do_rt_sigreturn(cpu_env);
|
return do_rt_sigreturn(cpu_env);
|
||||||
case TARGET_NR_sethostname:
|
case TARGET_NR_sethostname:
|
||||||
@ -13145,7 +13146,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
|||||||
static bool flag;
|
static bool flag;
|
||||||
flag = !flag;
|
flag = !flag;
|
||||||
if (flag) {
|
if (flag) {
|
||||||
return -TARGET_ERESTARTSYS;
|
return -QEMU_ERESTARTSYS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
#ifndef LINUX_USER_USER_INTERNALS_H
|
#ifndef LINUX_USER_USER_INTERNALS_H
|
||||||
#define LINUX_USER_USER_INTERNALS_H
|
#define LINUX_USER_USER_INTERNALS_H
|
||||||
|
|
||||||
#include "hostdep.h"
|
|
||||||
#include "exec/user/thunk.h"
|
#include "exec/user/thunk.h"
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "qemu/log.h"
|
#include "qemu/log.h"
|
||||||
|
@ -184,11 +184,11 @@ void cpu_loop(CPUXtensaState *env)
|
|||||||
env->regs[2] = ret;
|
env->regs[2] = ret;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case -TARGET_ERESTARTSYS:
|
case -QEMU_ERESTARTSYS:
|
||||||
env->pc -= 3;
|
env->pc -= 3;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case -TARGET_QEMU_ESIGRETURN:
|
case -QEMU_ESIGRETURN:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -263,12 +263,12 @@ long do_rt_sigreturn(CPUXtensaState *env)
|
|||||||
target_restore_altstack(&frame->uc.tuc_stack, env);
|
target_restore_altstack(&frame->uc.tuc_stack, env);
|
||||||
|
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup_sigtramp(abi_ulong sigtramp_page)
|
void setup_sigtramp(abi_ulong sigtramp_page)
|
||||||
|
23
meson.build
23
meson.build
@ -2375,13 +2375,12 @@ genh += hxdep
|
|||||||
authz_ss = ss.source_set()
|
authz_ss = ss.source_set()
|
||||||
blockdev_ss = ss.source_set()
|
blockdev_ss = ss.source_set()
|
||||||
block_ss = ss.source_set()
|
block_ss = ss.source_set()
|
||||||
bsd_user_ss = ss.source_set()
|
|
||||||
chardev_ss = ss.source_set()
|
chardev_ss = ss.source_set()
|
||||||
common_ss = ss.source_set()
|
common_ss = ss.source_set()
|
||||||
|
common_user_ss = ss.source_set()
|
||||||
crypto_ss = ss.source_set()
|
crypto_ss = ss.source_set()
|
||||||
hwcore_ss = ss.source_set()
|
hwcore_ss = ss.source_set()
|
||||||
io_ss = ss.source_set()
|
io_ss = ss.source_set()
|
||||||
linux_user_ss = ss.source_set()
|
|
||||||
qmp_ss = ss.source_set()
|
qmp_ss = ss.source_set()
|
||||||
qom_ss = ss.source_set()
|
qom_ss = ss.source_set()
|
||||||
softmmu_ss = ss.source_set()
|
softmmu_ss = ss.source_set()
|
||||||
@ -2622,14 +2621,24 @@ subdir('tcg')
|
|||||||
subdir('fpu')
|
subdir('fpu')
|
||||||
subdir('accel')
|
subdir('accel')
|
||||||
subdir('plugins')
|
subdir('plugins')
|
||||||
subdir('bsd-user')
|
|
||||||
subdir('linux-user')
|
|
||||||
subdir('ebpf')
|
subdir('ebpf')
|
||||||
|
|
||||||
specific_ss.add_all(when: 'CONFIG_BSD_USER', if_true: bsd_user_ss)
|
common_user_inc = []
|
||||||
|
|
||||||
linux_user_ss.add(files('thunk.c'))
|
subdir('common-user')
|
||||||
specific_ss.add_all(when: 'CONFIG_LINUX_USER', if_true: linux_user_ss)
|
subdir('bsd-user')
|
||||||
|
subdir('linux-user')
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
user_ss.add(common_user)
|
||||||
|
|
||||||
# needed for fuzzing binaries
|
# needed for fuzzing binaries
|
||||||
subdir('tests/qtest/libqos')
|
subdir('tests/qtest/libqos')
|
||||||
|
Loading…
Reference in New Issue
Block a user