diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2016-05-27 14:05:48 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2016-05-27 14:05:48 +0100 |
commit | d6550e9ed2e1a60d889dfb721de00d9a4e3bafbe (patch) | |
tree | 3ab1161c8e63c202cbd207cfb10e1e37ec206951 | |
parent | 34c99d7b93c9181aa8c426300beca130b2b19e39 (diff) | |
parent | 49e55cbacf4ad08f831b9f3f9cb0f3082883a3a1 (diff) |
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>
31 files changed, 1539 insertions, 972 deletions
diff --git a/Makefile.target b/Makefile.target index 34ddb7e762..5b80dd7fc9 100644 --- a/Makefile.target +++ b/Makefile.target @@ -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 diff --git a/linux-user/Makefile.objs b/linux-user/Makefile.objs index fd5021788f..8c93058100 100644 --- a/linux-user/Makefile.objs +++ b/linux-user/Makefile.objs @@ -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 diff --git a/linux-user/alpha/target_signal.h b/linux-user/alpha/target_signal.h index d3822da60e..4c78319145 100644 --- a/linux-user/alpha/target_signal.h +++ b/linux-user/alpha/target_signal.h @@ -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 */ diff --git a/linux-user/arm/target_signal.h b/linux-user/arm/target_signal.h index 2b3281312b..fb31f4c5ec 100644 --- a/linux-user/arm/target_signal.h +++ b/linux-user/arm/target_signal.h @@ -26,4 +26,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUARMState *state) return state->regs[13]; } + #endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/arm/target_syscall.h b/linux-user/arm/target_syscall.h index ea863db0b9..11077b761b 100644 --- a/linux-user/arm/target_syscall.h +++ b/linux-user/arm/target_syscall.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 diff --git a/linux-user/cris/target_signal.h b/linux-user/cris/target_signal.h index 5611840f83..e0f1382815 100644 --- a/linux-user/cris/target_signal.h +++ b/linux-user/cris/target_signal.h @@ -26,4 +26,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUCRISState *state) return state->regs[14]; } + #endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/elfload.c b/linux-user/elfload.c index e47caff7ae..bb2558f284 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -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 diff --git a/linux-user/errno_defs.h b/linux-user/errno_defs.h index 8a1cf76cdb..65522c4516 100644 --- a/linux-user/errno_defs.h +++ b/linux-user/errno_defs.h @@ -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 */ diff --git a/linux-user/host/generic/hostdep.h b/linux-user/host/generic/hostdep.h new file mode 100644 index 0000000000..cfabc3590b --- /dev/null +++ b/linux-user/host/generic/hostdep.h @@ -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 diff --git a/linux-user/host/x86_64/hostdep.h b/linux-user/host/x86_64/hostdep.h new file mode 100644 index 0000000000..9dfbf3ae6a --- /dev/null +++ b/linux-user/host/x86_64/hostdep.h @@ -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 diff --git a/linux-user/host/x86_64/safe-syscall.inc.S b/linux-user/host/x86_64/safe-syscall.inc.S new file mode 100644 index 0000000000..dde434c8d7 --- /dev/null +++ b/linux-user/host/x86_64/safe-syscall.inc.S @@ -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 diff --git a/linux-user/m68k/target_signal.h b/linux-user/m68k/target_signal.h index 479758a421..9deaa89c80 100644 --- a/linux-user/m68k/target_signal.h +++ b/linux-user/m68k/target_signal.h @@ -26,4 +26,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUM68KState *state) return state->aregs[7]; } + #endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/main.c b/linux-user/main.c index 95ed11d85c..b2bc6ab2f7 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -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; diff --git a/linux-user/microblaze/target_signal.h b/linux-user/microblaze/target_signal.h index 3d1f7a7238..acdf3b5acd 100644 --- a/linux-user/microblaze/target_signal.h +++ b/linux-user/microblaze/target_signal.h @@ -26,4 +26,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUMBState *state) return state->regs[14]; } + #endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/mips/target_signal.h b/linux-user/mips/target_signal.h index 6e1dc8b6e6..460cc9ffef 100644 --- a/linux-user/mips/target_signal.h +++ b/linux-user/mips/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 */ diff --git a/linux-user/mips/target_syscall.h b/linux-user/mips/target_syscall.h index 68db160e53..e8e305cc9c 100644 --- a/linux-user/mips/target_syscall.h +++ b/linux-user/mips/target_syscall.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" diff --git a/linux-user/mips64/target_signal.h b/linux-user/mips64/target_signal.h index 5fb6a2ccfc..a2dc514e3e 100644 --- a/linux-user/mips64/target_signal.h +++ b/linux-user/mips64/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 */ diff --git a/linux-user/mips64/target_syscall.h b/linux-user/mips64/target_syscall.h index 0e0c2d232f..5789e86150 100644 --- a/linux-user/mips64/target_syscall.h +++ b/linux-user/mips64/target_syscall.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" diff --git a/linux-user/openrisc/target_signal.h b/linux-user/openrisc/target_signal.h index 964aed69f1..f600501f6f 100644 --- a/linux-user/openrisc/target_signal.h +++ b/linux-user/openrisc/target_signal.h @@ -23,4 +23,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUOpenRISCState *state) return state->gpr[1]; } + #endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/ppc/target_signal.h b/linux-user/ppc/target_signal.h index a93b5cf1df..4f01dd4ea8 100644 --- a/linux-user/ppc/target_signal.h +++ b/linux-user/ppc/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 */ diff --git a/linux-user/ppc/target_syscall.h b/linux-user/ppc/target_syscall.h index 35cab59462..7ca83c2280 100644 --- a/linux-user/ppc/target_syscall.h +++ b/linux-user/ppc/target_syscall.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 diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 208c63eb2a..f09b750bbf 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -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); diff --git a/linux-user/s390x/target_signal.h b/linux-user/s390x/target_signal.h index b4816b040f..a6fb2873a3 100644 --- a/linux-user/s390x/target_signal.h +++ b/linux-user/s390x/target_signal.h @@ -23,4 +23,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUS390XState *state) return state->regs[15]; } + #endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/safe-syscall.S b/linux-user/safe-syscall.S new file mode 100644 index 0000000000..b5df6254ae --- /dev/null +++ b/linux-user/safe-syscall.S @@ -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 diff --git a/linux-user/sh4/target_signal.h b/linux-user/sh4/target_signal.h index e148da0925..f9911aa7f2 100644 --- a/linux-user/sh4/target_signal.h +++ b/linux-user/sh4/target_signal.h @@ -26,4 +26,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUSH4State *state) return state->gregs[15]; } + #endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/signal.c b/linux-user/signal.c index 96e86c0a29..8090b4de1f 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -157,7 +157,7 @@ static void target_to_host_sigset_internal(sigset_t *d, if (target_sigismember(s, i)) { sigaddset(d, target_to_host_signal(i)); } - } + } } void target_to_host_sigset(sigset_t *d, const target_sigset_t *s) @@ -250,18 +250,18 @@ static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo, tinfo->si_code = info->si_code; if (sig == TARGET_SIGILL || sig == TARGET_SIGFPE || sig == TARGET_SIGSEGV - || sig == TARGET_SIGBUS || sig == TARGET_SIGTRAP) { + || sig == TARGET_SIGBUS || sig == TARGET_SIGTRAP) { /* Should never come here, but who knows. The information for the target is irrelevant. */ tinfo->_sifields._sigfault._addr = 0; } else if (sig == TARGET_SIGIO) { tinfo->_sifields._sigpoll._band = info->si_band; - tinfo->_sifields._sigpoll._fd = info->si_fd; + tinfo->_sifields._sigpoll._fd = info->si_fd; } else if (sig == TARGET_SIGCHLD) { tinfo->_sifields._sigchld._pid = info->si_pid; tinfo->_sifields._sigchld._uid = info->si_uid; tinfo->_sifields._sigchld._status - = host_to_target_waitstatus(info->si_status); + = host_to_target_waitstatus(info->si_status); tinfo->_sifields._sigchld._utime = info->si_utime; tinfo->_sifields._sigchld._stime = info->si_stime; } else if (sig >= TARGET_SIGRTMIN) { @@ -269,7 +269,7 @@ static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo, tinfo->_sifields._rt._uid = info->si_uid; /* XXX: potential problem if 64 bit */ tinfo->_sifields._rt._sigval.sival_ptr - = (abi_ulong)(unsigned long)info->si_value.sival_ptr; + = (abi_ulong)(unsigned long)info->si_value.sival_ptr; } } @@ -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 */ @@ -723,75 +733,75 @@ int do_sigaction(int sig, const struct target_sigaction *act, /* from the Linux kernel */ struct target_fpreg { - uint16_t significand[4]; - uint16_t exponent; + uint16_t significand[4]; + uint16_t exponent; }; struct target_fpxreg { - uint16_t significand[4]; - uint16_t exponent; - uint16_t padding[3]; + uint16_t significand[4]; + uint16_t exponent; + uint16_t padding[3]; }; struct target_xmmreg { - abi_ulong element[4]; + abi_ulong element[4]; }; struct target_fpstate { - /* Regular FPU environment */ - abi_ulong cw; - abi_ulong sw; - abi_ulong tag; - abi_ulong ipoff; - abi_ulong cssel; - abi_ulong dataoff; - abi_ulong datasel; - struct target_fpreg _st[8]; - uint16_t status; - uint16_t magic; /* 0xffff = regular FPU data only */ - - /* FXSR FPU environment */ - abi_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */ - abi_ulong mxcsr; - abi_ulong reserved; - struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */ - struct target_xmmreg _xmm[8]; - abi_ulong padding[56]; + /* Regular FPU environment */ + abi_ulong cw; + abi_ulong sw; + abi_ulong tag; + abi_ulong ipoff; + abi_ulong cssel; + abi_ulong dataoff; + abi_ulong datasel; + struct target_fpreg _st[8]; + uint16_t status; + uint16_t magic; /* 0xffff = regular FPU data only */ + + /* FXSR FPU environment */ + abi_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */ + abi_ulong mxcsr; + abi_ulong reserved; + struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */ + struct target_xmmreg _xmm[8]; + abi_ulong padding[56]; }; #define X86_FXSR_MAGIC 0x0000 struct target_sigcontext { - uint16_t gs, __gsh; - uint16_t fs, __fsh; - uint16_t es, __esh; - uint16_t ds, __dsh; - abi_ulong edi; - abi_ulong esi; - abi_ulong ebp; - abi_ulong esp; - abi_ulong ebx; - abi_ulong edx; - abi_ulong ecx; - abi_ulong eax; - abi_ulong trapno; - abi_ulong err; - abi_ulong eip; - uint16_t cs, __csh; - abi_ulong eflags; - abi_ulong esp_at_signal; - uint16_t ss, __ssh; - abi_ulong fpstate; /* pointer */ - abi_ulong oldmask; - abi_ulong cr2; + uint16_t gs, __gsh; + uint16_t fs, __fsh; + uint16_t es, __esh; + uint16_t ds, __dsh; + abi_ulong edi; + abi_ulong esi; + abi_ulong ebp; + abi_ulong esp; + abi_ulong ebx; + abi_ulong edx; + abi_ulong ecx; + abi_ulong eax; + abi_ulong trapno; + abi_ulong err; + abi_ulong eip; + uint16_t cs, __csh; + abi_ulong eflags; + abi_ulong esp_at_signal; + uint16_t ss, __ssh; + abi_ulong fpstate; /* pointer */ + abi_ulong oldmask; + abi_ulong cr2; }; struct target_ucontext { - abi_ulong tuc_flags; - abi_ulong tuc_link; - target_stack_t tuc_stack; - struct target_sigcontext tuc_mcontext; - target_sigset_t tuc_sigmask; /* mask last for extensibility */ + abi_ulong tuc_flags; + abi_ulong tuc_link; + target_stack_t tuc_stack; + struct target_sigcontext tuc_mcontext; + target_sigset_t tuc_sigmask; /* mask last for extensibility */ }; struct sigframe @@ -828,7 +838,7 @@ static void setup_sigcontext(struct target_sigcontext *sc, CPUState *cs = CPU(x86_env_get_cpu(env)); uint16_t magic; - /* already locked in setup_frame() */ + /* already locked in setup_frame() */ __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs); __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs); __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es); @@ -849,13 +859,13 @@ static void setup_sigcontext(struct target_sigcontext *sc, __put_user(env->regs[R_ESP], &sc->esp_at_signal); __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss); - cpu_x86_fsave(env, fpstate_addr, 1); - fpstate->status = fpstate->sw; - magic = 0xffff; + cpu_x86_fsave(env, fpstate_addr, 1); + fpstate->status = fpstate->sw; + magic = 0xffff; __put_user(magic, &fpstate->magic); __put_user(fpstate_addr, &sc->fpstate); - /* non-iBCS2 extensions.. */ + /* non-iBCS2 extensions.. */ __put_user(mask, &sc->oldmask); __put_user(env->cr[2], &sc->cr2); } @@ -867,110 +877,112 @@ static void setup_sigcontext(struct target_sigcontext *sc, static inline abi_ulong get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size) { - unsigned long esp; + unsigned long esp; - /* Default to using normal stack */ - 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) - esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; + /* Default to using normal stack */ + 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) { + esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; } + } else { - /* This is the legacy signal stack switching. */ - else + /* This is the legacy signal stack switching. */ if ((env->segs[R_SS].selector & 0xffff) != __USER_DS && - !(ka->sa_flags & TARGET_SA_RESTORER) && - ka->sa_restorer) { + !(ka->sa_flags & TARGET_SA_RESTORER) && + ka->sa_restorer) { esp = (unsigned long) ka->sa_restorer; - } - return (esp - frame_size) & -8ul; + } + } + return (esp - frame_size) & -8ul; } /* compare linux/arch/i386/kernel/signal.c:setup_frame() */ static void setup_frame(int sig, struct target_sigaction *ka, - target_sigset_t *set, CPUX86State *env) + target_sigset_t *set, CPUX86State *env) { - abi_ulong frame_addr; - struct sigframe *frame; - int i; + abi_ulong frame_addr; + struct sigframe *frame; + int i; - frame_addr = get_sigframe(ka, env, sizeof(*frame)); - trace_user_setup_frame(env, frame_addr); + 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)) - goto give_sigsegv; + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) + goto give_sigsegv; __put_user(sig, &frame->sig); - setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0], - frame_addr + offsetof(struct sigframe, fpstate)); + setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0], + frame_addr + offsetof(struct sigframe, fpstate)); for(i = 1; i < TARGET_NSIG_WORDS; i++) { __put_user(set->sig[i], &frame->extramask[i - 1]); } - /* Set up to return from userspace. If provided, use a stub - already in userspace. */ - if (ka->sa_flags & TARGET_SA_RESTORER) { + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + if (ka->sa_flags & TARGET_SA_RESTORER) { __put_user(ka->sa_restorer, &frame->pretcode); - } else { - uint16_t val16; - abi_ulong retcode_addr; - retcode_addr = frame_addr + offsetof(struct sigframe, retcode); + } else { + uint16_t val16; + abi_ulong retcode_addr; + retcode_addr = frame_addr + offsetof(struct sigframe, retcode); __put_user(retcode_addr, &frame->pretcode); - /* This is popl %eax ; movl $,%eax ; int $0x80 */ - val16 = 0xb858; + /* This is popl %eax ; movl $,%eax ; int $0x80 */ + val16 = 0xb858; __put_user(val16, (uint16_t *)(frame->retcode+0)); __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2)); - val16 = 0x80cd; + val16 = 0x80cd; __put_user(val16, (uint16_t *)(frame->retcode+6)); - } + } - /* Set up registers for signal handler */ - env->regs[R_ESP] = frame_addr; - env->eip = ka->_sa_handler; + /* Set up registers for signal handler */ + env->regs[R_ESP] = frame_addr; + env->eip = ka->_sa_handler; - cpu_x86_load_seg(env, R_DS, __USER_DS); - cpu_x86_load_seg(env, R_ES, __USER_DS); - cpu_x86_load_seg(env, R_SS, __USER_DS); - cpu_x86_load_seg(env, R_CS, __USER_CS); - env->eflags &= ~TF_MASK; + cpu_x86_load_seg(env, R_DS, __USER_DS); + cpu_x86_load_seg(env, R_ES, __USER_DS); + cpu_x86_load_seg(env, R_SS, __USER_DS); + cpu_x86_load_seg(env, R_CS, __USER_CS); + env->eflags &= ~TF_MASK; - unlock_user_struct(frame, frame_addr, 1); + unlock_user_struct(frame, frame_addr, 1); - return; + return; give_sigsegv: - if (sig == TARGET_SIGSEGV) - ka->_sa_handler = TARGET_SIG_DFL; - force_sig(TARGET_SIGSEGV /* , current */); + if (sig == TARGET_SIGSEGV) { + ka->_sa_handler = TARGET_SIG_DFL; + } + force_sig(TARGET_SIGSEGV /* , current */); } /* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */ static void setup_rt_frame(int sig, struct target_sigaction *ka, target_siginfo_t *info, - target_sigset_t *set, CPUX86State *env) + target_sigset_t *set, CPUX86State *env) { - abi_ulong frame_addr, addr; - struct rt_sigframe *frame; - int i; + abi_ulong frame_addr, addr; + struct rt_sigframe *frame; + int i; - frame_addr = get_sigframe(ka, env, sizeof(*frame)); - trace_user_setup_rt_frame(env, frame_addr); + 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)) - goto give_sigsegv; + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) + goto give_sigsegv; __put_user(sig, &frame->sig); - addr = frame_addr + offsetof(struct rt_sigframe, info); + addr = frame_addr + offsetof(struct rt_sigframe, info); __put_user(addr, &frame->pinfo); - addr = frame_addr + offsetof(struct rt_sigframe, uc); + addr = frame_addr + offsetof(struct rt_sigframe, uc); __put_user(addr, &frame->puc); tswap_siginfo(&frame->info, info); - /* Create the ucontext. */ + /* Create the ucontext. */ __put_user(0, &frame->uc.tuc_flags); __put_user(0, &frame->uc.tuc_link); __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp); @@ -985,81 +997,82 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]); } - /* Set up to return from userspace. If provided, use a stub - already in userspace. */ - if (ka->sa_flags & TARGET_SA_RESTORER) { + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + if (ka->sa_flags & TARGET_SA_RESTORER) { __put_user(ka->sa_restorer, &frame->pretcode); - } else { - uint16_t val16; - addr = frame_addr + offsetof(struct rt_sigframe, retcode); + } else { + uint16_t val16; + addr = frame_addr + offsetof(struct rt_sigframe, retcode); __put_user(addr, &frame->pretcode); - /* This is movl $,%eax ; int $0x80 */ + /* This is movl $,%eax ; int $0x80 */ __put_user(0xb8, (char *)(frame->retcode+0)); __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1)); - val16 = 0x80cd; + val16 = 0x80cd; __put_user(val16, (uint16_t *)(frame->retcode+5)); - } + } - /* Set up registers for signal handler */ - env->regs[R_ESP] = frame_addr; - env->eip = ka->_sa_handler; + /* Set up registers for signal handler */ + env->regs[R_ESP] = frame_addr; + env->eip = ka->_sa_handler; - cpu_x86_load_seg(env, R_DS, __USER_DS); - cpu_x86_load_seg(env, R_ES, __USER_DS); - cpu_x86_load_seg(env, R_SS, __USER_DS); - cpu_x86_load_seg(env, R_CS, __USER_CS); - env->eflags &= ~TF_MASK; + cpu_x86_load_seg(env, R_DS, __USER_DS); + cpu_x86_load_seg(env, R_ES, __USER_DS); + cpu_x86_load_seg(env, R_SS, __USER_DS); + cpu_x86_load_seg(env, R_CS, __USER_CS); + env->eflags &= ~TF_MASK; - unlock_user_struct(frame, frame_addr, 1); + unlock_user_struct(frame, frame_addr, 1); - return; + return; give_sigsegv: - if (sig == TARGET_SIGSEGV) - ka->_sa_handler = TARGET_SIG_DFL; - force_sig(TARGET_SIGSEGV /* , current */); + 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) -{ - unsigned int err = 0; - abi_ulong fpstate_addr; - unsigned int tmpflags; - - cpu_x86_load_seg(env, R_GS, tswap16(sc->gs)); - cpu_x86_load_seg(env, R_FS, tswap16(sc->fs)); - cpu_x86_load_seg(env, R_ES, tswap16(sc->es)); - cpu_x86_load_seg(env, R_DS, tswap16(sc->ds)); - - env->regs[R_EDI] = tswapl(sc->edi); - env->regs[R_ESI] = tswapl(sc->esi); - env->regs[R_EBP] = tswapl(sc->ebp); - env->regs[R_ESP] = tswapl(sc->esp); - env->regs[R_EBX] = tswapl(sc->ebx); - env->regs[R_EDX] = tswapl(sc->edx); - env->regs[R_ECX] = tswapl(sc->ecx); - env->eip = tswapl(sc->eip); - - cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3); - cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3); - - tmpflags = tswapl(sc->eflags); - env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5); - // regs->orig_eax = -1; /* disable syscall checks */ - - fpstate_addr = tswapl(sc->fpstate); - if (fpstate_addr != 0) { - if (!access_ok(VERIFY_READ, fpstate_addr, - sizeof(struct target_fpstate))) - goto badframe; - cpu_x86_frstor(env, fpstate_addr, 1); - } +restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc) +{ + unsigned int err = 0; + abi_ulong fpstate_addr; + unsigned int tmpflags; + + cpu_x86_load_seg(env, R_GS, tswap16(sc->gs)); + cpu_x86_load_seg(env, R_FS, tswap16(sc->fs)); + cpu_x86_load_seg(env, R_ES, tswap16(sc->es)); + cpu_x86_load_seg(env, R_DS, tswap16(sc->ds)); + + env->regs[R_EDI] = tswapl(sc->edi); + env->regs[R_ESI] = tswapl(sc->esi); + env->regs[R_EBP] = tswapl(sc->ebp); + env->regs[R_ESP] = tswapl(sc->esp); + 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); + cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3); + + tmpflags = tswapl(sc->eflags); + env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5); + // regs->orig_eax = -1; /* disable syscall checks */ + + fpstate_addr = tswapl(sc->fpstate); + if (fpstate_addr != 0) { + if (!access_ok(VERIFY_READ, fpstate_addr, + sizeof(struct target_fpstate))) + goto badframe; + cpu_x86_frstor(env, fpstate_addr, 1); + } - *peax = tswapl(sc->eax); - return err; + return err; badframe: - return 1; + return 1; } long do_sigreturn(CPUX86State *env) @@ -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); @@ -1096,32 +1109,33 @@ badframe: long do_rt_sigreturn(CPUX86State *env) { - abi_ulong frame_addr; - struct rt_sigframe *frame; - sigset_t set; - int eax; + abi_ulong frame_addr; + struct rt_sigframe *frame; + sigset_t set; - frame_addr = env->regs[R_ESP] - 4; - trace_user_do_rt_sigreturn(env, frame_addr); - if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) - goto badframe; - target_to_host_sigset(&set, &frame->uc.tuc_sigmask); - do_sigprocmask(SIG_SETMASK, &set, NULL); + frame_addr = env->regs[R_ESP] - 4; + trace_user_do_rt_sigreturn(env, frame_addr); + if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) + goto badframe; + target_to_host_sigset(&set, &frame->uc.tuc_sigmask); + do_sigprocmask(SIG_SETMASK, &set, NULL); - if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax)) - goto badframe; + 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) - goto badframe; + if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0, + get_sp_from_cpustate(env)) == -EFAULT) { + goto badframe; + } - unlock_user_struct(frame, frame_addr, 0); - return eax; + unlock_user_struct(frame, frame_addr, 0); + return -TARGET_QEMU_ESIGRETURN; badframe: - unlock_user_struct(frame, frame_addr, 0); - force_sig(TARGET_SIGSEGV); - return 0; + unlock_user_struct(frame, frame_addr, 0); + force_sig(TARGET_SIGSEGV); + return 0; } #elif defined(TARGET_AARCH64) @@ -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); @@ -1402,27 +1416,27 @@ long do_sigreturn(CPUARMState *env) #elif defined(TARGET_ARM) struct target_sigcontext { - abi_ulong trap_no; - abi_ulong error_code; - abi_ulong oldmask; - abi_ulong arm_r0; - abi_ulong arm_r1; - abi_ulong arm_r2; - abi_ulong arm_r3; - abi_ulong arm_r4; - abi_ulong arm_r5; - abi_ulong arm_r6; - abi_ulong arm_r7; - abi_ulong arm_r8; - abi_ulong arm_r9; - abi_ulong arm_r10; - abi_ulong arm_fp; - abi_ulong arm_ip; - abi_ulong arm_sp; - abi_ulong arm_lr; - abi_ulong arm_pc; - abi_ulong arm_cpsr; - abi_ulong fault_address; + abi_ulong trap_no; + abi_ulong error_code; + abi_ulong oldmask; + abi_ulong arm_r0; + abi_ulong arm_r1; + abi_ulong arm_r2; + abi_ulong arm_r3; + abi_ulong arm_r4; + abi_ulong arm_r5; + abi_ulong arm_r6; + abi_ulong arm_r7; + abi_ulong arm_r8; + abi_ulong arm_r9; + abi_ulong arm_r10; + abi_ulong arm_fp; + abi_ulong arm_ip; + abi_ulong arm_sp; + abi_ulong arm_lr; + abi_ulong arm_pc; + abi_ulong arm_cpsr; + abi_ulong fault_address; }; struct target_ucontext_v1 { @@ -1581,7 +1595,7 @@ get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize) static void setup_return(CPUARMState *env, struct target_sigaction *ka, - abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr) + abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr) { abi_ulong handler = ka->_sa_handler; abi_ulong retcode; @@ -1691,42 +1705,44 @@ static void setup_sigframe_v2(struct target_ucontext_v2 *uc, static void setup_frame_v1(int usig, struct target_sigaction *ka, target_sigset_t *set, CPUARMState *regs) { - struct sigframe_v1 *frame; - abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame)); - int i; + struct sigframe_v1 *frame; + abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame)); + int i; - trace_user_setup_frame(regs, frame_addr); - if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) - return; + trace_user_setup_frame(regs, frame_addr); + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { + return; + } - setup_sigcontext(&frame->sc, regs, set->sig[0]); + setup_sigcontext(&frame->sc, regs, set->sig[0]); for(i = 1; i < TARGET_NSIG_WORDS; i++) { __put_user(set->sig[i], &frame->extramask[i - 1]); } - setup_return(regs, ka, &frame->retcode, frame_addr, usig, - frame_addr + offsetof(struct sigframe_v1, retcode)); + setup_return(regs, ka, &frame->retcode, frame_addr, usig, + frame_addr + offsetof(struct sigframe_v1, retcode)); - unlock_user_struct(frame, frame_addr, 1); + unlock_user_struct(frame, frame_addr, 1); } static void setup_frame_v2(int usig, struct target_sigaction *ka, target_sigset_t *set, CPUARMState *regs) { - struct sigframe_v2 *frame; - abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame)); + struct sigframe_v2 *frame; + 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)) - return; + trace_user_setup_frame(regs, frame_addr); + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { + return; + } - setup_sigframe_v2(&frame->uc, set, regs); + setup_sigframe_v2(&frame->uc, set, regs); - setup_return(regs, ka, &frame->retcode, frame_addr, usig, - frame_addr + offsetof(struct sigframe_v2, retcode)); + setup_return(regs, ka, &frame->retcode, frame_addr, usig, + frame_addr + offsetof(struct sigframe_v2, retcode)); - unlock_user_struct(frame, frame_addr, 1); + unlock_user_struct(frame, frame_addr, 1); } static void setup_frame(int usig, struct target_sigaction *ka, @@ -1744,70 +1760,72 @@ static void setup_rt_frame_v1(int usig, struct target_sigaction *ka, target_siginfo_t *info, target_sigset_t *set, CPUARMState *env) { - struct rt_sigframe_v1 *frame; - abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame)); - struct target_sigaltstack stack; - int i; - abi_ulong info_addr, uc_addr; + struct rt_sigframe_v1 *frame; + abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame)); + struct target_sigaltstack stack; + int i; + abi_ulong info_addr, uc_addr; - trace_user_setup_rt_frame(env, frame_addr); - if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) - return /* 1 */; + trace_user_setup_rt_frame(env, frame_addr); + 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); - uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc); - __put_user(uc_addr, &frame->puc); - tswap_siginfo(&frame->info, info); + info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info); + __put_user(info_addr, &frame->pinfo); + uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc); + __put_user(uc_addr, &frame->puc); + tswap_siginfo(&frame->info, info); - /* Clear all the bits of the ucontext we don't use. */ - memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext)); + /* Clear all the bits of the ucontext we don't use. */ + memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext)); - memset(&stack, 0, sizeof(stack)); - __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp); - __put_user(target_sigaltstack_used.ss_size, &stack.ss_size); - __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags); - memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack)); + memset(&stack, 0, sizeof(stack)); + __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp); + __put_user(target_sigaltstack_used.ss_size, &stack.ss_size); + __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags); + memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack)); - setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]); - for(i = 0; i < TARGET_NSIG_WORDS; i++) { - __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]); - } + setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]); + for(i = 0; i < TARGET_NSIG_WORDS; i++) { + __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]); + } - setup_return(env, ka, &frame->retcode, frame_addr, usig, - frame_addr + offsetof(struct rt_sigframe_v1, retcode)); + setup_return(env, ka, &frame->retcode, frame_addr, usig, + frame_addr + offsetof(struct rt_sigframe_v1, retcode)); - env->regs[1] = info_addr; - env->regs[2] = uc_addr; + env->regs[1] = info_addr; + env->regs[2] = uc_addr; - unlock_user_struct(frame, frame_addr, 1); + unlock_user_struct(frame, frame_addr, 1); } static void setup_rt_frame_v2(int usig, struct target_sigaction *ka, target_siginfo_t *info, target_sigset_t *set, CPUARMState *env) { - struct rt_sigframe_v2 *frame; - abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame)); - abi_ulong info_addr, uc_addr; + struct rt_sigframe_v2 *frame; + abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame)); + abi_ulong info_addr, uc_addr; - trace_user_setup_rt_frame(env, frame_addr); - if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) - return /* 1 */; + trace_user_setup_rt_frame(env, frame_addr); + 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); - tswap_siginfo(&frame->info, info); + info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info); + uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc); + tswap_siginfo(&frame->info, info); - setup_sigframe_v2(&frame->uc, set, env); + setup_sigframe_v2(&frame->uc, set, env); - setup_return(env, ka, &frame->retcode, frame_addr, usig, - frame_addr + offsetof(struct rt_sigframe_v2, retcode)); + setup_return(env, ka, &frame->retcode, frame_addr, usig, + frame_addr + offsetof(struct rt_sigframe_v2, retcode)); - env->regs[1] = info_addr; - env->regs[2] = uc_addr; + env->regs[1] = info_addr; + env->regs[2] = uc_addr; - unlock_user_struct(frame, frame_addr, 1); + unlock_user_struct(frame, frame_addr, 1); } static void setup_rt_frame(int usig, struct target_sigaction *ka, @@ -1824,8 +1842,8 @@ static void setup_rt_frame(int usig, struct target_sigaction *ka, static int restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc) { - int err = 0; - uint32_t cpsr; + int err = 0; + uint32_t cpsr; __get_user(env->regs[0], &sc->arm_r0); __get_user(env->regs[1], &sc->arm_r1); @@ -1848,55 +1866,57 @@ restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc) cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC, CPSRWriteByInstr); #endif - err |= !valid_user_regs(env); + err |= !valid_user_regs(env); - return err; + return err; } static long do_sigreturn_v1(CPUARMState *env) { - abi_ulong frame_addr; - struct sigframe_v1 *frame = NULL; - target_sigset_t set; - sigset_t host_set; - int i; - - /* - * Since we stacked the signal on a 64-bit boundary, - * then 'sp' should be word aligned here. If it's - * not, then the user is trying to mess with us. - */ - frame_addr = env->regs[13]; - trace_user_do_sigreturn(env, frame_addr); - if (frame_addr & 7) { - goto badframe; - } + abi_ulong frame_addr; + struct sigframe_v1 *frame = NULL; + target_sigset_t set; + sigset_t host_set; + int i; - if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) - goto badframe; + /* + * Since we stacked the signal on a 64-bit boundary, + * then 'sp' should be word aligned here. If it's + * not, then the user is trying to mess with us. + */ + frame_addr = env->regs[13]; + trace_user_do_sigreturn(env, frame_addr); + if (frame_addr & 7) { + goto badframe; + } + + 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++) { __get_user(set.sig[i], &frame->extramask[i - 1]); } - target_to_host_sigset_internal(&host_set, &set); - do_sigprocmask(SIG_SETMASK, &host_set, NULL); + target_to_host_sigset_internal(&host_set, &set); + do_sigprocmask(SIG_SETMASK, &host_set, NULL); - if (restore_sigcontext(env, &frame->sc)) - goto badframe; + if (restore_sigcontext(env, &frame->sc)) { + goto badframe; + } #if 0 - /* Send SIGTRAP if we're single-stepping */ - if (ptrace_cancel_bpt(current)) - send_sig(SIGTRAP, current, 1); + /* Send SIGTRAP if we're single-stepping */ + if (ptrace_cancel_bpt(current)) + send_sig(SIGTRAP, current, 1); #endif - unlock_user_struct(frame, frame_addr, 0); - return env->regs[0]; + unlock_user_struct(frame, frame_addr, 0); + return -TARGET_QEMU_ESIGRETURN; badframe: - force_sig(TARGET_SIGSEGV /* , current */); - return 0; + force_sig(TARGET_SIGSEGV /* , current */); + return 0; } static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace) @@ -1987,7 +2007,7 @@ static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr, #if 0 /* Send SIGTRAP if we're single-stepping */ if (ptrace_cancel_bpt(current)) - send_sig(SIGTRAP, current, 1); + send_sig(SIGTRAP, current, 1); #endif return 0; @@ -1995,33 +2015,35 @@ static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr, static long do_sigreturn_v2(CPUARMState *env) { - abi_ulong frame_addr; - struct sigframe_v2 *frame = NULL; - - /* - * Since we stacked the signal on a 64-bit boundary, - * then 'sp' should be word aligned here. If it's - * not, then the user is trying to mess with us. - */ - frame_addr = env->regs[13]; - trace_user_do_sigreturn(env, frame_addr); - if (frame_addr & 7) { - goto badframe; - } + abi_ulong frame_addr; + struct sigframe_v2 *frame = NULL; - if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) - goto badframe; + /* + * Since we stacked the signal on a 64-bit boundary, + * then 'sp' should be word aligned here. If it's + * not, then the user is trying to mess with us. + */ + frame_addr = env->regs[13]; + trace_user_do_sigreturn(env, frame_addr); + if (frame_addr & 7) { + goto badframe; + } + + if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { + goto badframe; + } - if (do_sigframe_return_v2(env, frame_addr, &frame->uc)) - goto badframe; + if (do_sigframe_return_v2(env, frame_addr, &frame->uc)) { + goto badframe; + } - unlock_user_struct(frame, frame_addr, 0); - return env->regs[0]; + unlock_user_struct(frame, frame_addr, 0); + return -TARGET_QEMU_ESIGRETURN; badframe: - unlock_user_struct(frame, frame_addr, 0); - force_sig(TARGET_SIGSEGV /* , current */); - return 0; + unlock_user_struct(frame, frame_addr, 0); + force_sig(TARGET_SIGSEGV /* , current */); + return 0; } long do_sigreturn(CPUARMState *env) @@ -2035,76 +2057,80 @@ long do_sigreturn(CPUARMState *env) static long do_rt_sigreturn_v1(CPUARMState *env) { - abi_ulong frame_addr; - struct rt_sigframe_v1 *frame = NULL; - sigset_t host_set; - - /* - * Since we stacked the signal on a 64-bit boundary, - * then 'sp' should be word aligned here. If it's - * not, then the user is trying to mess with us. - */ - frame_addr = env->regs[13]; - trace_user_do_rt_sigreturn(env, frame_addr); - if (frame_addr & 7) { - goto badframe; - } + abi_ulong frame_addr; + struct rt_sigframe_v1 *frame = NULL; + sigset_t host_set; + + /* + * Since we stacked the signal on a 64-bit boundary, + * then 'sp' should be word aligned here. If it's + * not, then the user is trying to mess with us. + */ + frame_addr = env->regs[13]; + trace_user_do_rt_sigreturn(env, frame_addr); + if (frame_addr & 7) { + goto badframe; + } - if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) - goto badframe; + 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); + 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)) - goto badframe; + 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; + if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe_v1, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) + goto badframe; #if 0 - /* Send SIGTRAP if we're single-stepping */ - if (ptrace_cancel_bpt(current)) - send_sig(SIGTRAP, current, 1); + /* Send SIGTRAP if we're single-stepping */ + if (ptrace_cancel_bpt(current)) + send_sig(SIGTRAP, current, 1); #endif - unlock_user_struct(frame, frame_addr, 0); - return env->regs[0]; + unlock_user_struct(frame, frame_addr, 0); + return -TARGET_QEMU_ESIGRETURN; badframe: - unlock_user_struct(frame, frame_addr, 0); - force_sig(TARGET_SIGSEGV /* , current */); - return 0; + unlock_user_struct(frame, frame_addr, 0); + force_sig(TARGET_SIGSEGV /* , current */); + return 0; } static long do_rt_sigreturn_v2(CPUARMState *env) { - abi_ulong frame_addr; - struct rt_sigframe_v2 *frame = NULL; - - /* - * Since we stacked the signal on a 64-bit boundary, - * then 'sp' should be word aligned here. If it's - * not, then the user is trying to mess with us. - */ - frame_addr = env->regs[13]; - trace_user_do_rt_sigreturn(env, frame_addr); - if (frame_addr & 7) { - goto badframe; - } + abi_ulong frame_addr; + struct rt_sigframe_v2 *frame = NULL; - if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) - goto badframe; + /* + * Since we stacked the signal on a 64-bit boundary, + * then 'sp' should be word aligned here. If it's + * not, then the user is trying to mess with us. + */ + frame_addr = env->regs[13]; + trace_user_do_rt_sigreturn(env, frame_addr); + if (frame_addr & 7) { + goto badframe; + } - if (do_sigframe_return_v2(env, frame_addr, &frame->uc)) - goto badframe; + if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { + goto badframe; + } - unlock_user_struct(frame, frame_addr, 0); - return env->regs[0]; + if (do_sigframe_return_v2(env, frame_addr, &frame->uc)) { + goto badframe; + } + + unlock_user_struct(frame, frame_addr, 0); + return -TARGET_QEMU_ESIGRETURN; badframe: - unlock_user_struct(frame, frame_addr, 0); - force_sig(TARGET_SIGSEGV /* , current */); - return 0; + unlock_user_struct(frame, frame_addr, 0); + force_sig(TARGET_SIGSEGV /* , current */); + return 0; } long do_rt_sigreturn(CPUARMState *env) @@ -2122,83 +2148,83 @@ long do_rt_sigreturn(CPUARMState *env) /* This is what SunOS does, so shall I. */ struct target_sigcontext { - abi_ulong sigc_onstack; /* state to restore */ + abi_ulong sigc_onstack; /* state to restore */ - abi_ulong sigc_mask; /* sigmask to restore */ - abi_ulong sigc_sp; /* stack pointer */ - abi_ulong sigc_pc; /* program counter */ - abi_ulong sigc_npc; /* next program counter */ - abi_ulong sigc_psr; /* for condition codes etc */ - abi_ulong sigc_g1; /* User uses these two registers */ - abi_ulong sigc_o0; /* within the trampoline code. */ + abi_ulong sigc_mask; /* sigmask to restore */ + abi_ulong sigc_sp; /* stack pointer */ + abi_ulong sigc_pc; /* program counter */ + abi_ulong sigc_npc; /* next program counter */ + abi_ulong sigc_psr; /* for condition codes etc */ + abi_ulong sigc_g1; /* User uses these two registers */ + abi_ulong sigc_o0; /* within the trampoline code. */ - /* Now comes information regarding the users window set + /* Now comes information regarding the users window set * at the time of the signal. */ - abi_ulong sigc_oswins; /* outstanding windows */ + abi_ulong sigc_oswins; /* outstanding windows */ - /* stack ptrs for each regwin buf */ - char *sigc_spbuf[__SUNOS_MAXWIN]; + /* stack ptrs for each regwin buf */ + char *sigc_spbuf[__SUNOS_MAXWIN]; - /* Windows to restore after signal */ - struct { - abi_ulong locals[8]; - abi_ulong ins[8]; - } sigc_wbuf[__SUNOS_MAXWIN]; + /* Windows to restore after signal */ + struct { + abi_ulong locals[8]; + abi_ulong ins[8]; + } sigc_wbuf[__SUNOS_MAXWIN]; }; /* A Sparc stack frame */ struct sparc_stackf { - abi_ulong locals[8]; - abi_ulong ins[8]; - /* It's simpler to treat fp and callers_pc as elements of ins[] + abi_ulong locals[8]; + abi_ulong ins[8]; + /* It's simpler to treat fp and callers_pc as elements of ins[] * since we never need to access them ourselves. */ - char *structptr; - abi_ulong xargs[6]; - abi_ulong xxargs[1]; + char *structptr; + abi_ulong xargs[6]; + abi_ulong xxargs[1]; }; typedef struct { - struct { - abi_ulong psr; - abi_ulong pc; - abi_ulong npc; - abi_ulong y; - abi_ulong u_regs[16]; /* globals and ins */ - } si_regs; - int si_mask; + struct { + abi_ulong psr; + abi_ulong pc; + abi_ulong npc; + abi_ulong y; + abi_ulong u_regs[16]; /* globals and ins */ + } si_regs; + int si_mask; } __siginfo_t; typedef struct { - abi_ulong si_float_regs[32]; - unsigned long si_fsr; - unsigned long si_fpqdepth; - struct { - unsigned long *insn_addr; - unsigned long insn; - } si_fpqueue [16]; + abi_ulong si_float_regs[32]; + unsigned long si_fsr; + unsigned long si_fpqdepth; + struct { + unsigned long *insn_addr; + unsigned long insn; + } si_fpqueue [16]; } qemu_siginfo_fpu_t; struct target_signal_frame { - struct sparc_stackf ss; - __siginfo_t info; - abi_ulong fpu_save; - abi_ulong insns[2] __attribute__ ((aligned (8))); - abi_ulong extramask[TARGET_NSIG_WORDS - 1]; - abi_ulong extra_size; /* Should be 0 */ - qemu_siginfo_fpu_t fpu_state; + struct sparc_stackf ss; + __siginfo_t info; + abi_ulong fpu_save; + abi_ulong insns[2] __attribute__ ((aligned (8))); + abi_ulong extramask[TARGET_NSIG_WORDS - 1]; + abi_ulong extra_size; /* Should be 0 */ + qemu_siginfo_fpu_t fpu_state; }; struct target_rt_signal_frame { - struct sparc_stackf ss; - siginfo_t info; - abi_ulong regs[20]; - sigset_t mask; - abi_ulong fpu_save; - unsigned int insns[2]; - stack_t stack; - unsigned int extra_size; /* Should be 0 */ - qemu_siginfo_fpu_t fpu_state; + struct sparc_stackf ss; + siginfo_t info; + abi_ulong regs[20]; + sigset_t mask; + abi_ulong fpu_save; + unsigned int insns[2]; + stack_t stack; + unsigned int extra_size; /* Should be 0 */ + qemu_siginfo_fpu_t fpu_state; }; #define UREG_O0 16 @@ -2219,36 +2245,37 @@ static inline abi_ulong get_sigframe(struct target_sigaction *sa, CPUSPARCState *env, unsigned long framesize) { - abi_ulong sp; + abi_ulong sp; - sp = env->regwptr[UREG_FP]; + sp = env->regwptr[UREG_FP]; - /* 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)) - sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; - } - return sp - framesize; + /* 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)) { + sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; + } + } + return sp - framesize; } static int setup___siginfo(__siginfo_t *si, CPUSPARCState *env, abi_ulong mask) { - int err = 0, i; + int err = 0, i; __put_user(env->psr, &si->si_regs.psr); __put_user(env->pc, &si->si_regs.pc); __put_user(env->npc, &si->si_regs.npc); __put_user(env->y, &si->si_regs.y); - for (i=0; i < 8; i++) { + for (i=0; i < 8; i++) { __put_user(env->gregs[i], &si->si_regs.u_regs[i]); - } - for (i=0; i < 8; i++) { + } + for (i=0; i < 8; i++) { __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]); - } + } __put_user(mask, &si->si_mask); - return err; + return err; } #if 0 @@ -2256,7 +2283,7 @@ static int setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/ CPUSPARCState *env, unsigned long mask) { - int err = 0; + int err = 0; __put_user(mask, &sc->sigc_mask); __put_user(env->regwptr[UREG_SP], &sc->sigc_sp); @@ -2266,7 +2293,7 @@ setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/ __put_user(env->gregs[1], &sc->sigc_g1); __put_user(env->regwptr[UREG_O0], &sc->sigc_o0); - return err; + return err; } #endif #define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7))) @@ -2274,90 +2301,90 @@ setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/ static void setup_frame(int sig, struct target_sigaction *ka, target_sigset_t *set, CPUSPARCState *env) { - abi_ulong sf_addr; - struct target_signal_frame *sf; - int sigframe_size, err, i; + abi_ulong sf_addr; + struct target_signal_frame *sf; + int sigframe_size, err, i; - /* 1. Make sure everything is clean */ - //synchronize_user_stack(); + /* 1. Make sure everything is clean */ + //synchronize_user_stack(); - sigframe_size = NF_ALIGNEDSZ; - sf_addr = get_sigframe(ka, env, sigframe_size); - trace_user_setup_frame(env, sf_addr); + sigframe_size = NF_ALIGNEDSZ; + sf_addr = get_sigframe(ka, env, sigframe_size); + trace_user_setup_frame(env, sf_addr); - sf = lock_user(VERIFY_WRITE, sf_addr, - sizeof(struct target_signal_frame), 0); - if (!sf) - goto sigsegv; - + sf = lock_user(VERIFY_WRITE, sf_addr, + sizeof(struct target_signal_frame), 0); + if (!sf) { + goto sigsegv; + } #if 0 - if (invalid_frame_pointer(sf, sigframe_size)) - goto sigill_and_return; + if (invalid_frame_pointer(sf, sigframe_size)) + goto sigill_and_return; #endif - /* 2. Save the current process state */ - err = setup___siginfo(&sf->info, env, set->sig[0]); + /* 2. Save the current process state */ + err = setup___siginfo(&sf->info, env, set->sig[0]); __put_user(0, &sf->extra_size); - //save_fpu_state(regs, &sf->fpu_state); - //__put_user(&sf->fpu_state, &sf->fpu_save); + //save_fpu_state(regs, &sf->fpu_state); + //__put_user(&sf->fpu_state, &sf->fpu_save); __put_user(set->sig[0], &sf->info.si_mask); - for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) { + for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) { __put_user(set->sig[i + 1], &sf->extramask[i]); - } + } - for (i = 0; i < 8; i++) { + for (i = 0; i < 8; i++) { __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]); - } - for (i = 0; i < 8; i++) { + } + for (i = 0; i < 8; i++) { __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]); - } - if (err) - goto sigsegv; - - /* 3. signal handler back-trampoline and parameters */ - env->regwptr[UREG_FP] = sf_addr; - env->regwptr[UREG_I0] = sig; - env->regwptr[UREG_I1] = sf_addr + - offsetof(struct target_signal_frame, info); - env->regwptr[UREG_I2] = sf_addr + - offsetof(struct target_signal_frame, info); - - /* 4. signal handler */ - env->pc = ka->_sa_handler; - env->npc = (env->pc + 4); - /* 5. return to kernel instructions */ - if (ka->sa_restorer) - env->regwptr[UREG_I7] = ka->sa_restorer; - else { - uint32_t val32; - - env->regwptr[UREG_I7] = sf_addr + - offsetof(struct target_signal_frame, insns) - 2 * 4; - - /* mov __NR_sigreturn, %g1 */ - val32 = 0x821020d8; + } + if (err) + goto sigsegv; + + /* 3. signal handler back-trampoline and parameters */ + env->regwptr[UREG_FP] = sf_addr; + env->regwptr[UREG_I0] = sig; + env->regwptr[UREG_I1] = sf_addr + + offsetof(struct target_signal_frame, info); + env->regwptr[UREG_I2] = sf_addr + + offsetof(struct target_signal_frame, info); + + /* 4. signal handler */ + env->pc = ka->_sa_handler; + env->npc = (env->pc + 4); + /* 5. return to kernel instructions */ + if (ka->sa_restorer) { + env->regwptr[UREG_I7] = ka->sa_restorer; + } else { + uint32_t val32; + + env->regwptr[UREG_I7] = sf_addr + + offsetof(struct target_signal_frame, insns) - 2 * 4; + + /* mov __NR_sigreturn, %g1 */ + val32 = 0x821020d8; __put_user(val32, &sf->insns[0]); - /* t 0x10 */ - val32 = 0x91d02010; + /* t 0x10 */ + val32 = 0x91d02010; __put_user(val32, &sf->insns[1]); - if (err) - goto sigsegv; + if (err) + goto sigsegv; - /* Flush instruction space. */ - //flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); - // tb_flush(CPU(sparc_env_get_cpu(env))); - } - unlock_user(sf, sf_addr, sizeof(struct target_signal_frame)); - return; + /* Flush instruction space. */ + // flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); + // tb_flush(env); + } + unlock_user(sf, sf_addr, sizeof(struct target_signal_frame)); + return; #if 0 sigill_and_return: - force_sig(TARGET_SIGILL); + force_sig(TARGET_SIGILL); #endif sigsegv: - unlock_user(sf, sf_addr, sizeof(struct target_signal_frame)); - force_sig(TARGET_SIGSEGV); + unlock_user(sf, sf_addr, sizeof(struct target_signal_frame)); + force_sig(TARGET_SIGSEGV); } static void setup_rt_frame(int sig, struct target_sigaction *ka, @@ -2369,71 +2396,74 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, long do_sigreturn(CPUSPARCState *env) { - abi_ulong sf_addr; - struct target_signal_frame *sf; - uint32_t up_psr, pc, npc; - target_sigset_t set; - sigset_t host_set; - int err=0, i; + abi_ulong sf_addr; + struct target_signal_frame *sf; + uint32_t up_psr, pc, npc; + target_sigset_t set; + sigset_t host_set; + int err=0, i; - sf_addr = env->regwptr[UREG_FP]; - trace_user_do_sigreturn(env, sf_addr); - if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1)) - goto segv_and_exit; + sf_addr = env->regwptr[UREG_FP]; + trace_user_do_sigreturn(env, sf_addr); + 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 */ + /* 1. Make sure we are not getting garbage from the user */ - if (sf_addr & 3) - goto segv_and_exit; + if (sf_addr & 3) + goto segv_and_exit; - __get_user(pc, &sf->info.si_regs.pc); - __get_user(npc, &sf->info.si_regs.npc); + __get_user(pc, &sf->info.si_regs.pc); + __get_user(npc, &sf->info.si_regs.npc); - if ((pc | npc) & 3) - goto segv_and_exit; + if ((pc | npc) & 3) { + goto segv_and_exit; + } - /* 2. Restore the state */ - __get_user(up_psr, &sf->info.si_regs.psr); + /* 2. Restore the state */ + __get_user(up_psr, &sf->info.si_regs.psr); - /* User can only change condition codes and FPU enabling in %psr. */ - env->psr = (up_psr & (PSR_ICC /* | PSR_EF */)) - | (env->psr & ~(PSR_ICC /* | PSR_EF */)); + /* User can only change condition codes and FPU enabling in %psr. */ + env->psr = (up_psr & (PSR_ICC /* | PSR_EF */)) + | (env->psr & ~(PSR_ICC /* | PSR_EF */)); - env->pc = pc; - env->npc = npc; - __get_user(env->y, &sf->info.si_regs.y); - for (i=0; i < 8; i++) { - __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]); - } - for (i=0; i < 8; i++) { - __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]); - } + env->pc = pc; + env->npc = npc; + __get_user(env->y, &sf->info.si_regs.y); + for (i=0; i < 8; i++) { + __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]); + } + for (i=0; i < 8; i++) { + __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]); + } - /* FIXME: implement FPU save/restore: + /* FIXME: implement FPU save/restore: * __get_user(fpu_save, &sf->fpu_save); * if (fpu_save) * err |= restore_fpu_state(env, fpu_save); */ - /* This is pretty much atomic, no amount locking would prevent + /* This is pretty much atomic, no amount locking would prevent * the races which exist anyways. */ - __get_user(set.sig[0], &sf->info.si_mask); - for(i = 1; i < TARGET_NSIG_WORDS; i++) { - __get_user(set.sig[i], &sf->extramask[i - 1]); - } + __get_user(set.sig[0], &sf->info.si_mask); + for(i = 1; i < TARGET_NSIG_WORDS; i++) { + __get_user(set.sig[i], &sf->extramask[i - 1]); + } - target_to_host_sigset_internal(&host_set, &set); - do_sigprocmask(SIG_SETMASK, &host_set, NULL); + target_to_host_sigset_internal(&host_set, &set); + do_sigprocmask(SIG_SETMASK, &host_set, NULL); - if (err) - goto segv_and_exit; - unlock_user_struct(sf, sf_addr, 0); - return env->regwptr[0]; + if (err) { + goto segv_and_exit; + } + unlock_user_struct(sf, sf_addr, 0); + return -TARGET_QEMU_ESIGRETURN; segv_and_exit: - unlock_user_struct(sf, sf_addr, 0); - force_sig(TARGET_SIGSEGV); + unlock_user_struct(sf, sf_addr, 0); + force_sig(TARGET_SIGSEGV); } long do_rt_sigreturn(CPUSPARCState *env) @@ -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; @@ -2573,12 +2605,14 @@ void sparc64_set_context(CPUSPARCState *env) __get_user(i7, &(ucp->tuc_mcontext.mc_i7)); 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) + if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]), + abi_ulong) != 0) { goto do_sigsegv; - if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]), - abi_ulong) != 0) + } + if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]), + 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: @@ -2601,7 +2635,7 @@ void sparc64_set_context(CPUSPARCState *env) &(ucp->tuc_mcontext.mc_fpregs.mcfpu_gsr)); unlock_user_struct(ucp, ucp_addr, 0); return; - do_sigsegv: +do_sigsegv: unlock_user_struct(ucp, ucp_addr, 0); force_sig(TARGET_SIGSEGV); } @@ -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; @@ -2670,12 +2705,14 @@ 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) + if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]), + abi_ulong) != 0) { goto do_sigsegv; - if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]), - abi_ulong) != 0) + } + if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]), + abi_ulong) != 0) { goto do_sigsegv; + } __put_user(fp, &(mcp->mc_fp)); __put_user(i7, &(mcp->mc_i7)); @@ -2697,7 +2734,7 @@ void sparc64_get_context(CPUSPARCState *env) goto do_sigsegv; unlock_user_struct(ucp, ucp_addr, 1); return; - do_sigsegv: +do_sigsegv: unlock_user_struct(ucp, ucp_addr, 1); force_sig(TARGET_SIGSEGV); } @@ -2787,7 +2824,7 @@ static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall) } static inline void setup_sigcontext(CPUMIPSState *regs, - struct target_sigcontext *sc) + struct target_sigcontext *sc) { int i; @@ -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)) - goto give_sigsegv; + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { + goto give_sigsegv; + } install_sigtramp(frame->sf_code, TARGET_NR_sigreturn); @@ -2948,7 +2986,7 @@ long do_sigreturn(CPUMIPSState *regs) frame_addr = regs->active_tc.gpr[29]; trace_user_do_sigreturn(regs, frame_addr); if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) - goto badframe; + goto badframe; for(i = 0; i < TARGET_NSIG_WORDS; i++) { __get_user(target_set.sig[i], &frame->sf_mask.sig[i]); @@ -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)) - goto give_sigsegv; + 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)) - goto badframe; + 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); @@ -3062,8 +3102,8 @@ long do_rt_sigreturn(CPUMIPSState *env) restore_sigcontext(env, &frame->rs_uc.tuc_mcontext); if (do_sigaltstack(frame_addr + - offsetof(struct target_rt_sigframe, rs_uc.tuc_stack), - 0, get_sp_from_cpustate(env)) == -EFAULT) + offsetof(struct target_rt_sigframe, rs_uc.tuc_stack), + 0, get_sp_from_cpustate(env)) == -EFAULT) goto badframe; env->active_tc.PC = env->CP0_EPC; @@ -3134,7 +3174,7 @@ struct target_rt_sigframe #define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */ static abi_ulong get_sigframe(struct target_sigaction *ka, - unsigned long sp, size_t frame_size) + unsigned long sp, size_t frame_size) { if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) { sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; @@ -3144,7 +3184,7 @@ static abi_ulong get_sigframe(struct target_sigaction *ka, } static void setup_sigcontext(struct target_sigcontext *sc, - CPUSH4State *regs, unsigned long mask) + CPUSH4State *regs, unsigned long mask) { int i; @@ -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)) - goto give_sigsegv; + 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)) - goto give_sigsegv; + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { + goto give_sigsegv; + } tswap_siginfo(&frame->info, info); @@ -3273,7 +3313,7 @@ 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, - regs, set->sig[0]); + regs, set->sig[0]); for(i = 0; i < TARGET_NSIG_WORDS; i++) { __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]); } @@ -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)) - goto badframe; + 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)) - goto badframe; + 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) + offsetof(struct target_rt_sigframe, uc.tuc_stack), + 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 */ @@ -3548,7 +3590,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, unlock_user_struct(frame, frame_addr, 1); return; - badframe: +badframe: force_sig(TARGET_SIGSEGV); } @@ -3576,7 +3618,7 @@ long do_sigreturn(CPUMBState *env) /* Restore blocked signals */ __get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask); for(i = 1; i < TARGET_NSIG_WORDS; i++) { - __get_user(target_set.sig[i], &frame->extramask[i - 1]); + __get_user(target_set.sig[i], &frame->extramask[i - 1]); } target_to_host_sigset_internal(&set, &target_set); do_sigprocmask(SIG_SETMASK, &set, NULL); @@ -3585,10 +3627,10 @@ long do_sigreturn(CPUMBState *env) /* We got here through a sigreturn syscall, our path back is via an rtb insn so setup r14 for that. */ env->regs[14] = env->sregs[SR_PC]; - + unlock_user_struct(frame, frame_addr, 0); - return env->regs[10]; - badframe: + return -TARGET_QEMU_ESIGRETURN; +badframe: force_sig(TARGET_SIGSEGV); } @@ -3602,124 +3644,124 @@ long do_rt_sigreturn(CPUMBState *env) #elif defined(TARGET_CRIS) struct target_sigcontext { - struct target_pt_regs regs; /* needs to be first */ - uint32_t oldmask; - uint32_t usp; /* usp before stacking this gunk on it */ + struct target_pt_regs regs; /* needs to be first */ + uint32_t oldmask; + uint32_t usp; /* usp before stacking this gunk on it */ }; /* Signal frames. */ struct target_signal_frame { - struct target_sigcontext sc; - uint32_t extramask[TARGET_NSIG_WORDS - 1]; - uint16_t retcode[4]; /* Trampoline code. */ + struct target_sigcontext sc; + uint32_t extramask[TARGET_NSIG_WORDS - 1]; + uint16_t retcode[4]; /* Trampoline code. */ }; struct rt_signal_frame { - siginfo_t *pinfo; - void *puc; - siginfo_t info; - struct ucontext uc; - uint16_t retcode[4]; /* Trampoline code. */ + siginfo_t *pinfo; + void *puc; + siginfo_t info; + struct ucontext uc; + uint16_t retcode[4]; /* Trampoline code. */ }; static void setup_sigcontext(struct target_sigcontext *sc, CPUCRISState *env) { - __put_user(env->regs[0], &sc->regs.r0); - __put_user(env->regs[1], &sc->regs.r1); - __put_user(env->regs[2], &sc->regs.r2); - __put_user(env->regs[3], &sc->regs.r3); - __put_user(env->regs[4], &sc->regs.r4); - __put_user(env->regs[5], &sc->regs.r5); - __put_user(env->regs[6], &sc->regs.r6); - __put_user(env->regs[7], &sc->regs.r7); - __put_user(env->regs[8], &sc->regs.r8); - __put_user(env->regs[9], &sc->regs.r9); - __put_user(env->regs[10], &sc->regs.r10); - __put_user(env->regs[11], &sc->regs.r11); - __put_user(env->regs[12], &sc->regs.r12); - __put_user(env->regs[13], &sc->regs.r13); - __put_user(env->regs[14], &sc->usp); - __put_user(env->regs[15], &sc->regs.acr); - __put_user(env->pregs[PR_MOF], &sc->regs.mof); - __put_user(env->pregs[PR_SRP], &sc->regs.srp); - __put_user(env->pc, &sc->regs.erp); + __put_user(env->regs[0], &sc->regs.r0); + __put_user(env->regs[1], &sc->regs.r1); + __put_user(env->regs[2], &sc->regs.r2); + __put_user(env->regs[3], &sc->regs.r3); + __put_user(env->regs[4], &sc->regs.r4); + __put_user(env->regs[5], &sc->regs.r5); + __put_user(env->regs[6], &sc->regs.r6); + __put_user(env->regs[7], &sc->regs.r7); + __put_user(env->regs[8], &sc->regs.r8); + __put_user(env->regs[9], &sc->regs.r9); + __put_user(env->regs[10], &sc->regs.r10); + __put_user(env->regs[11], &sc->regs.r11); + __put_user(env->regs[12], &sc->regs.r12); + __put_user(env->regs[13], &sc->regs.r13); + __put_user(env->regs[14], &sc->usp); + __put_user(env->regs[15], &sc->regs.acr); + __put_user(env->pregs[PR_MOF], &sc->regs.mof); + __put_user(env->pregs[PR_SRP], &sc->regs.srp); + __put_user(env->pc, &sc->regs.erp); } static void restore_sigcontext(struct target_sigcontext *sc, CPUCRISState *env) { - __get_user(env->regs[0], &sc->regs.r0); - __get_user(env->regs[1], &sc->regs.r1); - __get_user(env->regs[2], &sc->regs.r2); - __get_user(env->regs[3], &sc->regs.r3); - __get_user(env->regs[4], &sc->regs.r4); - __get_user(env->regs[5], &sc->regs.r5); - __get_user(env->regs[6], &sc->regs.r6); - __get_user(env->regs[7], &sc->regs.r7); - __get_user(env->regs[8], &sc->regs.r8); - __get_user(env->regs[9], &sc->regs.r9); - __get_user(env->regs[10], &sc->regs.r10); - __get_user(env->regs[11], &sc->regs.r11); - __get_user(env->regs[12], &sc->regs.r12); - __get_user(env->regs[13], &sc->regs.r13); - __get_user(env->regs[14], &sc->usp); - __get_user(env->regs[15], &sc->regs.acr); - __get_user(env->pregs[PR_MOF], &sc->regs.mof); - __get_user(env->pregs[PR_SRP], &sc->regs.srp); - __get_user(env->pc, &sc->regs.erp); + __get_user(env->regs[0], &sc->regs.r0); + __get_user(env->regs[1], &sc->regs.r1); + __get_user(env->regs[2], &sc->regs.r2); + __get_user(env->regs[3], &sc->regs.r3); + __get_user(env->regs[4], &sc->regs.r4); + __get_user(env->regs[5], &sc->regs.r5); + __get_user(env->regs[6], &sc->regs.r6); + __get_user(env->regs[7], &sc->regs.r7); + __get_user(env->regs[8], &sc->regs.r8); + __get_user(env->regs[9], &sc->regs.r9); + __get_user(env->regs[10], &sc->regs.r10); + __get_user(env->regs[11], &sc->regs.r11); + __get_user(env->regs[12], &sc->regs.r12); + __get_user(env->regs[13], &sc->regs.r13); + __get_user(env->regs[14], &sc->usp); + __get_user(env->regs[15], &sc->regs.acr); + __get_user(env->pregs[PR_MOF], &sc->regs.mof); + __get_user(env->pregs[PR_SRP], &sc->regs.srp); + __get_user(env->pc, &sc->regs.erp); } static abi_ulong get_sigframe(CPUCRISState *env, int framesize) { - abi_ulong sp; - /* Align the stack downwards to 4. */ - sp = (env->regs[R_SP] & ~3); - return sp - framesize; + abi_ulong sp; + /* Align the stack downwards to 4. */ + sp = (env->regs[R_SP] & ~3); + return sp - framesize; } static void setup_frame(int sig, struct target_sigaction *ka, target_sigset_t *set, CPUCRISState *env) { - struct target_signal_frame *frame; - abi_ulong frame_addr; - int i; - - frame_addr = get_sigframe(env, sizeof *frame); - trace_user_setup_frame(env, frame_addr); - if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) - goto badframe; - - /* - * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't - * use this trampoline anymore but it sets it up for GDB. - * In QEMU, using the trampoline simplifies things a bit so we use it. - * - * This is movu.w __NR_sigreturn, r9; break 13; - */ + struct target_signal_frame *frame; + abi_ulong frame_addr; + int i; + + frame_addr = get_sigframe(env, sizeof *frame); + trace_user_setup_frame(env, frame_addr); + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) + goto badframe; + + /* + * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't + * use this trampoline anymore but it sets it up for GDB. + * In QEMU, using the trampoline simplifies things a bit so we use it. + * + * This is movu.w __NR_sigreturn, r9; break 13; + */ __put_user(0x9c5f, frame->retcode+0); __put_user(TARGET_NR_sigreturn, frame->retcode + 1); __put_user(0xe93d, frame->retcode + 2); - /* Save the mask. */ + /* Save the mask. */ __put_user(set->sig[0], &frame->sc.oldmask); for(i = 1; i < TARGET_NSIG_WORDS; i++) { __put_user(set->sig[i], &frame->extramask[i - 1]); } - setup_sigcontext(&frame->sc, env); + setup_sigcontext(&frame->sc, env); - /* Move the stack and setup the arguments for the handler. */ - env->regs[R_SP] = frame_addr; - env->regs[10] = sig; - env->pc = (unsigned long) ka->_sa_handler; - /* Link SRP so the guest returns through the trampoline. */ - env->pregs[PR_SRP] = frame_addr + offsetof(typeof(*frame), retcode); + /* Move the stack and setup the arguments for the handler. */ + env->regs[R_SP] = frame_addr; + env->regs[10] = sig; + env->pc = (unsigned long) ka->_sa_handler; + /* Link SRP so the guest returns through the trampoline. */ + env->pregs[PR_SRP] = frame_addr + offsetof(typeof(*frame), retcode); - unlock_user_struct(frame, frame_addr, 1); - return; - badframe: - force_sig(TARGET_SIGSEGV); + unlock_user_struct(frame, frame_addr, 1); + return; +badframe: + force_sig(TARGET_SIGSEGV); } static void setup_rt_frame(int sig, struct target_sigaction *ka, @@ -3731,31 +3773,32 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, long do_sigreturn(CPUCRISState *env) { - struct target_signal_frame *frame; - abi_ulong frame_addr; - target_sigset_t target_set; - sigset_t set; - int i; + struct target_signal_frame *frame; + abi_ulong frame_addr; + target_sigset_t target_set; + sigset_t set; + int i; - 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)) - goto badframe; + 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)) { + goto badframe; + } - /* Restore blocked signals */ + /* Restore blocked signals */ __get_user(target_set.sig[0], &frame->sc.oldmask); - for(i = 1; i < TARGET_NSIG_WORDS; i++) { + for(i = 1; i < TARGET_NSIG_WORDS; i++) { __get_user(target_set.sig[i], &frame->extramask[i - 1]); - } - target_to_host_sigset_internal(&set, &target_set); - do_sigprocmask(SIG_SETMASK, &set, NULL); + } + target_to_host_sigset_internal(&set, &target_set); + do_sigprocmask(SIG_SETMASK, &set, NULL); - restore_sigcontext(&frame->sc, env); - unlock_user_struct(frame, frame_addr, 0); - return env->regs[10]; - badframe: - force_sig(TARGET_SIGSEGV); + restore_sigcontext(&frame->sc, env); + unlock_user_struct(frame, frame_addr, 0); + return -TARGET_QEMU_ESIGRETURN; +badframe: + force_sig(TARGET_SIGSEGV); } long do_rt_sigreturn(CPUCRISState *env) @@ -3841,8 +3884,8 @@ badframe: /* Set up a signal frame. */ static void setup_sigcontext(struct target_sigcontext *sc, - CPUOpenRISCState *regs, - unsigned long mask) + CPUOpenRISCState *regs, + unsigned long mask) { unsigned long usp = regs->gpr[1]; @@ -4100,7 +4143,7 @@ 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)) { - goto give_sigsegv; + goto give_sigsegv; } __put_user(set->sig[0], &frame->sc.oldmask[0]); @@ -4113,13 +4156,13 @@ static void setup_frame(int sig, struct target_sigaction *ka, /* Set up to return from userspace. If provided, use a stub already in userspace. */ if (ka->sa_flags & TARGET_SA_RESTORER) { - env->regs[14] = (unsigned long) - ka->sa_restorer | PSW_ADDR_AMODE; + env->regs[14] = (unsigned long) + ka->sa_restorer | PSW_ADDR_AMODE; } else { - env->regs[14] = (unsigned long) - frame->retcode | PSW_ADDR_AMODE; - __put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn, - (uint16_t *)(frame->retcode)); + env->regs[14] = (frame_addr + offsetof(sigframe, retcode)) + | PSW_ADDR_AMODE; + __put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn, + (uint16_t *)(frame->retcode)); } /* Set up backchain. */ @@ -4167,12 +4210,12 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link); __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp); __put_user(sas_ss_flags(get_sp_from_cpustate(env)), - &frame->uc.tuc_stack.ss_flags); + &frame->uc.tuc_stack.ss_flags); __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size); save_sigregs(env, &frame->uc.tuc_mcontext); for (i = 0; i < TARGET_NSIG_WORDS; i++) { __put_user((abi_ulong)set->sig[i], - (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]); + (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]); } /* Set up to return from userspace. If provided, use a stub @@ -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); @@ -4423,15 +4466,15 @@ struct target_sigframe { #define TARGET_TRAMP_SIZE 6 struct target_rt_sigframe { - /* sys_rt_sigreturn requires the ucontext be the first field */ - struct target_ucontext uc; - target_ulong _unused[2]; - uint32_t trampoline[TARGET_TRAMP_SIZE]; - target_ulong pinfo; /* struct siginfo __user * */ - target_ulong puc; /* void __user * */ - struct target_siginfo info; - /* 64 bit ABI allows for 288 bytes below sp before decrementing it. */ - char abigap[288]; + /* sys_rt_sigreturn requires the ucontext be the first field */ + struct target_ucontext uc; + target_ulong _unused[2]; + uint32_t trampoline[TARGET_TRAMP_SIZE]; + target_ulong pinfo; /* struct siginfo __user * */ + target_ulong puc; /* void __user * */ + struct target_siginfo info; + /* 64 bit ABI allows for 288 bytes below sp before decrementing it. */ + char abigap[288]; } __attribute__((aligned(16))); #else @@ -4466,7 +4509,7 @@ static target_ulong get_sigframe(struct target_sigaction *ka, oldsp = env->gpr[1]; if ((ka->sa_flags & TARGET_SA_ONSTACK) && - (sas_ss_flags(oldsp) == 0)) { + (sas_ss_flags(oldsp) == 0)) { oldsp = (target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size); } @@ -4488,7 +4531,7 @@ static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame) /* Save general registers. */ for (i = 0; i < ARRAY_SIZE(env->gpr); i++) { - __put_user(env->gpr[i], &frame->mc_gregs[i]); + __put_user(env->gpr[i], &frame->mc_gregs[i]); } __put_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP]); __put_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR]); @@ -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; @@ -4925,7 +4968,7 @@ struct target_sigframe abi_ulong extramask[TARGET_NSIG_WORDS-1]; struct target_sigcontext sc; }; - + typedef int target_greg_t; #define TARGET_NGREG 18 typedef target_greg_t target_gregset_t[TARGET_NGREG]; @@ -4964,7 +5007,7 @@ struct target_rt_sigframe }; static void setup_sigcontext(struct target_sigcontext *sc, CPUM68KState *env, - abi_ulong mask) + abi_ulong mask) { __put_user(mask, &sc->sc_mask); __put_user(env->aregs[7], &sc->sc_usp); @@ -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)) - goto give_sigsegv; + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { + goto give_sigsegv; + } __put_user(sig, &frame->sig); @@ -5044,7 +5087,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, /* moveq #,d0; trap #0 */ __put_user(0x70004e40 + (TARGET_NR_sigreturn << 16), - (uint32_t *)(frame->retcode)); + (uint32_t *)(frame->retcode)); /* Set up to return from userspace */ @@ -5085,10 +5128,9 @@ static inline int target_rt_setup_ucontext(struct target_ucontext *uc, return 0; } - + 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)) - goto give_sigsegv; + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { + goto give_sigsegv; + } __put_user(sig, &frame->sig); @@ -5159,13 +5201,13 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp); __put_user(sas_ss_flags(env->aregs[7]), - &frame->uc.tuc_stack.ss_flags); + &frame->uc.tuc_stack.ss_flags); __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size); err |= target_rt_setup_ucontext(&frame->uc, env); if (err) - goto give_sigsegv; + goto give_sigsegv; for(i = 0; i < TARGET_NSIG_WORDS; i++) { __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]); @@ -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); @@ -5316,7 +5357,7 @@ struct target_rt_sigframe { #define INSN_CALLSYS 0x00000083 static void setup_sigcontext(struct target_sigcontext *sc, CPUAlphaState *env, - abi_ulong frame_addr, target_sigset_t *set) + abi_ulong frame_addr, target_sigset_t *set) { int i; @@ -5342,7 +5383,7 @@ static void setup_sigcontext(struct target_sigcontext *sc, CPUAlphaState *env, } static void restore_sigcontext(CPUAlphaState *env, - struct target_sigcontext *sc) + struct target_sigcontext *sc) { uint64_t fpcr; int i; @@ -5402,7 +5443,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, unlock_user_struct(frame, frame_addr, 1); if (err) { - give_sigsegv: +give_sigsegv: if (sig == TARGET_SIGSEGV) { ka->_sa_handler = TARGET_SIG_DFL; } @@ -5459,8 +5500,8 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, } if (err) { - give_sigsegv: - if (sig == TARGET_SIGSEGV) { +give_sigsegv: + if (sig == TARGET_SIGSEGV) { ka->_sa_handler = TARGET_SIG_DFL; } force_sig(TARGET_SIGSEGV); @@ -5493,9 +5534,9 @@ 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: +badframe: force_sig(TARGET_SIGSEGV); } @@ -5520,10 +5561,10 @@ long do_rt_sigreturn(CPUAlphaState *env) } unlock_user_struct(frame, frame_addr, 0); - return env->ir[IR_V0]; + return -TARGET_QEMU_ESIGRETURN; - badframe: +badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); } @@ -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; + 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: @@ -5690,14 +5739,14 @@ long do_rt_sigreturn(CPUTLGState *env) #else static void setup_frame(int sig, struct target_sigaction *ka, - target_sigset_t *set, CPUArchState *env) + target_sigset_t *set, CPUArchState *env) { fprintf(stderr, "setup_frame: not implemented\n"); } static void setup_rt_frame(int sig, struct target_sigaction *ka, target_siginfo_t *info, - target_sigset_t *set, CPUArchState *env) + target_sigset_t *set, CPUArchState *env) { fprintf(stderr, "setup_rt_frame: not implemented\n"); } diff --git a/linux-user/sparc/target_signal.h b/linux-user/sparc/target_signal.h index c7de300cd7..2df38c805f 100644 --- a/linux-user/sparc/target_signal.h +++ b/linux-user/sparc/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 */ diff --git a/linux-user/sparc64/target_signal.h b/linux-user/sparc64/target_signal.h index c7de300cd7..2df38c805f 100644 --- a/linux-user/sparc64/target_signal.h +++ b/linux-user/sparc64/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 */ diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 032d338869..df70255e5f 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -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,8 +1148,13 @@ 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)) - return -TARGET_EFAULT; + 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,11 +5440,11 @@ 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, - g2h(uaddr2), - (base_op == FUTEX_CMP_REQUEUE - ? tswap32(val3) - : val3))); + return get_errno(safe_futex(g2h(uaddr), op, val, pts, + g2h(uaddr2), + (base_op == FUTEX_CMP_REQUEUE + ? tswap32(val3) + : val3))); default: return -TARGET_ENOSYS; } @@ -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,8 +7252,8 @@ 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, - ts_ptr, sig_ptr)); + ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr, + ts_ptr, sig_ptr)); if (!is_error(ret)) { if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n)) @@ -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,9 +8868,9 @@ 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), - low2highuid(arg2), - low2highuid(arg3))); + ret = get_errno(sys_setresuid(low2highuid(arg1), + low2highuid(arg2), + low2highuid(arg3))); break; #endif #ifdef TARGET_NR_getresuid @@ -8761,9 +8889,9 @@ 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), - low2highgid(arg2), - low2highgid(arg3))); + ret = get_errno(sys_setresgid(low2highgid(arg1), + low2highgid(arg2), + low2highgid(arg3))); break; #endif #ifdef TARGET_NR_getresgid @@ -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 diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 9e2b3c200a..34af15a683 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.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 */ diff --git a/linux-user/tilegx/target_signal.h b/linux-user/tilegx/target_signal.h index b595f985cf..fcf10405c4 100644 --- a/linux-user/tilegx/target_signal.h +++ b/linux-user/tilegx/target_signal.h @@ -25,4 +25,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUTLGState *state) return state->regs[TILEGX_R_SP]; } + #endif /* TARGET_SIGNAL_H */ |