diff options
Diffstat (limited to 'arch/mips/kernel/signal.c')
| -rw-r--r-- | arch/mips/kernel/signal.c | 86 | 
1 files changed, 19 insertions, 67 deletions
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index d0c68b5d717..2099d5a4c4b 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -32,6 +32,7 @@  #include <asm/ucontext.h>  #include <asm/cpu-features.h>  #include <asm/war.h> +#include <asm/vdso.h>  #include "signal-common.h" @@ -44,47 +45,20 @@ extern asmlinkage int _restore_fp_context(struct sigcontext __user *sc);  extern asmlinkage int fpu_emulator_save_context(struct sigcontext __user *sc);  extern asmlinkage int fpu_emulator_restore_context(struct sigcontext __user *sc); -/* - * Horribly complicated - with the bloody RM9000 workarounds enabled - * the signal trampolines is moving to the end of the structure so we can - * increase the alignment without breaking software compatibility. - */ -#if ICACHE_REFILLS_WORKAROUND_WAR == 0 -  struct sigframe {  	u32 sf_ass[4];		/* argument save space for o32 */ -	u32 sf_code[2];		/* signal trampoline */ +	u32 sf_pad[2];		/* Was: signal trampoline */  	struct sigcontext sf_sc;  	sigset_t sf_mask;  };  struct rt_sigframe {  	u32 rs_ass[4];		/* argument save space for o32 */ -	u32 rs_code[2];		/* signal trampoline */ +	u32 rs_pad[2];		/* Was: signal trampoline */  	struct siginfo rs_info;  	struct ucontext rs_uc;  }; -#else - -struct sigframe { -	u32 sf_ass[4];			/* argument save space for o32 */ -	u32 sf_pad[2]; -	struct sigcontext sf_sc;	/* hw context */ -	sigset_t sf_mask; -	u32 sf_code[8] ____cacheline_aligned;	/* signal trampoline */ -}; - -struct rt_sigframe { -	u32 rs_ass[4];			/* argument save space for o32 */ -	u32 rs_pad[2]; -	struct siginfo rs_info; -	struct ucontext rs_uc; -	u32 rs_code[8] ____cacheline_aligned;	/* signal trampoline */ -}; - -#endif -  /*   * Helper routines   */ @@ -266,32 +240,6 @@ void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,  	return (void __user *)((sp - frame_size) & (ICACHE_REFILLS_WORKAROUND_WAR ? ~(cpu_icache_line_size()-1) : ALMASK));  } -int install_sigtramp(unsigned int __user *tramp, unsigned int syscall) -{ -	int err; - -	/* -	 * Set up the return code ... -	 * -	 *         li      v0, __NR__foo_sigreturn -	 *         syscall -	 */ - -	err = __put_user(0x24020000 + syscall, tramp + 0); -	err |= __put_user(0x0000000c         , tramp + 1); -	if (ICACHE_REFILLS_WORKAROUND_WAR) { -		err |= __put_user(0, tramp + 2); -		err |= __put_user(0, tramp + 3); -		err |= __put_user(0, tramp + 4); -		err |= __put_user(0, tramp + 5); -		err |= __put_user(0, tramp + 6); -		err |= __put_user(0, tramp + 7); -	} -	flush_cache_sigtramp((unsigned long) tramp); - -	return err; -} -  /*   * Atomically swap in the new signal mask, and wait for a signal.   */ @@ -484,8 +432,8 @@ badframe:  }  #ifdef CONFIG_TRAD_SIGNALS -static int setup_frame(struct k_sigaction * ka, struct pt_regs *regs, -	int signr, sigset_t *set) +static int setup_frame(void *sig_return, struct k_sigaction *ka, +		       struct pt_regs *regs, int signr, sigset_t *set)  {  	struct sigframe __user *frame;  	int err = 0; @@ -494,8 +442,6 @@ static int setup_frame(struct k_sigaction * ka, struct pt_regs *regs,  	if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))  		goto give_sigsegv; -	err |= install_sigtramp(frame->sf_code, __NR_sigreturn); -  	err |= setup_sigcontext(regs, &frame->sf_sc);  	err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set));  	if (err) @@ -515,7 +461,7 @@ static int setup_frame(struct k_sigaction * ka, struct pt_regs *regs,  	regs->regs[ 5] = 0;  	regs->regs[ 6] = (unsigned long) &frame->sf_sc;  	regs->regs[29] = (unsigned long) frame; -	regs->regs[31] = (unsigned long) frame->sf_code; +	regs->regs[31] = (unsigned long) sig_return;  	regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;  	DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", @@ -529,8 +475,9 @@ give_sigsegv:  }  #endif -static int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, -	int signr, sigset_t *set, siginfo_t *info) +static int setup_rt_frame(void *sig_return, struct k_sigaction *ka, +			  struct pt_regs *regs,	int signr, sigset_t *set, +			  siginfo_t *info)  {  	struct rt_sigframe __user *frame;  	int err = 0; @@ -539,8 +486,6 @@ static int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,  	if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))  		goto give_sigsegv; -	err |= install_sigtramp(frame->rs_code, __NR_rt_sigreturn); -  	/* Create siginfo.  */  	err |= copy_siginfo_to_user(&frame->rs_info, info); @@ -573,7 +518,7 @@ static int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,  	regs->regs[ 5] = (unsigned long) &frame->rs_info;  	regs->regs[ 6] = (unsigned long) &frame->rs_uc;  	regs->regs[29] = (unsigned long) frame; -	regs->regs[31] = (unsigned long) frame->rs_code; +	regs->regs[31] = (unsigned long) sig_return;  	regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;  	DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", @@ -590,8 +535,11 @@ give_sigsegv:  struct mips_abi mips_abi = {  #ifdef CONFIG_TRAD_SIGNALS  	.setup_frame	= setup_frame, +	.signal_return_offset = offsetof(struct mips_vdso, signal_trampoline),  #endif  	.setup_rt_frame	= setup_rt_frame, +	.rt_signal_return_offset = +		offsetof(struct mips_vdso, rt_signal_trampoline),  	.restart	= __NR_restart_syscall  }; @@ -599,6 +547,8 @@ static int handle_signal(unsigned long sig, siginfo_t *info,  	struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs)  {  	int ret; +	struct mips_abi *abi = current->thread.abi; +	void *vdso = current->mm->context.vdso;  	switch(regs->regs[0]) {  	case ERESTART_RESTARTBLOCK: @@ -619,9 +569,11 @@ static int handle_signal(unsigned long sig, siginfo_t *info,  	regs->regs[0] = 0;		/* Don't deal with this again.  */  	if (sig_uses_siginfo(ka)) -		ret = current->thread.abi->setup_rt_frame(ka, regs, sig, oldset, info); +		ret = abi->setup_rt_frame(vdso + abi->rt_signal_return_offset, +					  ka, regs, sig, oldset, info);  	else -		ret = current->thread.abi->setup_frame(ka, regs, sig, oldset); +		ret = abi->setup_frame(vdso + abi->signal_return_offset, +				       ka, regs, sig, oldset);  	spin_lock_irq(¤t->sighand->siglock);  	sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask);  |