diff options
Diffstat (limited to 'arch/sparc/kernel/signal_64.c')
| -rw-r--r-- | arch/sparc/kernel/signal_64.c | 142 | 
1 files changed, 46 insertions, 96 deletions
diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c index 689e1ba6280..35923e8abd8 100644 --- a/arch/sparc/kernel/signal_64.c +++ b/arch/sparc/kernel/signal_64.c @@ -236,23 +236,6 @@ struct rt_signal_frame {  	__siginfo_rwin_t	*rwin_save;  }; -static long _sigpause_common(old_sigset_t set) -{ -	sigset_t blocked; -	siginitset(&blocked, set); -	return sigsuspend(&blocked); -} - -asmlinkage long sys_sigpause(unsigned int set) -{ -	return _sigpause_common(set); -} - -asmlinkage long sys_sigsuspend(old_sigset_t set) -{ -	return _sigpause_common(set); -} -  void do_rt_sigreturn(struct pt_regs *regs)  {  	struct rt_signal_frame __user *sf; @@ -295,7 +278,8 @@ void do_rt_sigreturn(struct pt_regs *regs)  		err |= restore_fpu_state(regs, fpu_save);  	err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t)); -	if (err || do_sigaltstack(&sf->stack, NULL, (unsigned long)sf) == -EFAULT) +	err |= restore_altstack(&sf->stack); +	if (err)  		goto segv;  	err |= __get_user(rwin_save, &sf->rwin_save); @@ -324,7 +308,7 @@ static int invalid_frame_pointer(void __user *fp)  	return 0;  } -static inline void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, unsigned long framesize) +static inline void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize)  {  	unsigned long sp = regs->u_regs[UREG_FP] + STACK_BIAS; @@ -336,12 +320,7 @@ static inline void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *  		return (void __user *) -1L;  	/* This is the X/Open sanctioned signal stack switching.  */ -	if (ka->sa.sa_flags & SA_ONSTACK) { -		if (sas_ss_flags(sp) == 0) -			sp = current->sas_ss_sp + current->sas_ss_size; -	} - -	sp -= framesize; +	sp = sigsp(sp, ksig) - framesize;  	/* Always align the stack frame.  This handles two cases.  First,  	 * sigaltstack need not be mindful of platform specific stack @@ -355,8 +334,7 @@ static inline void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *  }  static inline int -setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, -	       int signo, sigset_t *oldset, siginfo_t *info) +setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs)  {  	struct rt_signal_frame __user *sf;  	int wsaved, err, sf_size; @@ -374,10 +352,12 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,  	if (wsaved)  		sf_size += sizeof(__siginfo_rwin_t);  	sf = (struct rt_signal_frame __user *) -		get_sigframe(ka, regs, sf_size); +		get_sigframe(ksig, regs, sf_size); -	if (invalid_frame_pointer (sf)) -		goto sigill; +	if (invalid_frame_pointer (sf)) { +		do_exit(SIGILL);	/* won't return, actually */ +		return -EINVAL; +	}  	tail = (sf + 1); @@ -403,11 +383,9 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,  	}  	/* Setup sigaltstack */ -	err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp); -	err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags); -	err |= __put_user(current->sas_ss_size, &sf->stack.ss_size); +	err |= __save_altstack(&sf->stack, regs->u_regs[UREG_FP]); -	err |= copy_to_user(&sf->mask, oldset, sizeof(sigset_t)); +	err |= copy_to_user(&sf->mask, sigmask_to_save(), sizeof(sigset_t));  	if (!wsaved) {  		err |= copy_in_user((u64 __user *)sf, @@ -420,18 +398,18 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,  		rp = ¤t_thread_info()->reg_window[wsaved - 1];  		err |= copy_to_user(sf, rp, sizeof(struct reg_window));  	} -	if (info) -		err |= copy_siginfo_to_user(&sf->info, info); +	if (ksig->ka.sa.sa_flags & SA_SIGINFO) +		err |= copy_siginfo_to_user(&sf->info, &ksig->info);  	else { -		err |= __put_user(signo, &sf->info.si_signo); +		err |= __put_user(ksig->sig, &sf->info.si_signo);  		err |= __put_user(SI_NOINFO, &sf->info.si_code);  	}  	if (err) -		goto sigsegv; +		return err;  	/* 3. signal handler back-trampoline and parameters */  	regs->u_regs[UREG_FP] = ((unsigned long) sf) - STACK_BIAS; -	regs->u_regs[UREG_I0] = signo; +	regs->u_regs[UREG_I0] = ksig->sig;  	regs->u_regs[UREG_I1] = (unsigned long) &sf->info;  	/* The sigcontext is passed in this way because of how it @@ -441,37 +419,15 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,  	regs->u_regs[UREG_I2] = (unsigned long) &sf->info;  	/* 5. signal handler */ -	regs->tpc = (unsigned long) ka->sa.sa_handler; +	regs->tpc = (unsigned long) ksig->ka.sa.sa_handler;  	regs->tnpc = (regs->tpc + 4);  	if (test_thread_flag(TIF_32BIT)) {  		regs->tpc &= 0xffffffff;  		regs->tnpc &= 0xffffffff;  	}  	/* 4. return to kernel instructions */ -	regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; +	regs->u_regs[UREG_I7] = (unsigned long)ksig->ka.ka_restorer;  	return 0; - -sigill: -	do_exit(SIGILL); -	return -EINVAL; - -sigsegv: -	force_sigsegv(signo, current); -	return -EFAULT; -} - -static inline void handle_signal(unsigned long signr, struct k_sigaction *ka, -				siginfo_t *info, -				sigset_t *oldset, struct pt_regs *regs) -{ -	int err; - -	err = setup_rt_frame(ka, regs, signr, oldset, -			     (ka->sa.sa_flags & SA_SIGINFO) ? info : NULL); -	if (err) -		return; - -	signal_delivered(signr, info, ka, regs, 0);  }  static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, @@ -501,11 +457,9 @@ static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,   */  static void do_signal(struct pt_regs *regs, unsigned long orig_i0)  { -	struct k_sigaction ka; +	struct ksignal ksig;  	int restart_syscall; -	sigset_t *oldset = sigmask_to_save(); -	siginfo_t info; -	int signr; +	bool has_handler;  	/* It's a lot of work and synchronization to add a new ptrace  	 * register for GDB to save and restore in order to get @@ -531,13 +485,13 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)  #ifdef CONFIG_COMPAT  	if (test_thread_flag(TIF_32BIT)) { -		extern void do_signal32(sigset_t *, struct pt_regs *); -		do_signal32(oldset, regs); +		extern void do_signal32(struct pt_regs *); +		do_signal32(regs);  		return;  	}  #endif	 -	signr = get_signal_to_deliver(&info, &ka, regs, NULL); +	has_handler = get_signal(&ksig);  	restart_syscall = 0;  	if (pt_regs_is_syscall(regs) && @@ -546,34 +500,30 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)  		orig_i0 = regs->u_regs[UREG_G6];  	} -	if (signr > 0) { +	if (has_handler) {  		if (restart_syscall) -			syscall_restart(orig_i0, regs, &ka.sa); -		handle_signal(signr, &ka, &info, oldset, regs); -		return; -	} -	if (restart_syscall && -	    (regs->u_regs[UREG_I0] == ERESTARTNOHAND || -	     regs->u_regs[UREG_I0] == ERESTARTSYS || -	     regs->u_regs[UREG_I0] == ERESTARTNOINTR)) { -		/* replay the system call when we are done */ -		regs->u_regs[UREG_I0] = orig_i0; -		regs->tpc -= 4; -		regs->tnpc -= 4; -		pt_regs_clear_syscall(regs); -	} -	if (restart_syscall && -	    regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) { -		regs->u_regs[UREG_G1] = __NR_restart_syscall; -		regs->tpc -= 4; -		regs->tnpc -= 4; -		pt_regs_clear_syscall(regs); +			syscall_restart(orig_i0, regs, &ksig.ka.sa); +		signal_setup_done(setup_rt_frame(&ksig, regs), &ksig, 0); +	} else { +		if (restart_syscall) { +			switch (regs->u_regs[UREG_I0]) { +			case ERESTARTNOHAND: +	     		case ERESTARTSYS: +			case ERESTARTNOINTR: +				/* replay the system call when we are done */ +				regs->u_regs[UREG_I0] = orig_i0; +				regs->tpc -= 4; +				regs->tnpc -= 4; +				pt_regs_clear_syscall(regs); +			case ERESTART_RESTARTBLOCK: +				regs->u_regs[UREG_G1] = __NR_restart_syscall; +				regs->tpc -= 4; +				regs->tnpc -= 4; +				pt_regs_clear_syscall(regs); +			} +		} +		restore_saved_sigmask();  	} - -	/* If there's no signal to deliver, we just put the saved sigmask -	 * back -	 */ -	restore_saved_sigmask();  }  void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, unsigned long thread_info_flags)  |