提交 d6550e9e 编写于 作者: P Peter Maydell

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: NPeter Maydell <peter.maydell@linaro.org>
......@@ -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
......
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 */
/*
* 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
/*
* 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
/*
* 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,28 +295,38 @@ void cpu_loop(CPUX86State *env)
switch(trapnr) {
case 0x80:
/* linux syscall from int $0x80 */
env->regs[R_EAX] = do_syscall(env,
env->regs[R_EAX],
env->regs[R_EBX],
env->regs[R_ECX],
env->regs[R_EDX],
env->regs[R_ESI],
env->regs[R_EDI],
env->regs[R_EBP],
0, 0);
ret = do_syscall(env,
env->regs[R_EAX],
env->regs[R_EBX],
env->regs[R_ECX],
env->regs[R_EDX],
env->regs[R_ESI],
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,
env->regs[R_EAX],
env->regs[R_EDI],
env->regs[R_ESI],
env->regs[R_EDX],
env->regs[10],
env->regs[8],
env->regs[9],
0, 0);
ret = do_syscall(env,
env->regs[R_EAX],
env->regs[R_EDI],
env->regs[R_ESI],
env->regs[R_EDX],
env->regs[10],
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,15 +866,20 @@ void cpu_loop(CPUARMState *env)
break;
}
} else {
env->regs[0] = do_syscall(env,
n,
env->regs[0],
env->regs[1],
env->regs[2],
env->regs[3],
env->regs[4],
env->regs[5],
0, 0);
ret = do_syscall(env,
n,
env->regs[0],
env->regs[1],
env->regs[2],
env->regs[3],
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,15 +1072,20 @@ void cpu_loop(CPUARMState *env)
switch (trapnr) {
case EXCP_SWI:
env->xregs[0] = do_syscall(env,
env->xregs[8],
env->xregs[0],
env->xregs[1],
env->xregs[2],
env->xregs[3],
env->xregs[4],
env->xregs[5],
0, 0);
ret = do_syscall(env,
env->xregs[8],
env->xregs[0],
env->xregs[1],
env->xregs[2],
env->xregs[3],
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,14 +2770,19 @@ void cpu_loop(CPUOpenRISCState *env)
break;
case EXCP_SYSCALL:
env->pc += 4; /* 0xc00; */
env->gpr[11] = do_syscall(env,
env->gpr[11], /* return value */
env->gpr[3], /* r3 - r7 are params */
env->gpr[4],
env->gpr[5],
env->gpr[6],
env->gpr[7],
env->gpr[8], 0, 0);
ret = do_syscall(env,
env->gpr[11], /* return value */
env->gpr[3], /* r3 - r7 are params */
env->gpr[4],
env->gpr[5],
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);
env->gregs[0] = ret;
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);
env->regs[10] = ret;
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);
env->regs[3] = ret;
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,18 +3102,24 @@ 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,
n,
env->dregs[1],
env->dregs[2],
env->dregs[3],
env->dregs[4],
env->dregs[5],
env->aregs[0],
0, 0);
ret = do_syscall(env,
n,
env->dregs[1],
env->dregs[2],
env->dregs[3],
env->dregs[4],
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],
env->regs[4], env->regs[5],
env->regs[6], env->regs[7], 0, 0);
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],
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;
{
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]);
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
......
#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 */
/*
* 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 */
此差异已折叠。
......@@ -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 */
此差异已折叠。
......@@ -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 */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册