mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-04 08:13:54 -06:00
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
80 changed files with 1099 additions and 932 deletions
|
@ -99,9 +99,9 @@ void cpu_loop(CPUARMState *env)
|
|||
env->xregs[4],
|
||||
env->xregs[5],
|
||||
0, 0);
|
||||
if (ret == -TARGET_ERESTARTSYS) {
|
||||
if (ret == -QEMU_ERESTARTSYS) {
|
||||
env->pc -= 4;
|
||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
||||
} else if (ret != -QEMU_ESIGRETURN) {
|
||||
env->xregs[0] = ret;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -556,12 +556,12 @@ long do_rt_sigreturn(CPUARMState *env)
|
|||
target_restore_altstack(&frame->uc.tuc_stack, env);
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
long do_sigreturn(CPUARMState *env)
|
||||
|
|
|
@ -98,11 +98,11 @@ void cpu_loop(CPUAlphaState *env)
|
|||
env->ir[IR_A2], env->ir[IR_A3],
|
||||
env->ir[IR_A4], env->ir[IR_A5],
|
||||
0, 0);
|
||||
if (sysret == -TARGET_ERESTARTSYS) {
|
||||
if (sysret == -QEMU_ERESTARTSYS) {
|
||||
env->pc -= 4;
|
||||
break;
|
||||
}
|
||||
if (sysret == -TARGET_QEMU_ESIGRETURN) {
|
||||
if (sysret == -QEMU_ESIGRETURN) {
|
||||
break;
|
||||
}
|
||||
/* Syscall writes 0 to V0 to bypass error check, similar
|
||||
|
|
|
@ -225,11 +225,11 @@ long do_sigreturn(CPUAlphaState *env)
|
|||
|
||||
restore_sigcontext(env, sc);
|
||||
unlock_user_struct(sc, sc_addr, 0);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
long do_rt_sigreturn(CPUAlphaState *env)
|
||||
|
@ -249,13 +249,13 @@ long do_rt_sigreturn(CPUAlphaState *env)
|
|||
target_restore_altstack(&frame->uc.tuc_stack, env);
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
|
||||
|
||||
badframe:
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
void setup_sigtramp(abi_ulong sigtramp_page)
|
||||
|
|
|
@ -407,9 +407,9 @@ void cpu_loop(CPUARMState *env)
|
|||
env->regs[4],
|
||||
env->regs[5],
|
||||
0, 0);
|
||||
if (ret == -TARGET_ERESTARTSYS) {
|
||||
if (ret == -QEMU_ERESTARTSYS) {
|
||||
env->regs[15] -= env->thumb ? 2 : 4;
|
||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
||||
} else if (ret != -QEMU_ESIGRETURN) {
|
||||
env->regs[0] = ret;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -511,12 +511,12 @@ long do_sigreturn(CPUARMState *env)
|
|||
}
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
long do_rt_sigreturn(CPUARMState *env)
|
||||
|
@ -546,12 +546,12 @@ long do_rt_sigreturn(CPUARMState *env)
|
|||
}
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#define CPU_LOOP_COMMON_H
|
||||
|
||||
#include "exec/log.h"
|
||||
#include "special-errno.h"
|
||||
|
||||
#define EXCP_DUMP(env, fmt, ...) \
|
||||
do { \
|
||||
|
|
|
@ -50,9 +50,9 @@ void cpu_loop(CPUCRISState *env)
|
|||
env->pregs[7],
|
||||
env->pregs[11],
|
||||
0, 0);
|
||||
if (ret == -TARGET_ERESTARTSYS) {
|
||||
if (ret == -QEMU_ERESTARTSYS) {
|
||||
env->pc -= 2;
|
||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
||||
} else if (ret != -QEMU_ESIGRETURN) {
|
||||
env->regs[10] = ret;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -177,10 +177,10 @@ long do_sigreturn(CPUCRISState *env)
|
|||
|
||||
restore_sigcontext(&frame->sc, env);
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
badframe:
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
long do_rt_sigreturn(CPUCRISState *env)
|
||||
|
|
|
@ -147,21 +147,4 @@
|
|||
#define TARGET_ERFKILL 132 /* Operation not possible due to RF-kill */
|
||||
#define TARGET_EHWPOISON 133 /* Memory page has hardware error */
|
||||
|
||||
/* QEMU internal, not visible to the guest. This is returned when a
|
||||
* system call should be restarted, to tell the main loop that it
|
||||
* should wind the guest PC backwards so it will re-execute the syscall
|
||||
* after handling any pending signals. They match with the ones the guest
|
||||
* kernel uses for the same purpose.
|
||||
*/
|
||||
#define TARGET_ERESTARTSYS 512 /* Restart system call (if SA_RESTART) */
|
||||
|
||||
/* QEMU internal, not visible to the guest. This is returned by the
|
||||
* do_sigreturn() code after a successful sigreturn syscall, to indicate
|
||||
* that it has correctly set the guest registers and so the main loop
|
||||
* should not touch them. We use the value the guest would use for
|
||||
* ERESTART_NOINTR (which is kernel internal) to guarantee that we won't
|
||||
* clash with a valid guest errno now or in the future.
|
||||
*/
|
||||
#define TARGET_QEMU_ESIGRETURN 513 /* Return from signal */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -55,9 +55,9 @@ void cpu_loop(CPUHexagonState *env)
|
|||
env->gpr[4],
|
||||
env->gpr[5],
|
||||
0, 0);
|
||||
if (ret == -TARGET_ERESTARTSYS) {
|
||||
if (ret == -QEMU_ERESTARTSYS) {
|
||||
env->gpr[HEX_REG_PC] -= 4;
|
||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
||||
} else if (ret != -QEMU_ESIGRETURN) {
|
||||
env->gpr[0] = ret;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -268,7 +268,7 @@ long do_rt_sigreturn(CPUHexagonState *env)
|
|||
target_restore_altstack(&frame->uc.uc_stack, env);
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
|
|
|
@ -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
|
|
@ -1,91 +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
|
||||
*
|
||||
* Copyright (C) 2015 Timothy Edward Baldwin <T.E.Baldwin99@members.leeds.ac.uk>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
.global safe_syscall_base
|
||||
.global safe_syscall_start
|
||||
.global safe_syscall_end
|
||||
.type safe_syscall_base, @function
|
||||
|
||||
/* This is the entry point for making a system call. The calling
|
||||
* convention here is that of a C varargs function with the
|
||||
* first argument an 'int *' to the signal_pending flag, the
|
||||
* second one the system call number (as a 'long'), and all further
|
||||
* arguments being syscall arguments (also 'long').
|
||||
* We return a long which is the syscall's return value, which
|
||||
* may be negative-errno on failure. Conversion to the
|
||||
* -1-and-errno-set convention is done by the calling wrapper.
|
||||
*/
|
||||
safe_syscall_base:
|
||||
.cfi_startproc
|
||||
/* This saves a frame pointer and aligns the stack for the syscall.
|
||||
* (It's unclear if the syscall ABI has the same stack alignment
|
||||
* requirements as the userspace function call ABI, but better safe than
|
||||
* sorry. Appendix A2 of http://www.x86-64.org/documentation/abi.pdf
|
||||
* does not list any ABI differences regarding stack alignment.)
|
||||
*/
|
||||
push %rbp
|
||||
.cfi_adjust_cfa_offset 8
|
||||
.cfi_rel_offset rbp, 0
|
||||
|
||||
/* The syscall calling convention isn't the same as the
|
||||
* C one:
|
||||
* we enter with rdi == *signal_pending
|
||||
* rsi == syscall number
|
||||
* rdx, rcx, r8, r9, (stack), (stack) == syscall arguments
|
||||
* and return the result in rax
|
||||
* and the syscall instruction needs
|
||||
* rax == syscall number
|
||||
* rdi, rsi, rdx, r10, r8, r9 == syscall arguments
|
||||
* and returns the result in rax
|
||||
* Shuffle everything around appropriately.
|
||||
* Note that syscall will trash rcx and r11.
|
||||
*/
|
||||
mov %rsi, %rax /* syscall number */
|
||||
mov %rdi, %rbp /* signal_pending pointer */
|
||||
/* and the syscall arguments */
|
||||
mov %rdx, %rdi
|
||||
mov %rcx, %rsi
|
||||
mov %r8, %rdx
|
||||
mov %r9, %r10
|
||||
mov 16(%rsp), %r8
|
||||
mov 24(%rsp), %r9
|
||||
|
||||
/* This next sequence of code works in conjunction with the
|
||||
* rewind_if_safe_syscall_function(). If a signal is taken
|
||||
* and the interrupted PC is anywhere between 'safe_syscall_start'
|
||||
* and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
|
||||
* The code sequence must therefore be able to cope with this, and
|
||||
* the syscall instruction must be the final one in the sequence.
|
||||
*/
|
||||
safe_syscall_start:
|
||||
/* if signal_pending is non-zero, don't do the call */
|
||||
cmpl $0, (%rbp)
|
||||
jnz 1f
|
||||
syscall
|
||||
safe_syscall_end:
|
||||
/* code path for having successfully executed the syscall */
|
||||
pop %rbp
|
||||
.cfi_remember_state
|
||||
.cfi_def_cfa_offset 8
|
||||
.cfi_restore rbp
|
||||
ret
|
||||
|
||||
1:
|
||||
/* code path when we didn't execute the syscall */
|
||||
.cfi_restore_state
|
||||
mov $-TARGET_ERESTARTSYS, %rax
|
||||
pop %rbp
|
||||
.cfi_def_cfa_offset 8
|
||||
.cfi_restore rbp
|
||||
ret
|
||||
.cfi_endproc
|
||||
|
||||
.size safe_syscall_base, .-safe_syscall_base
|
|
@ -133,8 +133,8 @@ void cpu_loop(CPUHPPAState *env)
|
|||
env->iaoq_f = env->gr[31];
|
||||
env->iaoq_b = env->gr[31] + 4;
|
||||
break;
|
||||
case -TARGET_ERESTARTSYS:
|
||||
case -TARGET_QEMU_ESIGRETURN:
|
||||
case -QEMU_ERESTARTSYS:
|
||||
case -QEMU_ESIGRETURN:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -191,9 +191,9 @@ long do_rt_sigreturn(CPUArchState *env)
|
|||
target_restore_altstack(&frame->uc.tuc_stack, env);
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
}
|
||||
|
|
|
@ -180,8 +180,8 @@ static void emulate_vsyscall(CPUX86State *env)
|
|||
ret = do_syscall(env, syscall, env->regs[R_EDI], env->regs[R_ESI],
|
||||
env->regs[R_EDX], env->regs[10], env->regs[8],
|
||||
env->regs[9], 0, 0);
|
||||
g_assert(ret != -TARGET_ERESTARTSYS);
|
||||
g_assert(ret != -TARGET_QEMU_ESIGRETURN);
|
||||
g_assert(ret != -QEMU_ERESTARTSYS);
|
||||
g_assert(ret != -QEMU_ESIGRETURN);
|
||||
if (ret == -TARGET_EFAULT) {
|
||||
goto sigsegv;
|
||||
}
|
||||
|
@ -223,9 +223,9 @@ void cpu_loop(CPUX86State *env)
|
|||
env->regs[R_EDI],
|
||||
env->regs[R_EBP],
|
||||
0, 0);
|
||||
if (ret == -TARGET_ERESTARTSYS) {
|
||||
if (ret == -QEMU_ERESTARTSYS) {
|
||||
env->eip -= 2;
|
||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
||||
} else if (ret != -QEMU_ESIGRETURN) {
|
||||
env->regs[R_EAX] = ret;
|
||||
}
|
||||
break;
|
||||
|
@ -241,9 +241,9 @@ void cpu_loop(CPUX86State *env)
|
|||
env->regs[8],
|
||||
env->regs[9],
|
||||
0, 0);
|
||||
if (ret == -TARGET_ERESTARTSYS) {
|
||||
if (ret == -QEMU_ERESTARTSYS) {
|
||||
env->eip -= 2;
|
||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
||||
} else if (ret != -QEMU_ESIGRETURN) {
|
||||
env->regs[R_EAX] = ret;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -559,12 +559,12 @@ long do_sigreturn(CPUX86State *env)
|
|||
if (restore_sigcontext(env, &frame->sc))
|
||||
goto badframe;
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -588,12 +588,12 @@ long do_rt_sigreturn(CPUX86State *env)
|
|||
target_restore_altstack(&frame->uc.tuc_stack, env);
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
#ifndef TARGET_X86_64
|
||||
|
|
|
@ -80,9 +80,9 @@ void cpu_loop(CPUM68KState *env)
|
|||
env->dregs[5],
|
||||
env->aregs[0],
|
||||
0, 0);
|
||||
if (ret == -TARGET_ERESTARTSYS) {
|
||||
if (ret == -QEMU_ERESTARTSYS) {
|
||||
env->pc -= 2;
|
||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
||||
} else if (ret != -QEMU_ESIGRETURN) {
|
||||
env->dregs[0] = ret;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -353,11 +353,11 @@ long do_sigreturn(CPUM68KState *env)
|
|||
restore_sigcontext(env, &frame->sc);
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
long do_rt_sigreturn(CPUM68KState *env)
|
||||
|
@ -381,12 +381,12 @@ long do_rt_sigreturn(CPUM68KState *env)
|
|||
target_restore_altstack(&frame->uc.tuc_stack, env);
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
void setup_sigtramp(abi_ulong sigtramp_page)
|
||||
|
|
|
@ -2,6 +2,11 @@ if not have_linux_user
|
|||
subdir_done()
|
||||
endif
|
||||
|
||||
linux_user_ss = ss.source_set()
|
||||
|
||||
common_user_inc += include_directories('host/' / host_arch)
|
||||
common_user_inc += include_directories('.')
|
||||
|
||||
linux_user_ss.add(files(
|
||||
'elfload.c',
|
||||
'exit.c',
|
||||
|
@ -9,10 +14,10 @@ linux_user_ss.add(files(
|
|||
'linuxload.c',
|
||||
'main.c',
|
||||
'mmap.c',
|
||||
'safe-syscall.S',
|
||||
'signal.c',
|
||||
'strace.c',
|
||||
'syscall.c',
|
||||
'thunk.c',
|
||||
'uaccess.c',
|
||||
'uname.c',
|
||||
))
|
||||
|
@ -39,3 +44,5 @@ subdir('sh4')
|
|||
subdir('sparc')
|
||||
subdir('x86_64')
|
||||
subdir('xtensa')
|
||||
|
||||
specific_ss.add_all(when: 'CONFIG_LINUX_USER', if_true: linux_user_ss)
|
||||
|
|
|
@ -53,10 +53,10 @@ void cpu_loop(CPUMBState *env)
|
|||
env->regs[9],
|
||||
env->regs[10],
|
||||
0, 0);
|
||||
if (ret == -TARGET_ERESTARTSYS) {
|
||||
if (ret == -QEMU_ERESTARTSYS) {
|
||||
/* Wind back to before the syscall. */
|
||||
env->pc -= 4;
|
||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
||||
} else if (ret != -QEMU_ESIGRETURN) {
|
||||
env->regs[3] = ret;
|
||||
}
|
||||
/* All syscall exits result in guest r14 being equal to the
|
||||
|
|
|
@ -207,12 +207,12 @@ long do_rt_sigreturn(CPUMBState *env)
|
|||
target_restore_altstack(&frame->uc.tuc_stack, env);
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
void setup_sigtramp(abi_ulong sigtramp_page)
|
||||
|
|
|
@ -141,11 +141,11 @@ done_syscall:
|
|||
env->active_tc.gpr[8], env->active_tc.gpr[9],
|
||||
env->active_tc.gpr[10], env->active_tc.gpr[11]);
|
||||
# endif /* O32 */
|
||||
if (ret == -TARGET_ERESTARTSYS) {
|
||||
if (ret == -QEMU_ERESTARTSYS) {
|
||||
env->active_tc.PC -= 4;
|
||||
break;
|
||||
}
|
||||
if (ret == -TARGET_QEMU_ESIGRETURN) {
|
||||
if (ret == -QEMU_ESIGRETURN) {
|
||||
/* Returning from a successful sigreturn syscall.
|
||||
Avoid clobbering register state. */
|
||||
break;
|
||||
|
|
|
@ -281,11 +281,11 @@ long do_sigreturn(CPUMIPSState *regs)
|
|||
/* I am not sure this is right, but it seems to work
|
||||
* maybe a problem with nested signals ? */
|
||||
regs->CP0_EPC = 0;
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
}
|
||||
# endif /* O32 */
|
||||
|
||||
|
@ -371,11 +371,11 @@ long do_rt_sigreturn(CPUMIPSState *env)
|
|||
/* I am not sure this is right, but it seems to work
|
||||
* maybe a problem with nested signals ? */
|
||||
env->CP0_EPC = 0;
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
void setup_sigtramp(abi_ulong sigtramp_page)
|
||||
|
|
|
@ -48,9 +48,9 @@ void cpu_loop(CPUOpenRISCState *env)
|
|||
cpu_get_gpr(env, 6),
|
||||
cpu_get_gpr(env, 7),
|
||||
cpu_get_gpr(env, 8), 0, 0);
|
||||
if (ret == -TARGET_ERESTARTSYS) {
|
||||
if (ret == -QEMU_ERESTARTSYS) {
|
||||
env->pc -= 4;
|
||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
||||
} else if (ret != -QEMU_ESIGRETURN) {
|
||||
cpu_set_gpr(env, 11, ret);
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -428,11 +428,11 @@ void cpu_loop(CPUPPCState *env)
|
|||
ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
|
||||
env->gpr[5], env->gpr[6], env->gpr[7],
|
||||
env->gpr[8], 0, 0);
|
||||
if (ret == -TARGET_ERESTARTSYS) {
|
||||
if (ret == -QEMU_ERESTARTSYS) {
|
||||
env->nip -= 4;
|
||||
break;
|
||||
}
|
||||
if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) {
|
||||
if (ret == (target_ulong)(-QEMU_ESIGRETURN)) {
|
||||
/* Returning from a successful sigreturn syscall.
|
||||
Avoid corrupting register state. */
|
||||
break;
|
||||
|
|
|
@ -591,13 +591,13 @@ long do_sigreturn(CPUPPCState *env)
|
|||
|
||||
unlock_user_struct(sr, sr_addr, 1);
|
||||
unlock_user_struct(sc, sc_addr, 1);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
|
||||
sigsegv:
|
||||
unlock_user_struct(sr, sr_addr, 1);
|
||||
unlock_user_struct(sc, sc_addr, 1);
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
}
|
||||
#endif /* !defined(TARGET_PPC64) */
|
||||
|
||||
|
@ -646,12 +646,12 @@ long do_rt_sigreturn(CPUPPCState *env)
|
|||
target_restore_altstack(&rt_sf->uc.tuc_stack, env);
|
||||
|
||||
unlock_user_struct(rt_sf, rt_sf_addr, 1);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
|
||||
sigsegv:
|
||||
unlock_user_struct(rt_sf, rt_sf_addr, 1);
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
/* This syscall implements {get,set,swap}context for userland. */
|
||||
|
@ -704,7 +704,7 @@ abi_long do_swapcontext(CPUArchState *env, abi_ulong uold_ctx,
|
|||
/* We cannot return to a partially updated context. */
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
}
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -69,9 +69,9 @@ void cpu_loop(CPURISCVState *env)
|
|||
env->gpr[xA5],
|
||||
0, 0);
|
||||
}
|
||||
if (ret == -TARGET_ERESTARTSYS) {
|
||||
if (ret == -QEMU_ERESTARTSYS) {
|
||||
env->pc -= 4;
|
||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
||||
} else if (ret != -QEMU_ESIGRETURN) {
|
||||
env->gpr[xA0] = ret;
|
||||
}
|
||||
if (cs->singlestep_enabled) {
|
||||
|
|
|
@ -188,7 +188,7 @@ long do_rt_sigreturn(CPURISCVState *env)
|
|||
target_restore_altstack(&frame->uc.uc_stack, env);
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
|
|
|
@ -83,9 +83,9 @@ void cpu_loop(CPUS390XState *env)
|
|||
ret = do_syscall(env, n, env->regs[2], env->regs[3],
|
||||
env->regs[4], env->regs[5],
|
||||
env->regs[6], env->regs[7], 0, 0);
|
||||
if (ret == -TARGET_ERESTARTSYS) {
|
||||
if (ret == -QEMU_ERESTARTSYS) {
|
||||
env->psw.addr -= env->int_svc_ilen;
|
||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
||||
} else if (ret != -QEMU_ESIGRETURN) {
|
||||
env->regs[2] = ret;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -359,7 +359,7 @@ long do_sigreturn(CPUS390XState *env)
|
|||
trace_user_do_sigreturn(env, frame_addr);
|
||||
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
/* Make sure that we're initializing all of target_set. */
|
||||
|
@ -373,7 +373,7 @@ long do_sigreturn(CPUS390XState *env)
|
|||
restore_sigregs_ext(env, &frame->sregs_ext);
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
long do_rt_sigreturn(CPUS390XState *env)
|
||||
|
@ -385,7 +385,7 @@ long do_rt_sigreturn(CPUS390XState *env)
|
|||
trace_user_do_rt_sigreturn(env, frame_addr);
|
||||
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
}
|
||||
target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
|
||||
|
||||
|
@ -397,7 +397,7 @@ long do_rt_sigreturn(CPUS390XState *env)
|
|||
target_restore_altstack(&frame->uc.tuc_stack, env);
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
void setup_sigtramp(abi_ulong sigtramp_page)
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
* safe-syscall.S : include the host-specific assembly fragment
|
||||
* to handle signals occurring at the same time as system calls.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "hostdep.h"
|
||||
#include "target_errno_defs.h"
|
||||
|
||||
/* We have the correct host directory on our include path
|
||||
* so that this will pull in the right fragment for the architecture.
|
||||
*/
|
||||
#ifdef HAVE_SAFE_SYSCALL
|
||||
#include "safe-syscall.inc.S"
|
||||
#endif
|
||||
|
||||
/* We must specifically say that we're happy for the stack to not be
|
||||
* executable, otherwise the toolchain will default to assuming our
|
||||
* assembly needs an executable stack and the whole QEMU binary will
|
||||
* needlessly end up with one. This should be the last thing in this file.
|
||||
*/
|
||||
#if defined(__linux__) && defined(__ELF__)
|
||||
.section .note.GNU-stack, "", %progbits
|
||||
#endif
|
|
@ -1,157 +0,0 @@
|
|||
/*
|
||||
* safe-syscall.h: prototypes for linux-user signal-race-safe syscalls
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LINUX_USER_SAFE_SYSCALL_H
|
||||
#define LINUX_USER_SAFE_SYSCALL_H
|
||||
|
||||
/**
|
||||
* safe_syscall:
|
||||
* @int number: number of system call to make
|
||||
* ...: arguments to the system call
|
||||
*
|
||||
* Call a system call if guest signal not pending.
|
||||
* This has the same API as the libc syscall() function, except that it
|
||||
* may return -1 with errno == TARGET_ERESTARTSYS if a signal was pending.
|
||||
*
|
||||
* Returns: the system call result, or -1 with an error code in errno
|
||||
* (Errnos are host errnos; we rely on TARGET_ERESTARTSYS not clashing
|
||||
* with any of the host errno values.)
|
||||
*/
|
||||
|
||||
/*
|
||||
* A guide to using safe_syscall() to handle interactions between guest
|
||||
* syscalls and guest signals:
|
||||
*
|
||||
* Guest syscalls come in two flavours:
|
||||
*
|
||||
* (1) Non-interruptible syscalls
|
||||
*
|
||||
* These are guest syscalls that never get interrupted by signals and
|
||||
* so never return EINTR. They can be implemented straightforwardly in
|
||||
* QEMU: just make sure that if the implementation code has to make any
|
||||
* blocking calls that those calls are retried if they return EINTR.
|
||||
* It's also OK to implement these with safe_syscall, though it will be
|
||||
* a little less efficient if a signal is delivered at the 'wrong' moment.
|
||||
*
|
||||
* Some non-interruptible syscalls need to be handled using block_signals()
|
||||
* to block signals for the duration of the syscall. This mainly applies
|
||||
* to code which needs to modify the data structures used by the
|
||||
* host_signal_handler() function and the functions it calls, including
|
||||
* all syscalls which change the thread's signal mask.
|
||||
*
|
||||
* (2) Interruptible syscalls
|
||||
*
|
||||
* These are guest syscalls that can be interrupted by signals and
|
||||
* for which we need to either return EINTR or arrange for the guest
|
||||
* syscall to be restarted. This category includes both syscalls which
|
||||
* always restart (and in the kernel return -ERESTARTNOINTR), ones
|
||||
* which only restart if there is no handler (kernel returns -ERESTARTNOHAND
|
||||
* or -ERESTART_RESTARTBLOCK), and the most common kind which restart
|
||||
* if the handler was registered with SA_RESTART (kernel returns
|
||||
* -ERESTARTSYS). System calls which are only interruptible in some
|
||||
* situations (like 'open') also need to be handled this way.
|
||||
*
|
||||
* Here it is important that the host syscall is made
|
||||
* via this safe_syscall() function, and *not* via the host libc.
|
||||
* If the host libc is used then the implementation will appear to work
|
||||
* most of the time, but there will be a race condition where a
|
||||
* signal could arrive just before we make the host syscall inside libc,
|
||||
* and then then guest syscall will not correctly be interrupted.
|
||||
* Instead the implementation of the guest syscall can use the safe_syscall
|
||||
* function but otherwise just return the result or errno in the usual
|
||||
* way; the main loop code will take care of restarting the syscall
|
||||
* if appropriate.
|
||||
*
|
||||
* (If the implementation needs to make multiple host syscalls this is
|
||||
* OK; any which might really block must be via safe_syscall(); for those
|
||||
* which are only technically blocking (ie which we know in practice won't
|
||||
* stay in the host kernel indefinitely) it's OK to use libc if necessary.
|
||||
* You must be able to cope with backing out correctly if some safe_syscall
|
||||
* you make in the implementation returns either -TARGET_ERESTARTSYS or
|
||||
* EINTR though.)
|
||||
*
|
||||
* block_signals() cannot be used for interruptible syscalls.
|
||||
*
|
||||
*
|
||||
* How and why the safe_syscall implementation works:
|
||||
*
|
||||
* The basic setup is that we make the host syscall via a known
|
||||
* section of host native assembly. If a signal occurs, our signal
|
||||
* handler checks the interrupted host PC against the addresse of that
|
||||
* known section. If the PC is before or at the address of the syscall
|
||||
* instruction then we change the PC to point at a "return
|
||||
* -TARGET_ERESTARTSYS" code path instead, and then exit the signal handler
|
||||
* (causing the safe_syscall() call to immediately return that value).
|
||||
* Then in the main.c loop if we see this magic return value we adjust
|
||||
* the guest PC to wind it back to before the system call, and invoke
|
||||
* the guest signal handler as usual.
|
||||
*
|
||||
* This winding-back will happen in two cases:
|
||||
* (1) signal came in just before we took the host syscall (a race);
|
||||
* in this case we'll take the guest signal and have another go
|
||||
* at the syscall afterwards, and this is indistinguishable for the
|
||||
* guest from the timing having been different such that the guest
|
||||
* signal really did win the race
|
||||
* (2) signal came in while the host syscall was blocking, and the
|
||||
* host kernel decided the syscall should be restarted;
|
||||
* in this case we want to restart the guest syscall also, and so
|
||||
* rewinding is the right thing. (Note that "restart" semantics mean
|
||||
* "first call the signal handler, then reattempt the syscall".)
|
||||
* The other situation to consider is when a signal came in while the
|
||||
* host syscall was blocking, and the host kernel decided that the syscall
|
||||
* should not be restarted; in this case QEMU's host signal handler will
|
||||
* be invoked with the PC pointing just after the syscall instruction,
|
||||
* with registers indicating an EINTR return; the special code in the
|
||||
* handler will not kick in, and we will return EINTR to the guest as
|
||||
* we should.
|
||||
*
|
||||
* Notice that we can leave the host kernel to make the decision for
|
||||
* us about whether to do a restart of the syscall or not; we do not
|
||||
* need to check SA_RESTART flags in QEMU or distinguish the various
|
||||
* kinds of restartability.
|
||||
*/
|
||||
#ifdef HAVE_SAFE_SYSCALL
|
||||
/* The core part of this function is implemented in assembly */
|
||||
extern long safe_syscall_base(int *pending, long number, ...);
|
||||
/* These are defined by the safe-syscall.inc.S file */
|
||||
extern char safe_syscall_start[];
|
||||
extern char safe_syscall_end[];
|
||||
|
||||
#define safe_syscall(...) \
|
||||
({ \
|
||||
long ret_; \
|
||||
int *psp_ = &((TaskState *)thread_cpu->opaque)->signal_pending; \
|
||||
ret_ = safe_syscall_base(psp_, __VA_ARGS__); \
|
||||
if (is_error(ret_)) { \
|
||||
errno = -ret_; \
|
||||
ret_ = -1; \
|
||||
} \
|
||||
ret_; \
|
||||
})
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* Fallback for architectures which don't yet provide a safe-syscall assembly
|
||||
* fragment; note that this is racy!
|
||||
* This should go away when all host architectures have been updated.
|
||||
*/
|
||||
#define safe_syscall syscall
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -50,9 +50,9 @@ void cpu_loop(CPUSH4State *env)
|
|||
env->gregs[0],
|
||||
env->gregs[1],
|
||||
0, 0);
|
||||
if (ret == -TARGET_ERESTARTSYS) {
|
||||
if (ret == -QEMU_ERESTARTSYS) {
|
||||
env->pc -= 2;
|
||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
||||
} else if (ret != -QEMU_ESIGRETURN) {
|
||||
env->gregs[0] = ret;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -286,12 +286,12 @@ long do_sigreturn(CPUSH4State *regs)
|
|||
restore_sigcontext(regs, &frame->sc);
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
long do_rt_sigreturn(CPUSH4State *regs)
|
||||
|
@ -313,12 +313,12 @@ long do_rt_sigreturn(CPUSH4State *regs)
|
|||
target_restore_altstack(&frame->uc.tuc_stack, regs);
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
void setup_sigtramp(abi_ulong sigtramp_page)
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#ifndef SIGNAL_COMMON_H
|
||||
#define SIGNAL_COMMON_H
|
||||
|
||||
#include "special-errno.h"
|
||||
|
||||
/* Fallback addresses into sigtramp page. */
|
||||
extern abi_ulong default_sigreturn;
|
||||
extern abi_ulong default_rt_sigreturn;
|
||||
|
@ -76,7 +78,7 @@ abi_long do_swapcontext(CPUArchState *env, abi_ulong uold_ctx,
|
|||
* Block all signals, and arrange that the signal mask is returned to
|
||||
* its correct value for the guest before we resume execution of guest code.
|
||||
* If this function returns non-zero, then the caller should immediately
|
||||
* return -TARGET_ERESTARTSYS to the main loop, which will take the pending
|
||||
* return -QEMU_ERESTARTSYS to the main loop, which will take the pending
|
||||
* signal and restart execution of the syscall.
|
||||
* If block_signals() returns zero, then the caller can continue with
|
||||
* emulation of the system call knowing that no signals can be taken
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#include "trace.h"
|
||||
#include "signal-common.h"
|
||||
#include "host-signal.h"
|
||||
#include "safe-syscall.h"
|
||||
#include "user/safe-syscall.h"
|
||||
|
||||
static struct target_sigaction sigact_table[TARGET_NSIG];
|
||||
|
||||
|
@ -213,7 +213,7 @@ int block_signals(void)
|
|||
|
||||
/* Wrapper for sigprocmask function
|
||||
* Emulates a sigprocmask in a safe way for the guest. Note that set and oldset
|
||||
* are host signal set, not guest ones. Returns -TARGET_ERESTARTSYS if
|
||||
* are host signal set, not guest ones. Returns -QEMU_ERESTARTSYS if
|
||||
* a signal was already pending and the syscall must be restarted, or
|
||||
* 0 on success.
|
||||
* If set is NULL, this is guaranteed not to fail.
|
||||
|
@ -230,7 +230,7 @@ int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
|
|||
int i;
|
||||
|
||||
if (block_signals()) {
|
||||
return -TARGET_ERESTARTSYS;
|
||||
return -QEMU_ERESTARTSYS;
|
||||
}
|
||||
|
||||
switch (how) {
|
||||
|
@ -798,7 +798,6 @@ int queue_signal(CPUArchState *env, int sig, int si_type,
|
|||
/* Adjust the signal context to rewind out of safe-syscall if we're in it */
|
||||
static inline void rewind_if_in_safe_syscall(void *puc)
|
||||
{
|
||||
#ifdef HAVE_SAFE_SYSCALL
|
||||
ucontext_t *uc = (ucontext_t *)puc;
|
||||
uintptr_t pcreg = host_signal_pc(uc);
|
||||
|
||||
|
@ -806,7 +805,6 @@ static inline void rewind_if_in_safe_syscall(void *puc)
|
|||
&& pcreg < (uintptr_t)safe_syscall_end) {
|
||||
host_signal_set_pc(uc, (uintptr_t)safe_syscall_start);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
|
||||
|
@ -987,7 +985,7 @@ int do_sigaction(int sig, const struct target_sigaction *act,
|
|||
}
|
||||
|
||||
if (block_signals()) {
|
||||
return -TARGET_ERESTARTSYS;
|
||||
return -QEMU_ERESTARTSYS;
|
||||
}
|
||||
|
||||
k = &sigact_table[sig - 1];
|
||||
|
|
|
@ -181,7 +181,7 @@ void cpu_loop (CPUSPARCState *env)
|
|||
env->regwptr[2], env->regwptr[3],
|
||||
env->regwptr[4], env->regwptr[5],
|
||||
0, 0);
|
||||
if (ret == -TARGET_ERESTARTSYS || ret == -TARGET_QEMU_ESIGRETURN) {
|
||||
if (ret == -QEMU_ERESTARTSYS || ret == -QEMU_ESIGRETURN) {
|
||||
break;
|
||||
}
|
||||
if ((abi_ulong)ret >= (abi_ulong)(-515)) {
|
||||
|
|
|
@ -431,12 +431,12 @@ long do_sigreturn(CPUSPARCState *env)
|
|||
set_sigmask(&host_set);
|
||||
|
||||
unlock_user_struct(sf, sf_addr, 0);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
|
||||
segv_and_exit:
|
||||
unlock_user_struct(sf, sf_addr, 0);
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
#else
|
||||
return -TARGET_ENOSYS;
|
||||
#endif
|
||||
|
@ -495,12 +495,12 @@ long do_rt_sigreturn(CPUSPARCState *env)
|
|||
env->npc = tnpc;
|
||||
|
||||
unlock_user_struct(sf, sf_addr, 0);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
|
||||
segv_and_exit:
|
||||
unlock_user_struct(sf, sf_addr, 0);
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
|
||||
|
|
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 "loader.h"
|
||||
#include "user-mmap.h"
|
||||
#include "safe-syscall.h"
|
||||
#include "user/safe-syscall.h"
|
||||
#include "qemu/guest-random.h"
|
||||
#include "qemu/selfmap.h"
|
||||
#include "user/syscall-trace.h"
|
||||
#include "special-errno.h"
|
||||
#include "qapi/error.h"
|
||||
#include "fd-trans.h"
|
||||
#include "tcg/tcg.h"
|
||||
|
@ -547,10 +548,10 @@ static inline abi_long get_errno(abi_long ret)
|
|||
|
||||
const char *target_strerror(int err)
|
||||
{
|
||||
if (err == TARGET_ERESTARTSYS) {
|
||||
if (err == QEMU_ERESTARTSYS) {
|
||||
return "To be restarted";
|
||||
}
|
||||
if (err == TARGET_QEMU_ESIGRETURN) {
|
||||
if (err == QEMU_ESIGRETURN) {
|
||||
return "Successful exit from sigreturn";
|
||||
}
|
||||
|
||||
|
@ -6458,7 +6459,7 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
|
|||
}
|
||||
|
||||
if (block_signals()) {
|
||||
return -TARGET_ERESTARTSYS;
|
||||
return -QEMU_ERESTARTSYS;
|
||||
}
|
||||
|
||||
fork_start();
|
||||
|
@ -8328,7 +8329,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
|
|||
Do thread termination if we have more then one thread. */
|
||||
|
||||
if (block_signals()) {
|
||||
return -TARGET_ERESTARTSYS;
|
||||
return -QEMU_ERESTARTSYS;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&clone_lock);
|
||||
|
@ -9317,7 +9318,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
|
|||
#endif
|
||||
ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
|
||||
SIGSET_T_SIZE));
|
||||
if (ret != -TARGET_ERESTARTSYS) {
|
||||
if (ret != -QEMU_ERESTARTSYS) {
|
||||
ts->in_sigsuspend = 1;
|
||||
}
|
||||
}
|
||||
|
@ -9336,7 +9337,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
|
|||
unlock_user(p, arg1, 0);
|
||||
ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
|
||||
SIGSET_T_SIZE));
|
||||
if (ret != -TARGET_ERESTARTSYS) {
|
||||
if (ret != -QEMU_ERESTARTSYS) {
|
||||
ts->in_sigsuspend = 1;
|
||||
}
|
||||
}
|
||||
|
@ -9452,13 +9453,13 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
|
|||
#ifdef TARGET_NR_sigreturn
|
||||
case TARGET_NR_sigreturn:
|
||||
if (block_signals()) {
|
||||
return -TARGET_ERESTARTSYS;
|
||||
return -QEMU_ERESTARTSYS;
|
||||
}
|
||||
return do_sigreturn(cpu_env);
|
||||
#endif
|
||||
case TARGET_NR_rt_sigreturn:
|
||||
if (block_signals()) {
|
||||
return -TARGET_ERESTARTSYS;
|
||||
return -QEMU_ERESTARTSYS;
|
||||
}
|
||||
return do_rt_sigreturn(cpu_env);
|
||||
case TARGET_NR_sethostname:
|
||||
|
@ -13145,7 +13146,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
|||
static bool flag;
|
||||
flag = !flag;
|
||||
if (flag) {
|
||||
return -TARGET_ERESTARTSYS;
|
||||
return -QEMU_ERESTARTSYS;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
481
linux-user/thunk.c
Normal file
481
linux-user/thunk.c
Normal file
|
@ -0,0 +1,481 @@
|
|||
/*
|
||||
* Generic thunking code to convert data between host and target CPU
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
|
||||
#include "qemu.h"
|
||||
#include "exec/user/thunk.h"
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
static unsigned int max_struct_entries;
|
||||
StructEntry *struct_entries;
|
||||
|
||||
static const argtype *thunk_type_next_ptr(const argtype *type_ptr);
|
||||
|
||||
static inline const argtype *thunk_type_next(const argtype *type_ptr)
|
||||
{
|
||||
int type;
|
||||
|
||||
type = *type_ptr++;
|
||||
switch(type) {
|
||||
case TYPE_CHAR:
|
||||
case TYPE_SHORT:
|
||||
case TYPE_INT:
|
||||
case TYPE_LONGLONG:
|
||||
case TYPE_ULONGLONG:
|
||||
case TYPE_LONG:
|
||||
case TYPE_ULONG:
|
||||
case TYPE_PTRVOID:
|
||||
case TYPE_OLDDEVT:
|
||||
return type_ptr;
|
||||
case TYPE_PTR:
|
||||
return thunk_type_next_ptr(type_ptr);
|
||||
case TYPE_ARRAY:
|
||||
return thunk_type_next_ptr(type_ptr + 1);
|
||||
case TYPE_STRUCT:
|
||||
return type_ptr + 1;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const argtype *thunk_type_next_ptr(const argtype *type_ptr)
|
||||
{
|
||||
return thunk_type_next(type_ptr);
|
||||
}
|
||||
|
||||
void thunk_register_struct(int id, const char *name, const argtype *types)
|
||||
{
|
||||
const argtype *type_ptr;
|
||||
StructEntry *se;
|
||||
int nb_fields, offset, max_align, align, size, i, j;
|
||||
|
||||
assert(id < max_struct_entries);
|
||||
|
||||
/* first we count the number of fields */
|
||||
type_ptr = types;
|
||||
nb_fields = 0;
|
||||
while (*type_ptr != TYPE_NULL) {
|
||||
type_ptr = thunk_type_next(type_ptr);
|
||||
nb_fields++;
|
||||
}
|
||||
assert(nb_fields > 0);
|
||||
se = struct_entries + id;
|
||||
se->field_types = types;
|
||||
se->nb_fields = nb_fields;
|
||||
se->name = name;
|
||||
#ifdef DEBUG
|
||||
printf("struct %s: id=%d nb_fields=%d\n",
|
||||
se->name, id, se->nb_fields);
|
||||
#endif
|
||||
/* now we can alloc the data */
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(se->field_offsets); i++) {
|
||||
offset = 0;
|
||||
max_align = 1;
|
||||
se->field_offsets[i] = g_new(int, nb_fields);
|
||||
type_ptr = se->field_types;
|
||||
for(j = 0;j < nb_fields; j++) {
|
||||
size = thunk_type_size(type_ptr, i);
|
||||
align = thunk_type_align(type_ptr, i);
|
||||
offset = (offset + align - 1) & ~(align - 1);
|
||||
se->field_offsets[i][j] = offset;
|
||||
offset += size;
|
||||
if (align > max_align)
|
||||
max_align = align;
|
||||
type_ptr = thunk_type_next(type_ptr);
|
||||
}
|
||||
offset = (offset + max_align - 1) & ~(max_align - 1);
|
||||
se->size[i] = offset;
|
||||
se->align[i] = max_align;
|
||||
#ifdef DEBUG
|
||||
printf("%s: size=%d align=%d\n",
|
||||
i == THUNK_HOST ? "host" : "target", offset, max_align);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void thunk_register_struct_direct(int id, const char *name,
|
||||
const StructEntry *se1)
|
||||
{
|
||||
StructEntry *se;
|
||||
|
||||
assert(id < max_struct_entries);
|
||||
se = struct_entries + id;
|
||||
*se = *se1;
|
||||
se->name = name;
|
||||
}
|
||||
|
||||
|
||||
/* now we can define the main conversion functions */
|
||||
const argtype *thunk_convert(void *dst, const void *src,
|
||||
const argtype *type_ptr, int to_host)
|
||||
{
|
||||
int type;
|
||||
|
||||
type = *type_ptr++;
|
||||
switch(type) {
|
||||
case TYPE_CHAR:
|
||||
*(uint8_t *)dst = *(uint8_t *)src;
|
||||
break;
|
||||
case TYPE_SHORT:
|
||||
*(uint16_t *)dst = tswap16(*(uint16_t *)src);
|
||||
break;
|
||||
case TYPE_INT:
|
||||
*(uint32_t *)dst = tswap32(*(uint32_t *)src);
|
||||
break;
|
||||
case TYPE_LONGLONG:
|
||||
case TYPE_ULONGLONG:
|
||||
*(uint64_t *)dst = tswap64(*(uint64_t *)src);
|
||||
break;
|
||||
#if HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 32
|
||||
case TYPE_LONG:
|
||||
case TYPE_ULONG:
|
||||
case TYPE_PTRVOID:
|
||||
*(uint32_t *)dst = tswap32(*(uint32_t *)src);
|
||||
break;
|
||||
#elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 32
|
||||
case TYPE_LONG:
|
||||
case TYPE_ULONG:
|
||||
case TYPE_PTRVOID:
|
||||
if (to_host) {
|
||||
if (type == TYPE_LONG) {
|
||||
/* sign extension */
|
||||
*(uint64_t *)dst = (int32_t)tswap32(*(uint32_t *)src);
|
||||
} else {
|
||||
*(uint64_t *)dst = tswap32(*(uint32_t *)src);
|
||||
}
|
||||
} else {
|
||||
*(uint32_t *)dst = tswap32(*(uint64_t *)src & 0xffffffff);
|
||||
}
|
||||
break;
|
||||
#elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 64
|
||||
case TYPE_LONG:
|
||||
case TYPE_ULONG:
|
||||
case TYPE_PTRVOID:
|
||||
*(uint64_t *)dst = tswap64(*(uint64_t *)src);
|
||||
break;
|
||||
#elif HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 64
|
||||
case TYPE_LONG:
|
||||
case TYPE_ULONG:
|
||||
case TYPE_PTRVOID:
|
||||
if (to_host) {
|
||||
*(uint32_t *)dst = tswap64(*(uint64_t *)src);
|
||||
} else {
|
||||
if (type == TYPE_LONG) {
|
||||
/* sign extension */
|
||||
*(uint64_t *)dst = tswap64(*(int32_t *)src);
|
||||
} else {
|
||||
*(uint64_t *)dst = tswap64(*(uint32_t *)src);
|
||||
}
|
||||
}
|
||||
break;
|
||||
#else
|
||||
#warning unsupported conversion
|
||||
#endif
|
||||
case TYPE_OLDDEVT:
|
||||
{
|
||||
uint64_t val = 0;
|
||||
switch (thunk_type_size(type_ptr - 1, !to_host)) {
|
||||
case 2:
|
||||
val = *(uint16_t *)src;
|
||||
break;
|
||||
case 4:
|
||||
val = *(uint32_t *)src;
|
||||
break;
|
||||
case 8:
|
||||
val = *(uint64_t *)src;
|
||||
break;
|
||||
}
|
||||
switch (thunk_type_size(type_ptr - 1, to_host)) {
|
||||
case 2:
|
||||
*(uint16_t *)dst = tswap16(val);
|
||||
break;
|
||||
case 4:
|
||||
*(uint32_t *)dst = tswap32(val);
|
||||
break;
|
||||
case 8:
|
||||
*(uint64_t *)dst = tswap64(val);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TYPE_ARRAY:
|
||||
{
|
||||
int array_length, i, dst_size, src_size;
|
||||
const uint8_t *s;
|
||||
uint8_t *d;
|
||||
|
||||
array_length = *type_ptr++;
|
||||
dst_size = thunk_type_size(type_ptr, to_host);
|
||||
src_size = thunk_type_size(type_ptr, 1 - to_host);
|
||||
d = dst;
|
||||
s = src;
|
||||
for(i = 0;i < array_length; i++) {
|
||||
thunk_convert(d, s, type_ptr, to_host);
|
||||
d += dst_size;
|
||||
s += src_size;
|
||||
}
|
||||
type_ptr = thunk_type_next(type_ptr);
|
||||
}
|
||||
break;
|
||||
case TYPE_STRUCT:
|
||||
{
|
||||
int i;
|
||||
const StructEntry *se;
|
||||
const uint8_t *s;
|
||||
uint8_t *d;
|
||||
const argtype *field_types;
|
||||
const int *dst_offsets, *src_offsets;
|
||||
|
||||
assert(*type_ptr < max_struct_entries);
|
||||
se = struct_entries + *type_ptr++;
|
||||
if (se->convert[0] != NULL) {
|
||||
/* specific conversion is needed */
|
||||
(*se->convert[to_host])(dst, src);
|
||||
} else {
|
||||
/* standard struct conversion */
|
||||
field_types = se->field_types;
|
||||
dst_offsets = se->field_offsets[to_host];
|
||||
src_offsets = se->field_offsets[1 - to_host];
|
||||
d = dst;
|
||||
s = src;
|
||||
for(i = 0;i < se->nb_fields; i++) {
|
||||
field_types = thunk_convert(d + dst_offsets[i],
|
||||
s + src_offsets[i],
|
||||
field_types, to_host);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Invalid type 0x%x\n", type);
|
||||
break;
|
||||
}
|
||||
return type_ptr;
|
||||
}
|
||||
|
||||
const argtype *thunk_print(void *arg, const argtype *type_ptr)
|
||||
{
|
||||
int type;
|
||||
|
||||
type = *type_ptr++;
|
||||
|
||||
switch (type) {
|
||||
case TYPE_CHAR:
|
||||
qemu_log("%c", *(uint8_t *)arg);
|
||||
break;
|
||||
case TYPE_SHORT:
|
||||
qemu_log("%" PRId16, tswap16(*(uint16_t *)arg));
|
||||
break;
|
||||
case TYPE_INT:
|
||||
qemu_log("%" PRId32, tswap32(*(uint32_t *)arg));
|
||||
break;
|
||||
case TYPE_LONGLONG:
|
||||
qemu_log("%" PRId64, tswap64(*(uint64_t *)arg));
|
||||
break;
|
||||
case TYPE_ULONGLONG:
|
||||
qemu_log("%" PRIu64, tswap64(*(uint64_t *)arg));
|
||||
break;
|
||||
#if HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 32
|
||||
case TYPE_PTRVOID:
|
||||
qemu_log("0x%" PRIx32, tswap32(*(uint32_t *)arg));
|
||||
break;
|
||||
case TYPE_LONG:
|
||||
qemu_log("%" PRId32, tswap32(*(uint32_t *)arg));
|
||||
break;
|
||||
case TYPE_ULONG:
|
||||
qemu_log("%" PRIu32, tswap32(*(uint32_t *)arg));
|
||||
break;
|
||||
#elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 32
|
||||
case TYPE_PTRVOID:
|
||||
qemu_log("0x%" PRIx32, tswap32(*(uint64_t *)arg & 0xffffffff));
|
||||
break;
|
||||
case TYPE_LONG:
|
||||
qemu_log("%" PRId32, tswap32(*(uint64_t *)arg & 0xffffffff));
|
||||
break;
|
||||
case TYPE_ULONG:
|
||||
qemu_log("%" PRIu32, tswap32(*(uint64_t *)arg & 0xffffffff));
|
||||
break;
|
||||
#elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 64
|
||||
case TYPE_PTRVOID:
|
||||
qemu_log("0x%" PRIx64, tswap64(*(uint64_t *)arg));
|
||||
break;
|
||||
case TYPE_LONG:
|
||||
qemu_log("%" PRId64, tswap64(*(uint64_t *)arg));
|
||||
break;
|
||||
case TYPE_ULONG:
|
||||
qemu_log("%" PRIu64, tswap64(*(uint64_t *)arg));
|
||||
break;
|
||||
#else
|
||||
case TYPE_PTRVOID:
|
||||
qemu_log("0x%" PRIx64, tswap64(*(uint64_t *)arg));
|
||||
break;
|
||||
case TYPE_LONG:
|
||||
qemu_log("%" PRId64, tswap64(*(uint64_t *)arg));
|
||||
break;
|
||||
case TYPE_ULONG:
|
||||
qemu_log("%" PRIu64, tswap64(*(uint64_t *)arg));
|
||||
break;
|
||||
#endif
|
||||
case TYPE_OLDDEVT:
|
||||
{
|
||||
uint64_t val = 0;
|
||||
switch (thunk_type_size(type_ptr - 1, 1)) {
|
||||
case 2:
|
||||
val = *(uint16_t *)arg;
|
||||
break;
|
||||
case 4:
|
||||
val = *(uint32_t *)arg;
|
||||
break;
|
||||
case 8:
|
||||
val = *(uint64_t *)arg;
|
||||
break;
|
||||
}
|
||||
switch (thunk_type_size(type_ptr - 1, 0)) {
|
||||
case 2:
|
||||
qemu_log("%" PRIu16, tswap16(val));
|
||||
break;
|
||||
case 4:
|
||||
qemu_log("%" PRIu32, tswap32(val));
|
||||
break;
|
||||
case 8:
|
||||
qemu_log("%" PRIu64, tswap64(val));
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TYPE_ARRAY:
|
||||
{
|
||||
int i, array_length, arg_size;
|
||||
uint8_t *a;
|
||||
int is_string = 0;
|
||||
|
||||
array_length = *type_ptr++;
|
||||
arg_size = thunk_type_size(type_ptr, 0);
|
||||
a = arg;
|
||||
|
||||
if (*type_ptr == TYPE_CHAR) {
|
||||
qemu_log("\"");
|
||||
is_string = 1;
|
||||
} else {
|
||||
qemu_log("[");
|
||||
}
|
||||
|
||||
for (i = 0; i < array_length; i++) {
|
||||
if (i > 0 && !is_string) {
|
||||
qemu_log(",");
|
||||
}
|
||||
thunk_print(a, type_ptr);
|
||||
a += arg_size;
|
||||
}
|
||||
|
||||
if (is_string) {
|
||||
qemu_log("\"");
|
||||
} else {
|
||||
qemu_log("]");
|
||||
}
|
||||
|
||||
type_ptr = thunk_type_next(type_ptr);
|
||||
}
|
||||
break;
|
||||
case TYPE_STRUCT:
|
||||
{
|
||||
int i;
|
||||
const StructEntry *se;
|
||||
uint8_t *a;
|
||||
const argtype *field_types;
|
||||
const int *arg_offsets;
|
||||
|
||||
se = struct_entries + *type_ptr++;
|
||||
|
||||
if (se->print != NULL) {
|
||||
se->print(arg);
|
||||
} else {
|
||||
a = arg;
|
||||
|
||||
field_types = se->field_types;
|
||||
arg_offsets = se->field_offsets[0];
|
||||
|
||||
qemu_log("{");
|
||||
for (i = 0; i < se->nb_fields; i++) {
|
||||
if (i > 0) {
|
||||
qemu_log(",");
|
||||
}
|
||||
field_types = thunk_print(a + arg_offsets[i], field_types);
|
||||
}
|
||||
qemu_log("}");
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
return type_ptr;
|
||||
}
|
||||
|
||||
/* from em86 */
|
||||
|
||||
/* Utility function: Table-driven functions to translate bitmasks
|
||||
* between host and target formats
|
||||
*/
|
||||
unsigned int target_to_host_bitmask(unsigned int target_mask,
|
||||
const bitmask_transtbl * trans_tbl)
|
||||
{
|
||||
const bitmask_transtbl *btp;
|
||||
unsigned int host_mask = 0;
|
||||
|
||||
for (btp = trans_tbl; btp->target_mask && btp->host_mask; btp++) {
|
||||
if ((target_mask & btp->target_mask) == btp->target_bits) {
|
||||
host_mask |= btp->host_bits;
|
||||
}
|
||||
}
|
||||
return host_mask;
|
||||
}
|
||||
|
||||
unsigned int host_to_target_bitmask(unsigned int host_mask,
|
||||
const bitmask_transtbl * trans_tbl)
|
||||
{
|
||||
const bitmask_transtbl *btp;
|
||||
unsigned int target_mask = 0;
|
||||
|
||||
for (btp = trans_tbl; btp->target_mask && btp->host_mask; btp++) {
|
||||
if ((host_mask & btp->host_mask) == btp->host_bits) {
|
||||
target_mask |= btp->target_bits;
|
||||
}
|
||||
}
|
||||
return target_mask;
|
||||
}
|
||||
|
||||
int thunk_type_size_array(const argtype *type_ptr, int is_host)
|
||||
{
|
||||
return thunk_type_size(type_ptr, is_host);
|
||||
}
|
||||
|
||||
int thunk_type_align_array(const argtype *type_ptr, int is_host)
|
||||
{
|
||||
return thunk_type_align(type_ptr, is_host);
|
||||
}
|
||||
|
||||
void thunk_init(unsigned int max_structs)
|
||||
{
|
||||
max_struct_entries = max_structs;
|
||||
struct_entries = g_new0(StructEntry, max_structs);
|
||||
}
|
|
@ -18,7 +18,6 @@
|
|||
#ifndef LINUX_USER_USER_INTERNALS_H
|
||||
#define LINUX_USER_USER_INTERNALS_H
|
||||
|
||||
#include "hostdep.h"
|
||||
#include "exec/user/thunk.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "qemu/log.h"
|
||||
|
|
|
@ -184,11 +184,11 @@ void cpu_loop(CPUXtensaState *env)
|
|||
env->regs[2] = ret;
|
||||
break;
|
||||
|
||||
case -TARGET_ERESTARTSYS:
|
||||
case -QEMU_ERESTARTSYS:
|
||||
env->pc -= 3;
|
||||
break;
|
||||
|
||||
case -TARGET_QEMU_ESIGRETURN:
|
||||
case -QEMU_ESIGRETURN:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -263,12 +263,12 @@ long do_rt_sigreturn(CPUXtensaState *env)
|
|||
target_restore_altstack(&frame->uc.tuc_stack, env);
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
return -QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
void setup_sigtramp(abi_ulong sigtramp_page)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue