mirror of https://github.com/xemu-project/xemu.git
linux-user pull request v2 for may 2016
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIVAwUAV0g0rrRIkN7ePJvAAQh+hA//TZOrmRskN7/PzlGp90pkNVL4Xm6LDNsj fvgzB4ceuA+eRv426ttSpYgZestZjxmb/29c5UJWvH0Otnhrxj0aNKimxAO4FCIV u2u73Mn4cTGZPfoMJesCYihC19LIFIpYFPjXTKz2UJ4Dg/ZLBd6KORDTC7kfXoSx 9wTgaHZkbrUBCwWQ+0SKrbibPJWY4RHUkYCK4dxCCPFRVpGhYFt1vihjZpzDzzNH njjxr/GB8W1OByBI90TWUpx6e0YRqhKluuvr1ObezrK2/nCZhLwOkvgIB1yuew3e AwFz5wUFtx80FV3ThAKDoJadz6tVKPG67OG2w5DmgUrK6gpOTP9n1LcypTK+wti4 /LNb9AhyEqsDD/apFQWNEEdYwCG6qjlaE01zp6ZQPgNUWpN1BSEDmikoHwpUqLaq fXfgJZyOItp6LP3Tajkto2h9iAdXI6eoJHQtMK562J89WZz1Bb4IJxONAkWZq5oV aQCOj0wD/vObUhMU72jLy2cd3kHM/RT5NliMhb+nbR9JY/WXbTeOn41hOhEnkJJJ bjRPCN2O3ULfi3yn3St2ByCngPUG954uqmR2OaOGwEHGx6E/UEkWsduUlRwwY1zK 96pZvsHO8DSIDc5gNmUlvQlBc62v8b+KUcwsbloBCl2YGt9mbZNM9zi0Gg4R97MJ jHkpVjF4L4I= =/Nln -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/riku/tags/pull-linux-user-20160527' into staging linux-user pull request v2 for may 2016 # gpg: Signature made Fri 27 May 2016 12:51:10 BST using RSA key ID DE3C9BC0 # gpg: Good signature from "Riku Voipio <riku.voipio@iki.fi>" # gpg: aka "Riku Voipio <riku.voipio@linaro.org>" * remotes/riku/tags/pull-linux-user-20160527: (38 commits) linux-user,target-ppc: fix use of MSR_LE linux-user/signal.c: Use s390 target space address instead of host space linux-user/signal.c: Use target address instead of host address for microblaze restorer linux-user/signal.c: Generate opcode data for restorer in setup_rt_frame linux-user: arm: Remove ARM_cpsr and similar #defines linux-user: Use direct syscalls for setuid(), etc linux-user: x86_64: Don't use 16-bit UIDs linux-user: Use g_try_malloc() in do_msgrcv() linux-user: Handle msgrcv error case correctly linux-user: Handle negative values in timespec conversion linux-user: Use safe_syscall for futex syscall linux-user: Use safe_syscall for pselect, select syscalls linux-user: Use safe_syscall for execve syscall linux-user: Use safe_syscall for wait system calls linux-user: Use safe_syscall for open and openat system calls linux-user: Use safe_syscall for read and write system calls linux-user: Provide safe_syscall for fixing races between signals and syscalls linux-user: Add debug code to exercise restarting system calls linux-user: Support for restarting system calls for Microblaze targets linux-user: Set r14 on exit from microblaze syscall ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
d6550e9ed2
|
@ -108,7 +108,12 @@ obj-$(CONFIG_LIBDECNUMBER) += libdecnumber/dpd/decimal128.o
|
|||
|
||||
ifdef CONFIG_LINUX_USER
|
||||
|
||||
QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) -I$(SRC_PATH)/linux-user
|
||||
# Note that we only add linux-user/host/$ARCH if it exists, and
|
||||
# that it must come before linux-user/host/generic in the search path.
|
||||
QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) \
|
||||
$(patsubst %,-I%,$(wildcard $(SRC_PATH)/linux-user/host/$(ARCH))) \
|
||||
-I$(SRC_PATH)/linux-user/host/generic \
|
||||
-I$(SRC_PATH)/linux-user
|
||||
|
||||
obj-y += linux-user/
|
||||
obj-y += gdbstub.o thunk.o user-exec.o
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
obj-y = main.o syscall.o strace.o mmap.o signal.o \
|
||||
elfload.o linuxload.o uaccess.o uname.o
|
||||
elfload.o linuxload.o uaccess.o uname.o \
|
||||
safe-syscall.o
|
||||
|
||||
obj-$(TARGET_HAS_BFLT) += flatload.o
|
||||
obj-$(TARGET_I386) += vm86.o
|
||||
|
|
|
@ -27,6 +27,7 @@ static inline abi_ulong get_sp_from_cpustate(CPUAlphaState *state)
|
|||
return state->ir[IR_SP];
|
||||
}
|
||||
|
||||
|
||||
/* From <asm/gentrap.h>. */
|
||||
#define TARGET_GEN_INTOVF -1 /* integer overflow */
|
||||
#define TARGET_GEN_INTDIV -2 /* integer division by zero */
|
||||
|
|
|
@ -26,4 +26,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUARMState *state)
|
|||
return state->regs[13];
|
||||
}
|
||||
|
||||
|
||||
#endif /* TARGET_SIGNAL_H */
|
||||
|
|
|
@ -4,29 +4,11 @@
|
|||
/* this struct defines the way the registers are stored on the
|
||||
stack during a system call. */
|
||||
|
||||
/* uregs[0..15] are r0 to r15; uregs[16] is CPSR; uregs[17] is ORIG_r0 */
|
||||
struct target_pt_regs {
|
||||
abi_long uregs[18];
|
||||
};
|
||||
|
||||
#define ARM_cpsr uregs[16]
|
||||
#define ARM_pc uregs[15]
|
||||
#define ARM_lr uregs[14]
|
||||
#define ARM_sp uregs[13]
|
||||
#define ARM_ip uregs[12]
|
||||
#define ARM_fp uregs[11]
|
||||
#define ARM_r10 uregs[10]
|
||||
#define ARM_r9 uregs[9]
|
||||
#define ARM_r8 uregs[8]
|
||||
#define ARM_r7 uregs[7]
|
||||
#define ARM_r6 uregs[6]
|
||||
#define ARM_r5 uregs[5]
|
||||
#define ARM_r4 uregs[4]
|
||||
#define ARM_r3 uregs[3]
|
||||
#define ARM_r2 uregs[2]
|
||||
#define ARM_r1 uregs[1]
|
||||
#define ARM_r0 uregs[0]
|
||||
#define ARM_ORIG_r0 uregs[17]
|
||||
|
||||
#define ARM_SYSCALL_BASE 0x900000
|
||||
#define ARM_THUMB_SYSCALL 0
|
||||
|
||||
|
|
|
@ -26,4 +26,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUCRISState *state)
|
|||
return state->regs[14];
|
||||
}
|
||||
|
||||
|
||||
#endif /* TARGET_SIGNAL_H */
|
||||
|
|
|
@ -274,19 +274,20 @@ static inline void init_thread(struct target_pt_regs *regs,
|
|||
abi_long stack = infop->start_stack;
|
||||
memset(regs, 0, sizeof(*regs));
|
||||
|
||||
regs->ARM_cpsr = 0x10;
|
||||
if (infop->entry & 1)
|
||||
regs->ARM_cpsr |= CPSR_T;
|
||||
regs->ARM_pc = infop->entry & 0xfffffffe;
|
||||
regs->ARM_sp = infop->start_stack;
|
||||
regs->uregs[16] = ARM_CPU_MODE_USR;
|
||||
if (infop->entry & 1) {
|
||||
regs->uregs[16] |= CPSR_T;
|
||||
}
|
||||
regs->uregs[15] = infop->entry & 0xfffffffe;
|
||||
regs->uregs[13] = infop->start_stack;
|
||||
/* FIXME - what to for failure of get_user()? */
|
||||
get_user_ual(regs->ARM_r2, stack + 8); /* envp */
|
||||
get_user_ual(regs->ARM_r1, stack + 4); /* envp */
|
||||
get_user_ual(regs->uregs[2], stack + 8); /* envp */
|
||||
get_user_ual(regs->uregs[1], stack + 4); /* envp */
|
||||
/* XXX: it seems that r0 is zeroed after ! */
|
||||
regs->ARM_r0 = 0;
|
||||
regs->uregs[0] = 0;
|
||||
/* For uClinux PIC binaries. */
|
||||
/* XXX: Linux does this only on ARM with no MMU (do we care ?) */
|
||||
regs->ARM_r10 = infop->start_data;
|
||||
regs->uregs[10] = infop->start_data;
|
||||
}
|
||||
|
||||
#define ELF_NREG 18
|
||||
|
|
|
@ -139,3 +139,20 @@
|
|||
/* for robust mutexes */
|
||||
#define TARGET_EOWNERDEAD 130 /* Owner died */
|
||||
#define TARGET_ENOTRECOVERABLE 131 /* State not recoverable */
|
||||
|
||||
/* 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 */
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* hostdep.h : fallback generic version of header for 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 QEMU_HOSTDEP_H
|
||||
#define QEMU_HOSTDEP_H
|
||||
|
||||
/* This is the fallback header which is only used if the host
|
||||
* architecture doesn't provide one in linux-user/host/$ARCH.
|
||||
*/
|
||||
|
||||
#endif
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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 QEMU_HOSTDEP_H
|
||||
#define QEMU_HOSTDEP_H
|
||||
|
||||
/* We have a safe-syscall.inc.S */
|
||||
#define HAVE_SAFE_SYSCALL
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
/* These are defined by the safe-syscall.inc.S file */
|
||||
extern char safe_syscall_start[];
|
||||
extern char safe_syscall_end[];
|
||||
|
||||
/* 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)
|
||||
{
|
||||
struct ucontext *uc = puc;
|
||||
greg_t *pcreg = &uc->uc_mcontext.gregs[REG_RIP];
|
||||
|
||||
if (*pcreg > (uintptr_t)safe_syscall_start
|
||||
&& *pcreg < (uintptr_t)safe_syscall_end) {
|
||||
*pcreg = (uintptr_t)safe_syscall_start;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
|
||||
#endif
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* 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:
|
||||
/* 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
|
||||
|
||||
/* 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 */
|
||||
testl $1, (%rbp)
|
||||
jnz return_ERESTARTSYS
|
||||
syscall
|
||||
safe_syscall_end:
|
||||
/* code path for having successfully executed the syscall */
|
||||
pop %rbp
|
||||
ret
|
||||
|
||||
return_ERESTARTSYS:
|
||||
/* code path when we didn't execute the syscall */
|
||||
mov $-TARGET_ERESTARTSYS, %rax
|
||||
pop %rbp
|
||||
ret
|
||||
|
||||
.size safe_syscall_base, .-safe_syscall_base
|
|
@ -26,4 +26,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUM68KState *state)
|
|||
return state->aregs[7];
|
||||
}
|
||||
|
||||
|
||||
#endif /* TARGET_SIGNAL_H */
|
||||
|
|
|
@ -285,6 +285,7 @@ void cpu_loop(CPUX86State *env)
|
|||
CPUState *cs = CPU(x86_env_get_cpu(env));
|
||||
int trapnr;
|
||||
abi_ulong pc;
|
||||
abi_ulong ret;
|
||||
target_siginfo_t info;
|
||||
|
||||
for(;;) {
|
||||
|
@ -294,7 +295,7 @@ void cpu_loop(CPUX86State *env)
|
|||
switch(trapnr) {
|
||||
case 0x80:
|
||||
/* linux syscall from int $0x80 */
|
||||
env->regs[R_EAX] = do_syscall(env,
|
||||
ret = do_syscall(env,
|
||||
env->regs[R_EAX],
|
||||
env->regs[R_EBX],
|
||||
env->regs[R_ECX],
|
||||
|
@ -303,11 +304,16 @@ void cpu_loop(CPUX86State *env)
|
|||
env->regs[R_EDI],
|
||||
env->regs[R_EBP],
|
||||
0, 0);
|
||||
if (ret == -TARGET_ERESTARTSYS) {
|
||||
env->eip -= 2;
|
||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
||||
env->regs[R_EAX] = ret;
|
||||
}
|
||||
break;
|
||||
#ifndef TARGET_ABI32
|
||||
case EXCP_SYSCALL:
|
||||
/* linux syscall from syscall instruction */
|
||||
env->regs[R_EAX] = do_syscall(env,
|
||||
ret = do_syscall(env,
|
||||
env->regs[R_EAX],
|
||||
env->regs[R_EDI],
|
||||
env->regs[R_ESI],
|
||||
|
@ -316,6 +322,11 @@ void cpu_loop(CPUX86State *env)
|
|||
env->regs[8],
|
||||
env->regs[9],
|
||||
0, 0);
|
||||
if (ret == -TARGET_ERESTARTSYS) {
|
||||
env->eip -= 2;
|
||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
||||
env->regs[R_EAX] = ret;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case EXCP0B_NOSEG:
|
||||
|
@ -716,6 +727,7 @@ void cpu_loop(CPUARMState *env)
|
|||
unsigned int n, insn;
|
||||
target_siginfo_t info;
|
||||
uint32_t addr;
|
||||
abi_ulong ret;
|
||||
|
||||
for(;;) {
|
||||
cpu_exec_start(cs);
|
||||
|
@ -854,7 +866,7 @@ void cpu_loop(CPUARMState *env)
|
|||
break;
|
||||
}
|
||||
} else {
|
||||
env->regs[0] = do_syscall(env,
|
||||
ret = do_syscall(env,
|
||||
n,
|
||||
env->regs[0],
|
||||
env->regs[1],
|
||||
|
@ -863,6 +875,11 @@ void cpu_loop(CPUARMState *env)
|
|||
env->regs[4],
|
||||
env->regs[5],
|
||||
0, 0);
|
||||
if (ret == -TARGET_ERESTARTSYS) {
|
||||
env->regs[15] -= env->thumb ? 2 : 4;
|
||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
||||
env->regs[0] = ret;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
goto error;
|
||||
|
@ -1045,6 +1062,7 @@ void cpu_loop(CPUARMState *env)
|
|||
{
|
||||
CPUState *cs = CPU(arm_env_get_cpu(env));
|
||||
int trapnr, sig;
|
||||
abi_long ret;
|
||||
target_siginfo_t info;
|
||||
|
||||
for (;;) {
|
||||
|
@ -1054,7 +1072,7 @@ void cpu_loop(CPUARMState *env)
|
|||
|
||||
switch (trapnr) {
|
||||
case EXCP_SWI:
|
||||
env->xregs[0] = do_syscall(env,
|
||||
ret = do_syscall(env,
|
||||
env->xregs[8],
|
||||
env->xregs[0],
|
||||
env->xregs[1],
|
||||
|
@ -1063,6 +1081,11 @@ void cpu_loop(CPUARMState *env)
|
|||
env->xregs[4],
|
||||
env->xregs[5],
|
||||
0, 0);
|
||||
if (ret == -TARGET_ERESTARTSYS) {
|
||||
env->pc -= 4;
|
||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
||||
env->xregs[0] = ret;
|
||||
}
|
||||
break;
|
||||
case EXCP_INTERRUPT:
|
||||
/* just indicate that signals should be handled asap */
|
||||
|
@ -1148,7 +1171,7 @@ void cpu_loop(CPUUniCore32State *env)
|
|||
cpu_set_tls(env, env->regs[0]);
|
||||
env->regs[0] = 0;
|
||||
} else {
|
||||
env->regs[0] = do_syscall(env,
|
||||
abi_long ret = do_syscall(env,
|
||||
n,
|
||||
env->regs[0],
|
||||
env->regs[1],
|
||||
|
@ -1157,6 +1180,11 @@ void cpu_loop(CPUUniCore32State *env)
|
|||
env->regs[4],
|
||||
env->regs[5],
|
||||
0, 0);
|
||||
if (ret == -TARGET_ERESTARTSYS) {
|
||||
env->regs[31] -= 4;
|
||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
||||
env->regs[0] = ret;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
goto error;
|
||||
|
@ -1353,6 +1381,9 @@ 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) {
|
||||
break;
|
||||
}
|
||||
if ((abi_ulong)ret >= (abi_ulong)(-515)) {
|
||||
#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
|
||||
env->xcc |= PSR_CARRY;
|
||||
|
@ -1964,6 +1995,10 @@ 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) {
|
||||
env->nip -= 4;
|
||||
break;
|
||||
}
|
||||
if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) {
|
||||
/* Returning from a successful sigreturn syscall.
|
||||
Avoid corrupting register state. */
|
||||
|
@ -2505,6 +2540,10 @@ 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) {
|
||||
env->active_tc.PC -= 4;
|
||||
break;
|
||||
}
|
||||
if (ret == -TARGET_QEMU_ESIGRETURN) {
|
||||
/* Returning from a successful sigreturn syscall.
|
||||
Avoid clobbering register state. */
|
||||
|
@ -2685,6 +2724,7 @@ void cpu_loop(CPUOpenRISCState *env)
|
|||
{
|
||||
CPUState *cs = CPU(openrisc_env_get_cpu(env));
|
||||
int trapnr, gdbsig;
|
||||
abi_long ret;
|
||||
|
||||
for (;;) {
|
||||
cpu_exec_start(cs);
|
||||
|
@ -2730,7 +2770,7 @@ void cpu_loop(CPUOpenRISCState *env)
|
|||
break;
|
||||
case EXCP_SYSCALL:
|
||||
env->pc += 4; /* 0xc00; */
|
||||
env->gpr[11] = do_syscall(env,
|
||||
ret = do_syscall(env,
|
||||
env->gpr[11], /* return value */
|
||||
env->gpr[3], /* r3 - r7 are params */
|
||||
env->gpr[4],
|
||||
|
@ -2738,6 +2778,11 @@ void cpu_loop(CPUOpenRISCState *env)
|
|||
env->gpr[6],
|
||||
env->gpr[7],
|
||||
env->gpr[8], 0, 0);
|
||||
if (ret == -TARGET_ERESTARTSYS) {
|
||||
env->pc -= 4;
|
||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
||||
env->gpr[11] = ret;
|
||||
}
|
||||
break;
|
||||
case EXCP_FPE:
|
||||
qemu_log_mask(CPU_LOG_INT, "\nFloating point error\n");
|
||||
|
@ -2792,7 +2837,11 @@ void cpu_loop(CPUSH4State *env)
|
|||
env->gregs[0],
|
||||
env->gregs[1],
|
||||
0, 0);
|
||||
if (ret == -TARGET_ERESTARTSYS) {
|
||||
env->pc -= 2;
|
||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
||||
env->gregs[0] = ret;
|
||||
}
|
||||
break;
|
||||
case EXCP_INTERRUPT:
|
||||
/* just indicate that signals should be handled asap */
|
||||
|
@ -2865,7 +2914,11 @@ void cpu_loop(CPUCRISState *env)
|
|||
env->pregs[7],
|
||||
env->pregs[11],
|
||||
0, 0);
|
||||
if (ret == -TARGET_ERESTARTSYS) {
|
||||
env->pc -= 2;
|
||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
||||
env->regs[10] = ret;
|
||||
}
|
||||
break;
|
||||
case EXCP_DEBUG:
|
||||
{
|
||||
|
@ -2929,7 +2982,19 @@ void cpu_loop(CPUMBState *env)
|
|||
env->regs[9],
|
||||
env->regs[10],
|
||||
0, 0);
|
||||
if (ret == -TARGET_ERESTARTSYS) {
|
||||
/* Wind back to before the syscall. */
|
||||
env->sregs[SR_PC] -= 4;
|
||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
||||
env->regs[3] = ret;
|
||||
}
|
||||
/* All syscall exits result in guest r14 being equal to the
|
||||
* PC we return to, because the kernel syscall exit "rtbd" does
|
||||
* this. (This is true even for sigreturn(); note that r14 is
|
||||
* not a userspace-usable register, as the kernel may clobber it
|
||||
* at any point.)
|
||||
*/
|
||||
env->regs[14] = env->sregs[SR_PC];
|
||||
break;
|
||||
case EXCP_HW_EXCP:
|
||||
env->regs[17] = env->sregs[SR_PC] + 4;
|
||||
|
@ -3037,10 +3102,11 @@ void cpu_loop(CPUM68KState *env)
|
|||
break;
|
||||
case EXCP_TRAP0:
|
||||
{
|
||||
abi_long ret;
|
||||
ts->sim_syscalls = 0;
|
||||
n = env->dregs[0];
|
||||
env->pc += 2;
|
||||
env->dregs[0] = do_syscall(env,
|
||||
ret = do_syscall(env,
|
||||
n,
|
||||
env->dregs[1],
|
||||
env->dregs[2],
|
||||
|
@ -3049,6 +3115,11 @@ void cpu_loop(CPUM68KState *env)
|
|||
env->dregs[5],
|
||||
env->aregs[0],
|
||||
0, 0);
|
||||
if (ret == -TARGET_ERESTARTSYS) {
|
||||
env->pc -= 2;
|
||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
||||
env->dregs[0] = ret;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EXCP_INTERRUPT:
|
||||
|
@ -3229,8 +3300,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 (trapnr == TARGET_NR_sigreturn
|
||||
|| trapnr == TARGET_NR_rt_sigreturn) {
|
||||
if (sysret == -TARGET_ERESTARTSYS) {
|
||||
env->pc -= 4;
|
||||
break;
|
||||
}
|
||||
if (sysret == -TARGET_QEMU_ESIGRETURN) {
|
||||
break;
|
||||
}
|
||||
/* Syscall writes 0 to V0 to bypass error check, similar
|
||||
|
@ -3327,6 +3401,7 @@ void cpu_loop(CPUS390XState *env)
|
|||
int trapnr, n, sig;
|
||||
target_siginfo_t info;
|
||||
target_ulong addr;
|
||||
abi_long ret;
|
||||
|
||||
while (1) {
|
||||
cpu_exec_start(cs);
|
||||
|
@ -3344,9 +3419,14 @@ void cpu_loop(CPUS390XState *env)
|
|||
n = env->regs[1];
|
||||
}
|
||||
env->psw.addr += env->int_svc_ilen;
|
||||
env->regs[2] = 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[6], env->regs[7], 0, 0);
|
||||
if (ret == -TARGET_ERESTARTSYS) {
|
||||
env->psw.addr -= env->int_svc_ilen;
|
||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
||||
env->regs[2] = ret;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXCP_DEBUG:
|
||||
|
@ -3638,15 +3718,20 @@ void cpu_loop(CPUTLGState *env)
|
|||
cpu_exec_end(cs);
|
||||
switch (trapnr) {
|
||||
case TILEGX_EXCP_SYSCALL:
|
||||
env->regs[TILEGX_R_RE] = do_syscall(env, env->regs[TILEGX_R_NR],
|
||||
{
|
||||
abi_ulong ret = do_syscall(env, env->regs[TILEGX_R_NR],
|
||||
env->regs[0], env->regs[1],
|
||||
env->regs[2], env->regs[3],
|
||||
env->regs[4], env->regs[5],
|
||||
env->regs[6], env->regs[7]);
|
||||
env->regs[TILEGX_R_ERR] = TILEGX_IS_ERRNO(env->regs[TILEGX_R_RE])
|
||||
? - env->regs[TILEGX_R_RE]
|
||||
: 0;
|
||||
if (ret == -TARGET_ERESTARTSYS) {
|
||||
env->pc -= 8;
|
||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
||||
env->regs[TILEGX_R_RE] = ret;
|
||||
env->regs[TILEGX_R_ERR] = TILEGX_IS_ERRNO(ret) ? -ret : 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TILEGX_EXCP_OPCODE_EXCH:
|
||||
do_exch(env, true, false);
|
||||
break;
|
||||
|
|
|
@ -26,4 +26,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUMBState *state)
|
|||
return state->regs[14];
|
||||
}
|
||||
|
||||
|
||||
#endif /* TARGET_SIGNAL_H */
|
||||
|
|
|
@ -26,4 +26,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state)
|
|||
return state->active_tc.gpr[29];
|
||||
}
|
||||
|
||||
|
||||
#endif /* TARGET_SIGNAL_H */
|
||||
|
|
|
@ -222,10 +222,6 @@ struct target_pt_regs {
|
|||
#define TARGET_ENOTRECOVERABLE 166 /* State not recoverable */
|
||||
|
||||
|
||||
|
||||
/* Nasty hack: define a fake errno value for use by sigreturn. */
|
||||
#define TARGET_QEMU_ESIGRETURN 255
|
||||
|
||||
#define UNAME_MACHINE "mips"
|
||||
#define UNAME_MINIMUM_RELEASE "2.6.32"
|
||||
|
||||
|
|
|
@ -26,4 +26,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state)
|
|||
return state->active_tc.gpr[29];
|
||||
}
|
||||
|
||||
|
||||
#endif /* TARGET_SIGNAL_H */
|
||||
|
|
|
@ -219,10 +219,6 @@ struct target_pt_regs {
|
|||
#define TARGET_ENOTRECOVERABLE 166 /* State not recoverable */
|
||||
|
||||
|
||||
|
||||
/* Nasty hack: define a fake errno value for use by sigreturn. */
|
||||
#define TARGET_QEMU_ESIGRETURN 255
|
||||
|
||||
#define UNAME_MACHINE "mips64"
|
||||
#define UNAME_MINIMUM_RELEASE "2.6.32"
|
||||
|
||||
|
|
|
@ -23,4 +23,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUOpenRISCState *state)
|
|||
return state->gpr[1];
|
||||
}
|
||||
|
||||
|
||||
#endif /* TARGET_SIGNAL_H */
|
||||
|
|
|
@ -26,4 +26,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUPPCState *state)
|
|||
return state->gpr[1];
|
||||
}
|
||||
|
||||
|
||||
#endif /* TARGET_SIGNAL_H */
|
||||
|
|
|
@ -53,8 +53,6 @@ struct target_revectored_struct {
|
|||
abi_ulong __map[8]; /* 256 bits */
|
||||
};
|
||||
|
||||
/* Nasty hack: define a fake errno value for use by sigreturn. */
|
||||
#define TARGET_QEMU_ESIGRETURN 255
|
||||
|
||||
/*
|
||||
* flags masks
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef QEMU_H
|
||||
#define QEMU_H
|
||||
|
||||
|
||||
#include "hostdep.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
|
@ -205,6 +205,131 @@ unsigned long init_guest_space(unsigned long host_start,
|
|||
|
||||
#include "qemu/log.h"
|
||||
|
||||
/* safe_syscall.S */
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* (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.)
|
||||
*
|
||||
*
|
||||
* 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, ...);
|
||||
|
||||
#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
|
||||
|
||||
/* syscall.c */
|
||||
int host_to_target_waitstatus(int status);
|
||||
|
||||
|
|
|
@ -23,4 +23,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUS390XState *state)
|
|||
return state->regs[15];
|
||||
}
|
||||
|
||||
|
||||
#endif /* TARGET_SIGNAL_H */
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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 "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
|
|
@ -26,4 +26,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUSH4State *state)
|
|||
return state->gregs[15];
|
||||
}
|
||||
|
||||
|
||||
#endif /* TARGET_SIGNAL_H */
|
||||
|
|
|
@ -561,6 +561,13 @@ int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info)
|
|||
}
|
||||
}
|
||||
|
||||
#ifndef HAVE_SAFE_SYSCALL
|
||||
static inline void rewind_if_in_safe_syscall(void *puc)
|
||||
{
|
||||
/* Default version: never rewind */
|
||||
}
|
||||
#endif
|
||||
|
||||
static void host_signal_handler(int host_signum, siginfo_t *info,
|
||||
void *puc)
|
||||
{
|
||||
|
@ -581,6 +588,9 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
|
|||
if (sig < 1 || sig > TARGET_NSIG)
|
||||
return;
|
||||
trace_user_host_signal(env, host_signum, sig);
|
||||
|
||||
rewind_if_in_safe_syscall(puc);
|
||||
|
||||
host_to_target_siginfo_noswap(&tinfo, info);
|
||||
if (queue_signal(env, sig, &tinfo) == 1) {
|
||||
/* interrupt the virtual CPU as soon as possible */
|
||||
|
@ -873,17 +883,18 @@ get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
|
|||
esp = env->regs[R_ESP];
|
||||
/* This is the X/Open sanctioned signal stack switching. */
|
||||
if (ka->sa_flags & TARGET_SA_ONSTACK) {
|
||||
if (sas_ss_flags(esp) == 0)
|
||||
if (sas_ss_flags(esp) == 0) {
|
||||
esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
|
||||
}
|
||||
} else {
|
||||
|
||||
/* This is the legacy signal stack switching. */
|
||||
else
|
||||
if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
|
||||
!(ka->sa_flags & TARGET_SA_RESTORER) &&
|
||||
ka->sa_restorer) {
|
||||
esp = (unsigned long) ka->sa_restorer;
|
||||
}
|
||||
}
|
||||
return (esp - frame_size) & -8ul;
|
||||
}
|
||||
|
||||
|
@ -943,8 +954,9 @@ static void setup_frame(int sig, struct target_sigaction *ka,
|
|||
return;
|
||||
|
||||
give_sigsegv:
|
||||
if (sig == TARGET_SIGSEGV)
|
||||
if (sig == TARGET_SIGSEGV) {
|
||||
ka->_sa_handler = TARGET_SIG_DFL;
|
||||
}
|
||||
force_sig(TARGET_SIGSEGV /* , current */);
|
||||
}
|
||||
|
||||
|
@ -1015,13 +1027,14 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||
return;
|
||||
|
||||
give_sigsegv:
|
||||
if (sig == TARGET_SIGSEGV)
|
||||
if (sig == TARGET_SIGSEGV) {
|
||||
ka->_sa_handler = TARGET_SIG_DFL;
|
||||
}
|
||||
force_sig(TARGET_SIGSEGV /* , current */);
|
||||
}
|
||||
|
||||
static int
|
||||
restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
|
||||
restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc)
|
||||
{
|
||||
unsigned int err = 0;
|
||||
abi_ulong fpstate_addr;
|
||||
|
@ -1039,6 +1052,7 @@ restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
|
|||
env->regs[R_EBX] = tswapl(sc->ebx);
|
||||
env->regs[R_EDX] = tswapl(sc->edx);
|
||||
env->regs[R_ECX] = tswapl(sc->ecx);
|
||||
env->regs[R_EAX] = tswapl(sc->eax);
|
||||
env->eip = tswapl(sc->eip);
|
||||
|
||||
cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3);
|
||||
|
@ -1056,7 +1070,6 @@ restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
|
|||
cpu_x86_frstor(env, fpstate_addr, 1);
|
||||
}
|
||||
|
||||
*peax = tswapl(sc->eax);
|
||||
return err;
|
||||
badframe:
|
||||
return 1;
|
||||
|
@ -1068,7 +1081,7 @@ long do_sigreturn(CPUX86State *env)
|
|||
abi_ulong frame_addr = env->regs[R_ESP] - 8;
|
||||
target_sigset_t target_set;
|
||||
sigset_t set;
|
||||
int eax, i;
|
||||
int i;
|
||||
|
||||
trace_user_do_sigreturn(env, frame_addr);
|
||||
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
|
||||
|
@ -1083,10 +1096,10 @@ long do_sigreturn(CPUX86State *env)
|
|||
do_sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
|
||||
/* restore registers */
|
||||
if (restore_sigcontext(env, &frame->sc, &eax))
|
||||
if (restore_sigcontext(env, &frame->sc))
|
||||
goto badframe;
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return eax;
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
|
@ -1099,7 +1112,6 @@ long do_rt_sigreturn(CPUX86State *env)
|
|||
abi_ulong frame_addr;
|
||||
struct rt_sigframe *frame;
|
||||
sigset_t set;
|
||||
int eax;
|
||||
|
||||
frame_addr = env->regs[R_ESP] - 4;
|
||||
trace_user_do_rt_sigreturn(env, frame_addr);
|
||||
|
@ -1108,15 +1120,17 @@ long do_rt_sigreturn(CPUX86State *env)
|
|||
target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
|
||||
do_sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
|
||||
if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax))
|
||||
if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
|
||||
get_sp_from_cpustate(env)) == -EFAULT)
|
||||
get_sp_from_cpustate(env)) == -EFAULT) {
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return eax;
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
|
@ -1386,7 +1400,7 @@ long do_rt_sigreturn(CPUARMState *env)
|
|||
}
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return env->xregs[0];
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
|
@ -1696,8 +1710,9 @@ static void setup_frame_v1(int usig, struct target_sigaction *ka,
|
|||
int i;
|
||||
|
||||
trace_user_setup_frame(regs, frame_addr);
|
||||
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
|
||||
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
setup_sigcontext(&frame->sc, regs, set->sig[0]);
|
||||
|
||||
|
@ -1718,8 +1733,9 @@ static void setup_frame_v2(int usig, struct target_sigaction *ka,
|
|||
abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
|
||||
|
||||
trace_user_setup_frame(regs, frame_addr);
|
||||
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
|
||||
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
setup_sigframe_v2(&frame->uc, set, regs);
|
||||
|
||||
|
@ -1751,8 +1767,9 @@ static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
|
|||
abi_ulong info_addr, uc_addr;
|
||||
|
||||
trace_user_setup_rt_frame(env, frame_addr);
|
||||
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
|
||||
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
|
||||
return /* 1 */;
|
||||
}
|
||||
|
||||
info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
|
||||
__put_user(info_addr, &frame->pinfo);
|
||||
|
@ -1792,8 +1809,9 @@ static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
|
|||
abi_ulong info_addr, uc_addr;
|
||||
|
||||
trace_user_setup_rt_frame(env, frame_addr);
|
||||
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
|
||||
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
|
||||
return /* 1 */;
|
||||
}
|
||||
|
||||
info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
|
||||
uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
|
||||
|
@ -1872,8 +1890,9 @@ static long do_sigreturn_v1(CPUARMState *env)
|
|||
goto badframe;
|
||||
}
|
||||
|
||||
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
|
||||
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
__get_user(set.sig[0], &frame->sc.oldmask);
|
||||
for(i = 1; i < TARGET_NSIG_WORDS; i++) {
|
||||
|
@ -1883,8 +1902,9 @@ static long do_sigreturn_v1(CPUARMState *env)
|
|||
target_to_host_sigset_internal(&host_set, &set);
|
||||
do_sigprocmask(SIG_SETMASK, &host_set, NULL);
|
||||
|
||||
if (restore_sigcontext(env, &frame->sc))
|
||||
if (restore_sigcontext(env, &frame->sc)) {
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Send SIGTRAP if we're single-stepping */
|
||||
|
@ -1892,7 +1912,7 @@ static long do_sigreturn_v1(CPUARMState *env)
|
|||
send_sig(SIGTRAP, current, 1);
|
||||
#endif
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return env->regs[0];
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
force_sig(TARGET_SIGSEGV /* , current */);
|
||||
|
@ -2009,14 +2029,16 @@ static long do_sigreturn_v2(CPUARMState *env)
|
|||
goto badframe;
|
||||
}
|
||||
|
||||
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
|
||||
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
|
||||
if (do_sigframe_return_v2(env, frame_addr, &frame->uc)) {
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return env->regs[0];
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
|
@ -2050,14 +2072,16 @@ static long do_rt_sigreturn_v1(CPUARMState *env)
|
|||
goto badframe;
|
||||
}
|
||||
|
||||
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
|
||||
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
|
||||
do_sigprocmask(SIG_SETMASK, &host_set, NULL);
|
||||
|
||||
if (restore_sigcontext(env, &frame->uc.tuc_mcontext))
|
||||
if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe_v1, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
|
||||
goto badframe;
|
||||
|
@ -2068,7 +2092,7 @@ static long do_rt_sigreturn_v1(CPUARMState *env)
|
|||
send_sig(SIGTRAP, current, 1);
|
||||
#endif
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return env->regs[0];
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
|
@ -2092,14 +2116,16 @@ static long do_rt_sigreturn_v2(CPUARMState *env)
|
|||
goto badframe;
|
||||
}
|
||||
|
||||
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
|
||||
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
|
||||
if (do_sigframe_return_v2(env, frame_addr, &frame->uc)) {
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return env->regs[0];
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
|
@ -2226,9 +2252,10 @@ static inline abi_ulong get_sigframe(struct target_sigaction *sa,
|
|||
/* This is the X/Open sanctioned signal stack switching. */
|
||||
if (sa->sa_flags & TARGET_SA_ONSTACK) {
|
||||
if (!on_sig_stack(sp)
|
||||
&& !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7))
|
||||
&& !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7)) {
|
||||
sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
|
||||
}
|
||||
}
|
||||
return sp - framesize;
|
||||
}
|
||||
|
||||
|
@ -2287,9 +2314,9 @@ static void setup_frame(int sig, struct target_sigaction *ka,
|
|||
|
||||
sf = lock_user(VERIFY_WRITE, sf_addr,
|
||||
sizeof(struct target_signal_frame), 0);
|
||||
if (!sf)
|
||||
if (!sf) {
|
||||
goto sigsegv;
|
||||
|
||||
}
|
||||
#if 0
|
||||
if (invalid_frame_pointer(sf, sigframe_size))
|
||||
goto sigill_and_return;
|
||||
|
@ -2327,9 +2354,9 @@ static void setup_frame(int sig, struct target_sigaction *ka,
|
|||
env->pc = ka->_sa_handler;
|
||||
env->npc = (env->pc + 4);
|
||||
/* 5. return to kernel instructions */
|
||||
if (ka->sa_restorer)
|
||||
if (ka->sa_restorer) {
|
||||
env->regwptr[UREG_I7] = ka->sa_restorer;
|
||||
else {
|
||||
} else {
|
||||
uint32_t val32;
|
||||
|
||||
env->regwptr[UREG_I7] = sf_addr +
|
||||
|
@ -2347,7 +2374,7 @@ static void setup_frame(int sig, struct target_sigaction *ka,
|
|||
|
||||
/* Flush instruction space. */
|
||||
// flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
|
||||
// tb_flush(CPU(sparc_env_get_cpu(env)));
|
||||
// tb_flush(env);
|
||||
}
|
||||
unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
|
||||
return;
|
||||
|
@ -2378,8 +2405,9 @@ long do_sigreturn(CPUSPARCState *env)
|
|||
|
||||
sf_addr = env->regwptr[UREG_FP];
|
||||
trace_user_do_sigreturn(env, sf_addr);
|
||||
if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1))
|
||||
if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1)) {
|
||||
goto segv_and_exit;
|
||||
}
|
||||
|
||||
/* 1. Make sure we are not getting garbage from the user */
|
||||
|
||||
|
@ -2389,8 +2417,9 @@ long do_sigreturn(CPUSPARCState *env)
|
|||
__get_user(pc, &sf->info.si_regs.pc);
|
||||
__get_user(npc, &sf->info.si_regs.npc);
|
||||
|
||||
if ((pc | npc) & 3)
|
||||
if ((pc | npc) & 3) {
|
||||
goto segv_and_exit;
|
||||
}
|
||||
|
||||
/* 2. Restore the state */
|
||||
__get_user(up_psr, &sf->info.si_regs.psr);
|
||||
|
@ -2426,10 +2455,11 @@ long do_sigreturn(CPUSPARCState *env)
|
|||
target_to_host_sigset_internal(&host_set, &set);
|
||||
do_sigprocmask(SIG_SETMASK, &host_set, NULL);
|
||||
|
||||
if (err)
|
||||
if (err) {
|
||||
goto segv_and_exit;
|
||||
}
|
||||
unlock_user_struct(sf, sf_addr, 0);
|
||||
return env->regwptr[0];
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
|
||||
segv_and_exit:
|
||||
unlock_user_struct(sf, sf_addr, 0);
|
||||
|
@ -2522,13 +2552,15 @@ void sparc64_set_context(CPUSPARCState *env)
|
|||
unsigned int i;
|
||||
|
||||
ucp_addr = env->regwptr[UREG_I0];
|
||||
if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1))
|
||||
if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1)) {
|
||||
goto do_sigsegv;
|
||||
}
|
||||
grp = &ucp->tuc_mcontext.mc_gregs;
|
||||
__get_user(pc, &((*grp)[MC_PC]));
|
||||
__get_user(npc, &((*grp)[MC_NPC]));
|
||||
if ((pc | npc) & 3)
|
||||
if ((pc | npc) & 3) {
|
||||
goto do_sigsegv;
|
||||
}
|
||||
if (env->regwptr[UREG_I1]) {
|
||||
target_sigset_t target_set;
|
||||
sigset_t set;
|
||||
|
@ -2574,11 +2606,13 @@ void sparc64_set_context(CPUSPARCState *env)
|
|||
|
||||
w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
|
||||
if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
|
||||
abi_ulong) != 0)
|
||||
abi_ulong) != 0) {
|
||||
goto do_sigsegv;
|
||||
}
|
||||
if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
|
||||
abi_ulong) != 0)
|
||||
abi_ulong) != 0) {
|
||||
goto do_sigsegv;
|
||||
}
|
||||
/* FIXME this does not match how the kernel handles the FPU in
|
||||
* its sparc64_set_context implementation. In particular the FPU
|
||||
* is only restored if fenab is non-zero in:
|
||||
|
@ -2619,8 +2653,9 @@ void sparc64_get_context(CPUSPARCState *env)
|
|||
sigset_t set;
|
||||
|
||||
ucp_addr = env->regwptr[UREG_I0];
|
||||
if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0))
|
||||
if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0)) {
|
||||
goto do_sigsegv;
|
||||
}
|
||||
|
||||
mcp = &ucp->tuc_mcontext;
|
||||
grp = &mcp->mc_gregs;
|
||||
|
@ -2671,11 +2706,13 @@ void sparc64_get_context(CPUSPARCState *env)
|
|||
w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
|
||||
fp = i7 = 0;
|
||||
if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
|
||||
abi_ulong) != 0)
|
||||
abi_ulong) != 0) {
|
||||
goto do_sigsegv;
|
||||
}
|
||||
if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
|
||||
abi_ulong) != 0)
|
||||
abi_ulong) != 0) {
|
||||
goto do_sigsegv;
|
||||
}
|
||||
__put_user(fp, &(mcp->mc_fp));
|
||||
__put_user(i7, &(mcp->mc_i7));
|
||||
|
||||
|
@ -2899,8 +2936,9 @@ static void setup_frame(int sig, struct target_sigaction * ka,
|
|||
|
||||
frame_addr = get_sigframe(ka, regs, sizeof(*frame));
|
||||
trace_user_setup_frame(regs, frame_addr);
|
||||
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
|
||||
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
|
||||
goto give_sigsegv;
|
||||
}
|
||||
|
||||
install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
|
||||
|
||||
|
@ -2994,8 +3032,9 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||
|
||||
frame_addr = get_sigframe(ka, env, sizeof(*frame));
|
||||
trace_user_setup_rt_frame(env, frame_addr);
|
||||
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
|
||||
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
|
||||
goto give_sigsegv;
|
||||
}
|
||||
|
||||
install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
|
||||
|
||||
|
@ -3053,8 +3092,9 @@ long do_rt_sigreturn(CPUMIPSState *env)
|
|||
|
||||
frame_addr = env->active_tc.gpr[29];
|
||||
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)) {
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
|
||||
do_sigprocmask(SIG_SETMASK, &blocked, NULL);
|
||||
|
@ -3172,13 +3212,12 @@ static void setup_sigcontext(struct target_sigcontext *sc,
|
|||
__put_user(mask, &sc->oldmask);
|
||||
}
|
||||
|
||||
static void restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc,
|
||||
target_ulong *r0_p)
|
||||
static void restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc)
|
||||
{
|
||||
int i;
|
||||
|
||||
#define COPY(x) __get_user(regs->x, &sc->sc_##x)
|
||||
COPY(gregs[1]);
|
||||
COPY(gregs[0]); COPY(gregs[1]);
|
||||
COPY(gregs[2]); COPY(gregs[3]);
|
||||
COPY(gregs[4]); COPY(gregs[5]);
|
||||
COPY(gregs[6]); COPY(gregs[7]);
|
||||
|
@ -3198,7 +3237,6 @@ static void restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc,
|
|||
__get_user(regs->fpul, &sc->sc_fpul);
|
||||
|
||||
regs->tra = -1; /* disable syscall checks */
|
||||
__get_user(*r0_p, &sc->sc_gregs[0]);
|
||||
}
|
||||
|
||||
static void setup_frame(int sig, struct target_sigaction *ka,
|
||||
|
@ -3210,8 +3248,9 @@ static void setup_frame(int sig, struct target_sigaction *ka,
|
|||
|
||||
frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
|
||||
trace_user_setup_frame(regs, frame_addr);
|
||||
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
|
||||
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
|
||||
goto give_sigsegv;
|
||||
}
|
||||
|
||||
setup_sigcontext(&frame->sc, regs, set->sig[0]);
|
||||
|
||||
|
@ -3258,8 +3297,9 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||
|
||||
frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
|
||||
trace_user_setup_rt_frame(regs, frame_addr);
|
||||
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
|
||||
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
|
||||
goto give_sigsegv;
|
||||
}
|
||||
|
||||
tswap_siginfo(&frame->info, info);
|
||||
|
||||
|
@ -3313,14 +3353,14 @@ long do_sigreturn(CPUSH4State *regs)
|
|||
abi_ulong frame_addr;
|
||||
sigset_t blocked;
|
||||
target_sigset_t target_set;
|
||||
target_ulong r0;
|
||||
int i;
|
||||
int err = 0;
|
||||
|
||||
frame_addr = regs->gregs[15];
|
||||
trace_user_do_sigreturn(regs, frame_addr);
|
||||
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
|
||||
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
__get_user(target_set.sig[0], &frame->sc.oldmask);
|
||||
for(i = 1; i < TARGET_NSIG_WORDS; i++) {
|
||||
|
@ -3333,10 +3373,10 @@ long do_sigreturn(CPUSH4State *regs)
|
|||
target_to_host_sigset_internal(&blocked, &target_set);
|
||||
do_sigprocmask(SIG_SETMASK, &blocked, NULL);
|
||||
|
||||
restore_sigcontext(regs, &frame->sc, &r0);
|
||||
restore_sigcontext(regs, &frame->sc);
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return r0;
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
|
@ -3349,25 +3389,26 @@ long do_rt_sigreturn(CPUSH4State *regs)
|
|||
struct target_rt_sigframe *frame;
|
||||
abi_ulong frame_addr;
|
||||
sigset_t blocked;
|
||||
target_ulong r0;
|
||||
|
||||
frame_addr = regs->gregs[15];
|
||||
trace_user_do_rt_sigreturn(regs, frame_addr);
|
||||
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
|
||||
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
|
||||
do_sigprocmask(SIG_SETMASK, &blocked, NULL);
|
||||
|
||||
restore_sigcontext(regs, &frame->uc.tuc_mcontext, &r0);
|
||||
restore_sigcontext(regs, &frame->uc.tuc_mcontext);
|
||||
|
||||
if (do_sigaltstack(frame_addr +
|
||||
offsetof(struct target_rt_sigframe, uc.tuc_stack),
|
||||
0, get_sp_from_cpustate(regs)) == -EFAULT)
|
||||
0, get_sp_from_cpustate(regs)) == -EFAULT) {
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return r0;
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
|
@ -3532,7 +3573,8 @@ static void setup_frame(int sig, struct target_sigaction *ka,
|
|||
|
||||
/* Return from sighandler will jump to the tramp.
|
||||
Negative 8 offset because return is rtsd r15, 8 */
|
||||
env->regs[15] = ((unsigned long)frame->tramp) - 8;
|
||||
env->regs[15] = frame_addr + offsetof(struct target_signal_frame, tramp)
|
||||
- 8;
|
||||
}
|
||||
|
||||
/* Set up registers for signal handler */
|
||||
|
@ -3587,7 +3629,7 @@ long do_sigreturn(CPUMBState *env)
|
|||
env->regs[14] = env->sregs[SR_PC];
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return env->regs[10];
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
badframe:
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
}
|
||||
|
@ -3740,8 +3782,9 @@ long do_sigreturn(CPUCRISState *env)
|
|||
frame_addr = env->regs[R_SP];
|
||||
trace_user_do_sigreturn(env, frame_addr);
|
||||
/* Make sure the guest isn't playing games. */
|
||||
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
|
||||
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1)) {
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
/* Restore blocked signals */
|
||||
__get_user(target_set.sig[0], &frame->sc.oldmask);
|
||||
|
@ -3753,7 +3796,7 @@ long do_sigreturn(CPUCRISState *env)
|
|||
|
||||
restore_sigcontext(&frame->sc, env);
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return env->regs[10];
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
badframe:
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
}
|
||||
|
@ -4116,8 +4159,8 @@ static void setup_frame(int sig, struct target_sigaction *ka,
|
|||
env->regs[14] = (unsigned long)
|
||||
ka->sa_restorer | PSW_ADDR_AMODE;
|
||||
} else {
|
||||
env->regs[14] = (unsigned long)
|
||||
frame->retcode | PSW_ADDR_AMODE;
|
||||
env->regs[14] = (frame_addr + offsetof(sigframe, retcode))
|
||||
| PSW_ADDR_AMODE;
|
||||
__put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
|
||||
(uint16_t *)(frame->retcode));
|
||||
}
|
||||
|
@ -4248,7 +4291,7 @@ long do_sigreturn(CPUS390XState *env)
|
|||
}
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return env->regs[2];
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
|
@ -4278,7 +4321,7 @@ long do_rt_sigreturn(CPUS390XState *env)
|
|||
goto badframe;
|
||||
}
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return env->regs[2];
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
|
@ -4589,7 +4632,7 @@ static void restore_user_regs(CPUPPCState *env,
|
|||
|
||||
/* If doing signal return, restore the previous little-endian mode. */
|
||||
if (sig)
|
||||
env->msr = (env->msr & ~MSR_LE) | (msr & MSR_LE);
|
||||
env->msr = (env->msr & ~(1ull << MSR_LE)) | (msr & (1ull << MSR_LE));
|
||||
|
||||
/* Restore Altivec registers if necessary. */
|
||||
if (env->insns_flags & PPC_ALTIVEC) {
|
||||
|
@ -4704,7 +4747,7 @@ static void setup_frame(int sig, struct target_sigaction *ka,
|
|||
#endif
|
||||
|
||||
/* Signal handlers are entered in big-endian mode. */
|
||||
env->msr &= ~MSR_LE;
|
||||
env->msr &= ~(1ull << MSR_LE);
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 1);
|
||||
return;
|
||||
|
@ -4799,7 +4842,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||
#endif
|
||||
|
||||
/* Signal handlers are entered in big-endian mode. */
|
||||
env->msr &= ~MSR_LE;
|
||||
env->msr &= ~(1ull << MSR_LE);
|
||||
|
||||
unlock_user_struct(rt_sf, rt_sf_addr, 1);
|
||||
return;
|
||||
|
@ -4977,19 +5020,18 @@ static void setup_sigcontext(struct target_sigcontext *sc, CPUM68KState *env,
|
|||
}
|
||||
|
||||
static void
|
||||
restore_sigcontext(CPUM68KState *env, struct target_sigcontext *sc, int *pd0)
|
||||
restore_sigcontext(CPUM68KState *env, struct target_sigcontext *sc)
|
||||
{
|
||||
int temp;
|
||||
|
||||
__get_user(env->aregs[7], &sc->sc_usp);
|
||||
__get_user(env->dregs[0], &sc->sc_d0);
|
||||
__get_user(env->dregs[1], &sc->sc_d1);
|
||||
__get_user(env->aregs[0], &sc->sc_a0);
|
||||
__get_user(env->aregs[1], &sc->sc_a1);
|
||||
__get_user(env->pc, &sc->sc_pc);
|
||||
__get_user(temp, &sc->sc_sr);
|
||||
env->sr = (env->sr & 0xff00) | (temp & 0xff);
|
||||
|
||||
*pd0 = tswapl(sc->sc_d0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -5022,8 +5064,9 @@ static void setup_frame(int sig, struct target_sigaction *ka,
|
|||
|
||||
frame_addr = get_sigframe(ka, env, sizeof *frame);
|
||||
trace_user_setup_frame(env, frame_addr);
|
||||
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
|
||||
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
|
||||
goto give_sigsegv;
|
||||
}
|
||||
|
||||
__put_user(sig, &frame->sig);
|
||||
|
||||
|
@ -5087,8 +5130,7 @@ static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
|
|||
}
|
||||
|
||||
static inline int target_rt_restore_ucontext(CPUM68KState *env,
|
||||
struct target_ucontext *uc,
|
||||
int *pd0)
|
||||
struct target_ucontext *uc)
|
||||
{
|
||||
int temp;
|
||||
target_greg_t *gregs = uc->tuc_mcontext.gregs;
|
||||
|
@ -5118,7 +5160,6 @@ static inline int target_rt_restore_ucontext(CPUM68KState *env,
|
|||
__get_user(temp, &gregs[17]);
|
||||
env->sr = (env->sr & 0xff00) | (temp & 0xff);
|
||||
|
||||
*pd0 = env->dregs[0];
|
||||
return 0;
|
||||
|
||||
badframe:
|
||||
|
@ -5139,8 +5180,9 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||
|
||||
frame_addr = get_sigframe(ka, env, sizeof *frame);
|
||||
trace_user_setup_rt_frame(env, frame_addr);
|
||||
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
|
||||
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
|
||||
goto give_sigsegv;
|
||||
}
|
||||
|
||||
__put_user(sig, &frame->sig);
|
||||
|
||||
|
@ -5204,7 +5246,7 @@ long do_sigreturn(CPUM68KState *env)
|
|||
abi_ulong frame_addr = env->aregs[7] - 4;
|
||||
target_sigset_t target_set;
|
||||
sigset_t set;
|
||||
int d0, i;
|
||||
int i;
|
||||
|
||||
trace_user_do_sigreturn(env, frame_addr);
|
||||
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
|
||||
|
@ -5223,10 +5265,10 @@ long do_sigreturn(CPUM68KState *env)
|
|||
|
||||
/* restore registers */
|
||||
|
||||
restore_sigcontext(env, &frame->sc, &d0);
|
||||
restore_sigcontext(env, &frame->sc);
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return d0;
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
|
@ -5239,7 +5281,6 @@ long do_rt_sigreturn(CPUM68KState *env)
|
|||
abi_ulong frame_addr = env->aregs[7] - 4;
|
||||
target_sigset_t target_set;
|
||||
sigset_t set;
|
||||
int d0;
|
||||
|
||||
trace_user_do_rt_sigreturn(env, frame_addr);
|
||||
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
|
||||
|
@ -5250,7 +5291,7 @@ long do_rt_sigreturn(CPUM68KState *env)
|
|||
|
||||
/* restore registers */
|
||||
|
||||
if (target_rt_restore_ucontext(env, &frame->uc, &d0))
|
||||
if (target_rt_restore_ucontext(env, &frame->uc))
|
||||
goto badframe;
|
||||
|
||||
if (do_sigaltstack(frame_addr +
|
||||
|
@ -5259,7 +5300,7 @@ long do_rt_sigreturn(CPUM68KState *env)
|
|||
goto badframe;
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return d0;
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
|
@ -5493,7 +5534,7 @@ long do_sigreturn(CPUAlphaState *env)
|
|||
|
||||
restore_sigcontext(env, sc);
|
||||
unlock_user_struct(sc, sc_addr, 0);
|
||||
return env->ir[IR_V0];
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
|
@ -5520,7 +5561,7 @@ long do_rt_sigreturn(CPUAlphaState *env)
|
|||
}
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return env->ir[IR_V0];
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
|
||||
|
||||
badframe:
|
||||
|
@ -5559,8 +5600,13 @@ struct target_rt_sigframe {
|
|||
unsigned char save_area[16]; /* caller save area */
|
||||
struct target_siginfo info;
|
||||
struct target_ucontext uc;
|
||||
abi_ulong retcode[2];
|
||||
};
|
||||
|
||||
#define INSN_MOVELI_R10_139 0x00045fe551483000ULL /* { moveli r10, 139 } */
|
||||
#define INSN_SWINT1 0x286b180051485000ULL /* { swint1 } */
|
||||
|
||||
|
||||
static void setup_sigcontext(struct target_sigcontext *sc,
|
||||
CPUArchState *env, int signo)
|
||||
{
|
||||
|
@ -5636,9 +5682,12 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||
__put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
|
||||
setup_sigcontext(&frame->uc.tuc_mcontext, env, info->si_signo);
|
||||
|
||||
restorer = (unsigned long) do_rt_sigreturn;
|
||||
if (ka->sa_flags & TARGET_SA_RESTORER) {
|
||||
restorer = (unsigned long) ka->sa_restorer;
|
||||
} else {
|
||||
__put_user(INSN_MOVELI_R10_139, &frame->retcode[0]);
|
||||
__put_user(INSN_SWINT1, &frame->retcode[1]);
|
||||
restorer = frame_addr + offsetof(struct target_rt_sigframe, retcode);
|
||||
}
|
||||
env->pc = (unsigned long) ka->_sa_handler;
|
||||
env->regs[TILEGX_R_SP] = (unsigned long) frame;
|
||||
|
@ -5679,7 +5728,7 @@ long do_rt_sigreturn(CPUTLGState *env)
|
|||
}
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return env->regs[TILEGX_R_RE];
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
|
||||
|
||||
badframe:
|
||||
|
|
|
@ -33,4 +33,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
|
|||
return state->regwptr[UREG_FP];
|
||||
}
|
||||
|
||||
|
||||
#endif /* TARGET_SIGNAL_H */
|
||||
|
|
|
@ -33,4 +33,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
|
|||
return state->regwptr[UREG_FP];
|
||||
}
|
||||
|
||||
|
||||
#endif /* TARGET_SIGNAL_H */
|
||||
|
|
|
@ -110,6 +110,10 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
|
|||
CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
|
||||
|
||||
//#define DEBUG
|
||||
/* Define DEBUG_ERESTARTSYS to force every syscall to be restarted
|
||||
* once. This exercises the codepaths for restart.
|
||||
*/
|
||||
//#define DEBUG_ERESTARTSYS
|
||||
|
||||
//#include <linux/msdos_fs.h>
|
||||
#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
|
||||
|
@ -355,18 +359,6 @@ static int sys_getcwd1(char *buf, size_t size)
|
|||
return strlen(buf)+1;
|
||||
}
|
||||
|
||||
static int sys_openat(int dirfd, const char *pathname, int flags, mode_t mode)
|
||||
{
|
||||
/*
|
||||
* open(2) has extra parameter 'mode' when called with
|
||||
* flag O_CREAT.
|
||||
*/
|
||||
if ((flags & O_CREAT) != 0) {
|
||||
return (openat(dirfd, pathname, flags, mode));
|
||||
}
|
||||
return (openat(dirfd, pathname, flags));
|
||||
}
|
||||
|
||||
#ifdef TARGET_NR_utimensat
|
||||
#ifdef CONFIG_UTIMENSAT
|
||||
static int sys_utimensat(int dirfd, const char *pathname,
|
||||
|
@ -438,15 +430,6 @@ _syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds,
|
|||
size_t, sigsetsize)
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_NR_pselect6)
|
||||
#ifndef __NR_pselect6
|
||||
# define __NR_pselect6 -1
|
||||
#endif
|
||||
#define __NR_sys_pselect6 __NR_pselect6
|
||||
_syscall6(int, sys_pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds,
|
||||
fd_set *, exceptfds, struct timespec *, timeout, void *, sig);
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_NR_prlimit64)
|
||||
#ifndef __NR_prlimit64
|
||||
# define __NR_prlimit64 -1
|
||||
|
@ -619,15 +602,19 @@ static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
|
|||
|
||||
static inline int host_to_target_errno(int err)
|
||||
{
|
||||
if(host_to_target_errno_table[err])
|
||||
if (err >= 0 && err < ERRNO_TABLE_SIZE &&
|
||||
host_to_target_errno_table[err]) {
|
||||
return host_to_target_errno_table[err];
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline int target_to_host_errno(int err)
|
||||
{
|
||||
if (target_to_host_errno_table[err])
|
||||
if (err >= 0 && err < ERRNO_TABLE_SIZE &&
|
||||
target_to_host_errno_table[err]) {
|
||||
return target_to_host_errno_table[err];
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -652,6 +639,67 @@ char *target_strerror(int err)
|
|||
return strerror(target_to_host_errno(err));
|
||||
}
|
||||
|
||||
#define safe_syscall0(type, name) \
|
||||
static type safe_##name(void) \
|
||||
{ \
|
||||
return safe_syscall(__NR_##name); \
|
||||
}
|
||||
|
||||
#define safe_syscall1(type, name, type1, arg1) \
|
||||
static type safe_##name(type1 arg1) \
|
||||
{ \
|
||||
return safe_syscall(__NR_##name, arg1); \
|
||||
}
|
||||
|
||||
#define safe_syscall2(type, name, type1, arg1, type2, arg2) \
|
||||
static type safe_##name(type1 arg1, type2 arg2) \
|
||||
{ \
|
||||
return safe_syscall(__NR_##name, arg1, arg2); \
|
||||
}
|
||||
|
||||
#define safe_syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \
|
||||
static type safe_##name(type1 arg1, type2 arg2, type3 arg3) \
|
||||
{ \
|
||||
return safe_syscall(__NR_##name, arg1, arg2, arg3); \
|
||||
}
|
||||
|
||||
#define safe_syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \
|
||||
type4, arg4) \
|
||||
static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
|
||||
{ \
|
||||
return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4); \
|
||||
}
|
||||
|
||||
#define safe_syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \
|
||||
type4, arg4, type5, arg5) \
|
||||
static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
|
||||
type5 arg5) \
|
||||
{ \
|
||||
return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
|
||||
}
|
||||
|
||||
#define safe_syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \
|
||||
type4, arg4, type5, arg5, type6, arg6) \
|
||||
static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
|
||||
type5 arg5, type6 arg6) \
|
||||
{ \
|
||||
return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
|
||||
}
|
||||
|
||||
safe_syscall3(ssize_t, read, int, fd, void *, buff, size_t, count)
|
||||
safe_syscall3(ssize_t, write, int, fd, const void *, buff, size_t, count)
|
||||
safe_syscall4(int, openat, int, dirfd, const char *, pathname, \
|
||||
int, flags, mode_t, mode)
|
||||
safe_syscall4(pid_t, wait4, pid_t, pid, int *, status, int, options, \
|
||||
struct rusage *, rusage)
|
||||
safe_syscall5(int, waitid, idtype_t, idtype, id_t, id, siginfo_t *, infop, \
|
||||
int, options, struct rusage *, rusage)
|
||||
safe_syscall3(int, execve, const char *, filename, char **, argv, char **, envp)
|
||||
safe_syscall6(int, pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds, \
|
||||
fd_set *, exceptfds, struct timespec *, timeout, void *, sig)
|
||||
safe_syscall6(int,futex,int *,uaddr,int,op,int,val, \
|
||||
const struct timespec *,timeout,int *,uaddr2,int,val3)
|
||||
|
||||
static inline int host_to_target_sock_type(int host_type)
|
||||
{
|
||||
int target_type;
|
||||
|
@ -1062,7 +1110,8 @@ static abi_long do_select(int n,
|
|||
{
|
||||
fd_set rfds, wfds, efds;
|
||||
fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
|
||||
struct timeval tv, *tv_ptr;
|
||||
struct timeval tv;
|
||||
struct timespec ts, *ts_ptr;
|
||||
abi_long ret;
|
||||
|
||||
ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
|
||||
|
@ -1081,12 +1130,15 @@ static abi_long do_select(int n,
|
|||
if (target_tv_addr) {
|
||||
if (copy_from_user_timeval(&tv, target_tv_addr))
|
||||
return -TARGET_EFAULT;
|
||||
tv_ptr = &tv;
|
||||
ts.tv_sec = tv.tv_sec;
|
||||
ts.tv_nsec = tv.tv_usec * 1000;
|
||||
ts_ptr = &ts;
|
||||
} else {
|
||||
tv_ptr = NULL;
|
||||
ts_ptr = NULL;
|
||||
}
|
||||
|
||||
ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
|
||||
ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
|
||||
ts_ptr, NULL));
|
||||
|
||||
if (!is_error(ret)) {
|
||||
if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
|
||||
|
@ -1096,9 +1148,14 @@ static abi_long do_select(int n,
|
|||
if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
|
||||
return -TARGET_EFAULT;
|
||||
|
||||
if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv))
|
||||
if (target_tv_addr) {
|
||||
tv.tv_sec = ts.tv_sec;
|
||||
tv.tv_usec = ts.tv_nsec / 1000;
|
||||
if (copy_to_user_timeval(target_tv_addr, &tv)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -3095,7 +3152,7 @@ static inline abi_long do_msgsnd(int msqid, abi_long msgp,
|
|||
}
|
||||
|
||||
static inline abi_long do_msgrcv(int msqid, abi_long msgp,
|
||||
unsigned int msgsz, abi_long msgtyp,
|
||||
ssize_t msgsz, abi_long msgtyp,
|
||||
int msgflg)
|
||||
{
|
||||
struct target_msgbuf *target_mb;
|
||||
|
@ -3103,10 +3160,18 @@ static inline abi_long do_msgrcv(int msqid, abi_long msgp,
|
|||
struct msgbuf *host_mb;
|
||||
abi_long ret = 0;
|
||||
|
||||
if (msgsz < 0) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
|
||||
if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
|
||||
return -TARGET_EFAULT;
|
||||
|
||||
host_mb = g_malloc(msgsz+sizeof(long));
|
||||
host_mb = g_try_malloc(msgsz + sizeof(long));
|
||||
if (!host_mb) {
|
||||
ret = -TARGET_ENOMEM;
|
||||
goto end;
|
||||
}
|
||||
ret = get_errno(msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
|
||||
|
||||
if (ret > 0) {
|
||||
|
@ -5034,6 +5099,40 @@ static inline int tswapid(int id)
|
|||
|
||||
#endif /* USE_UID16 */
|
||||
|
||||
/* We must do direct syscalls for setting UID/GID, because we want to
|
||||
* implement the Linux system call semantics of "change only for this thread",
|
||||
* not the libc/POSIX semantics of "change for all threads in process".
|
||||
* (See http://ewontfix.com/17/ for more details.)
|
||||
* We use the 32-bit version of the syscalls if present; if it is not
|
||||
* then either the host architecture supports 32-bit UIDs natively with
|
||||
* the standard syscall, or the 16-bit UID is the best we can do.
|
||||
*/
|
||||
#ifdef __NR_setuid32
|
||||
#define __NR_sys_setuid __NR_setuid32
|
||||
#else
|
||||
#define __NR_sys_setuid __NR_setuid
|
||||
#endif
|
||||
#ifdef __NR_setgid32
|
||||
#define __NR_sys_setgid __NR_setgid32
|
||||
#else
|
||||
#define __NR_sys_setgid __NR_setgid
|
||||
#endif
|
||||
#ifdef __NR_setresuid32
|
||||
#define __NR_sys_setresuid __NR_setresuid32
|
||||
#else
|
||||
#define __NR_sys_setresuid __NR_setresuid
|
||||
#endif
|
||||
#ifdef __NR_setresgid32
|
||||
#define __NR_sys_setresgid __NR_setresgid32
|
||||
#else
|
||||
#define __NR_sys_setresgid __NR_setresgid
|
||||
#endif
|
||||
|
||||
_syscall1(int, sys_setuid, uid_t, uid)
|
||||
_syscall1(int, sys_setgid, gid_t, gid)
|
||||
_syscall3(int, sys_setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
|
||||
_syscall3(int, sys_setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
|
||||
|
||||
void syscall_init(void)
|
||||
{
|
||||
IOCTLEntry *ie;
|
||||
|
@ -5137,8 +5236,8 @@ static inline abi_long target_to_host_timespec(struct timespec *host_ts,
|
|||
|
||||
if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
|
||||
return -TARGET_EFAULT;
|
||||
host_ts->tv_sec = tswapal(target_ts->tv_sec);
|
||||
host_ts->tv_nsec = tswapal(target_ts->tv_nsec);
|
||||
__get_user(host_ts->tv_sec, &target_ts->tv_sec);
|
||||
__get_user(host_ts->tv_nsec, &target_ts->tv_nsec);
|
||||
unlock_user_struct(target_ts, target_addr, 0);
|
||||
return 0;
|
||||
}
|
||||
|
@ -5150,8 +5249,8 @@ static inline abi_long host_to_target_timespec(abi_ulong target_addr,
|
|||
|
||||
if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
|
||||
return -TARGET_EFAULT;
|
||||
target_ts->tv_sec = tswapal(host_ts->tv_sec);
|
||||
target_ts->tv_nsec = tswapal(host_ts->tv_nsec);
|
||||
__put_user(host_ts->tv_sec, &target_ts->tv_sec);
|
||||
__put_user(host_ts->tv_nsec, &target_ts->tv_nsec);
|
||||
unlock_user_struct(target_ts, target_addr, 1);
|
||||
return 0;
|
||||
}
|
||||
|
@ -5326,12 +5425,12 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
|
|||
} else {
|
||||
pts = NULL;
|
||||
}
|
||||
return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
|
||||
return get_errno(safe_futex(g2h(uaddr), op, tswap32(val),
|
||||
pts, NULL, val3));
|
||||
case FUTEX_WAKE:
|
||||
return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
|
||||
return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
|
||||
case FUTEX_FD:
|
||||
return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
|
||||
return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
|
||||
case FUTEX_REQUEUE:
|
||||
case FUTEX_CMP_REQUEUE:
|
||||
case FUTEX_WAKE_OP:
|
||||
|
@ -5341,7 +5440,7 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
|
|||
to satisfy the compiler. We do not need to tswap TIMEOUT
|
||||
since it's not compared to guest memory. */
|
||||
pts = (struct timespec *)(uintptr_t) timeout;
|
||||
return get_errno(sys_futex(g2h(uaddr), op, val, pts,
|
||||
return get_errno(safe_futex(g2h(uaddr), op, val, pts,
|
||||
g2h(uaddr2),
|
||||
(base_op == FUTEX_CMP_REQUEUE
|
||||
? tswap32(val3)
|
||||
|
@ -5555,7 +5654,9 @@ static int open_self_cmdline(void *cpu_env, int fd)
|
|||
|
||||
nb_read = read(fd_orig, buf, sizeof(buf));
|
||||
if (nb_read < 0) {
|
||||
int e = errno;
|
||||
fd_orig = close(fd_orig);
|
||||
errno = e;
|
||||
return -1;
|
||||
} else if (nb_read == 0) {
|
||||
break;
|
||||
|
@ -5575,7 +5676,9 @@ static int open_self_cmdline(void *cpu_env, int fd)
|
|||
|
||||
if (word_skipped) {
|
||||
if (write(fd, cp_buf, nb_read) != nb_read) {
|
||||
int e = errno;
|
||||
close(fd_orig);
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -5595,7 +5698,7 @@ static int open_self_maps(void *cpu_env, int fd)
|
|||
|
||||
fp = fopen("/proc/self/maps", "r");
|
||||
if (fp == NULL) {
|
||||
return -EACCES;
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((read = getline(&line, &len, fp)) != -1) {
|
||||
|
@ -5739,7 +5842,7 @@ static int open_net_route(void *cpu_env, int fd)
|
|||
|
||||
fp = fopen("/proc/net/route", "r");
|
||||
if (fp == NULL) {
|
||||
return -EACCES;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* read header */
|
||||
|
@ -5789,7 +5892,7 @@ static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags,
|
|||
|
||||
if (is_proc_myself(pathname, "exe")) {
|
||||
int execfd = qemu_getauxval(AT_EXECFD);
|
||||
return execfd ? execfd : get_errno(sys_openat(dirfd, exec_path, flags, mode));
|
||||
return execfd ? execfd : safe_openat(dirfd, exec_path, flags, mode);
|
||||
}
|
||||
|
||||
for (fake_open = fakes; fake_open->filename; fake_open++) {
|
||||
|
@ -5815,7 +5918,9 @@ static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags,
|
|||
unlink(filename);
|
||||
|
||||
if ((r = fake_open->fill(cpu_env, fd))) {
|
||||
int e = errno;
|
||||
close(fd);
|
||||
errno = e;
|
||||
return r;
|
||||
}
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
|
@ -5823,7 +5928,7 @@ static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags,
|
|||
return fd;
|
||||
}
|
||||
|
||||
return get_errno(sys_openat(dirfd, path(pathname), flags, mode));
|
||||
return safe_openat(dirfd, path(pathname), flags, mode);
|
||||
}
|
||||
|
||||
#define TIMER_MAGIC 0x0caf0000
|
||||
|
@ -5861,6 +5966,21 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
|||
struct statfs stfs;
|
||||
void *p;
|
||||
|
||||
#if defined(DEBUG_ERESTARTSYS)
|
||||
/* Debug-only code for exercising the syscall-restart code paths
|
||||
* in the per-architecture cpu main loops: restart every syscall
|
||||
* the guest makes once before letting it through.
|
||||
*/
|
||||
{
|
||||
static int flag;
|
||||
|
||||
flag = !flag;
|
||||
if (flag) {
|
||||
return -TARGET_ERESTARTSYS;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
gemu_log("syscall %d", num);
|
||||
#endif
|
||||
|
@ -5907,7 +6027,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
|||
else {
|
||||
if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
|
||||
goto efault;
|
||||
ret = get_errno(read(arg1, p, arg3));
|
||||
ret = get_errno(safe_read(arg1, p, arg3));
|
||||
if (ret >= 0 &&
|
||||
fd_trans_host_to_target_data(arg1)) {
|
||||
ret = fd_trans_host_to_target_data(arg1)(p, ret);
|
||||
|
@ -5918,7 +6038,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
|||
case TARGET_NR_write:
|
||||
if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
|
||||
goto efault;
|
||||
ret = get_errno(write(arg1, p, arg3));
|
||||
ret = get_errno(safe_write(arg1, p, arg3));
|
||||
unlock_user(p, arg2, 0);
|
||||
break;
|
||||
#ifdef TARGET_NR_open
|
||||
|
@ -5968,7 +6088,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
|||
case TARGET_NR_waitpid:
|
||||
{
|
||||
int status;
|
||||
ret = get_errno(waitpid(arg1, &status, arg3));
|
||||
ret = get_errno(safe_wait4(arg1, &status, arg3, 0));
|
||||
if (!is_error(ret) && arg2 && ret
|
||||
&& put_user_s32(host_to_target_waitstatus(status), arg2))
|
||||
goto efault;
|
||||
|
@ -5980,7 +6100,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
|||
{
|
||||
siginfo_t info;
|
||||
info.si_pid = 0;
|
||||
ret = get_errno(waitid(arg1, arg2, &info, arg4));
|
||||
ret = get_errno(safe_waitid(arg1, arg2, &info, arg4, NULL));
|
||||
if (!is_error(ret) && arg3 && info.si_pid != 0) {
|
||||
if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
|
||||
goto efault;
|
||||
|
@ -6106,7 +6226,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
|||
|
||||
if (!(p = lock_user_string(arg1)))
|
||||
goto execve_efault;
|
||||
ret = get_errno(execve(p, argp, envp));
|
||||
/* Although execve() is not an interruptible syscall it is
|
||||
* a special case where we must use the safe_syscall wrapper:
|
||||
* if we allow a signal to happen before we make the host
|
||||
* syscall then we will 'lose' it, because at the point of
|
||||
* execve the process leaves QEMU's control. So we use the
|
||||
* safe syscall wrapper to ensure that we either take the
|
||||
* signal as a guest signal, or else it does not happen
|
||||
* before the execve completes and makes it the other
|
||||
* program's problem.
|
||||
*/
|
||||
ret = get_errno(safe_execve(p, argp, envp));
|
||||
unlock_user(p, arg1, 0);
|
||||
|
||||
goto execve_end;
|
||||
|
@ -6930,12 +7060,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
|||
break;
|
||||
#ifdef TARGET_NR_sigreturn
|
||||
case TARGET_NR_sigreturn:
|
||||
/* NOTE: ret is eax, so not transcoding must be done */
|
||||
ret = do_sigreturn(cpu_env);
|
||||
break;
|
||||
#endif
|
||||
case TARGET_NR_rt_sigreturn:
|
||||
/* NOTE: ret is eax, so not transcoding must be done */
|
||||
ret = do_rt_sigreturn(cpu_env);
|
||||
break;
|
||||
case TARGET_NR_sethostname:
|
||||
|
@ -7124,7 +7252,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
|||
sig_ptr = NULL;
|
||||
}
|
||||
|
||||
ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
|
||||
ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
|
||||
ts_ptr, sig_ptr));
|
||||
|
||||
if (!is_error(ret)) {
|
||||
|
@ -7694,7 +7822,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
|||
rusage_ptr = &rusage;
|
||||
else
|
||||
rusage_ptr = NULL;
|
||||
ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
|
||||
ret = get_errno(safe_wait4(arg1, &status, arg3, rusage_ptr));
|
||||
if (!is_error(ret)) {
|
||||
if (status_ptr && ret) {
|
||||
status = host_to_target_waitstatus(status);
|
||||
|
@ -8740,7 +8868,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
|||
#endif
|
||||
#ifdef TARGET_NR_setresuid
|
||||
case TARGET_NR_setresuid:
|
||||
ret = get_errno(setresuid(low2highuid(arg1),
|
||||
ret = get_errno(sys_setresuid(low2highuid(arg1),
|
||||
low2highuid(arg2),
|
||||
low2highuid(arg3)));
|
||||
break;
|
||||
|
@ -8761,7 +8889,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
|||
#endif
|
||||
#ifdef TARGET_NR_getresgid
|
||||
case TARGET_NR_setresgid:
|
||||
ret = get_errno(setresgid(low2highgid(arg1),
|
||||
ret = get_errno(sys_setresgid(low2highgid(arg1),
|
||||
low2highgid(arg2),
|
||||
low2highgid(arg3)));
|
||||
break;
|
||||
|
@ -8789,10 +8917,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
|||
break;
|
||||
#endif
|
||||
case TARGET_NR_setuid:
|
||||
ret = get_errno(setuid(low2highuid(arg1)));
|
||||
ret = get_errno(sys_setuid(low2highuid(arg1)));
|
||||
break;
|
||||
case TARGET_NR_setgid:
|
||||
ret = get_errno(setgid(low2highgid(arg1)));
|
||||
ret = get_errno(sys_setgid(low2highgid(arg1)));
|
||||
break;
|
||||
case TARGET_NR_setfsuid:
|
||||
ret = get_errno(setfsuid(arg1));
|
||||
|
@ -9074,7 +9202,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
|||
#endif
|
||||
#ifdef TARGET_NR_setresuid32
|
||||
case TARGET_NR_setresuid32:
|
||||
ret = get_errno(setresuid(arg1, arg2, arg3));
|
||||
ret = get_errno(sys_setresuid(arg1, arg2, arg3));
|
||||
break;
|
||||
#endif
|
||||
#ifdef TARGET_NR_getresuid32
|
||||
|
@ -9093,7 +9221,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
|||
#endif
|
||||
#ifdef TARGET_NR_setresgid32
|
||||
case TARGET_NR_setresgid32:
|
||||
ret = get_errno(setresgid(arg1, arg2, arg3));
|
||||
ret = get_errno(sys_setresgid(arg1, arg2, arg3));
|
||||
break;
|
||||
#endif
|
||||
#ifdef TARGET_NR_getresgid32
|
||||
|
@ -9120,12 +9248,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
|||
#endif
|
||||
#ifdef TARGET_NR_setuid32
|
||||
case TARGET_NR_setuid32:
|
||||
ret = get_errno(setuid(arg1));
|
||||
ret = get_errno(sys_setuid(arg1));
|
||||
break;
|
||||
#endif
|
||||
#ifdef TARGET_NR_setgid32
|
||||
case TARGET_NR_setgid32:
|
||||
ret = get_errno(setgid(arg1));
|
||||
ret = get_errno(sys_setgid(arg1));
|
||||
break;
|
||||
#endif
|
||||
#ifdef TARGET_NR_setfsuid32
|
||||
|
|
|
@ -55,7 +55,8 @@
|
|||
#define TARGET_IOC_NRBITS 8
|
||||
#define TARGET_IOC_TYPEBITS 8
|
||||
|
||||
#if defined(TARGET_I386) || (defined(TARGET_ARM) && defined(TARGET_ABI32)) \
|
||||
#if (defined(TARGET_I386) && defined(TARGET_ABI32)) \
|
||||
|| (defined(TARGET_ARM) && defined(TARGET_ABI32)) \
|
||||
|| defined(TARGET_SPARC) \
|
||||
|| defined(TARGET_M68K) || defined(TARGET_SH4) || defined(TARGET_CRIS)
|
||||
/* 16 bit uid wrappers emulation */
|
||||
|
|
|
@ -25,4 +25,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUTLGState *state)
|
|||
return state->regs[TILEGX_R_SP];
|
||||
}
|
||||
|
||||
|
||||
#endif /* TARGET_SIGNAL_H */
|
||||
|
|
Loading…
Reference in New Issue