diff options
| author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-07-16 12:32:42 -0700 | 
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-07-16 12:32:42 -0700 | 
| commit | 467a3ca5cab64a16b5ec46ebb1895c84c280dcfe (patch) | |
| tree | 68096d5b17e884d270420d50e466186c73019830 /arch/arm/kernel/signal.c | |
| parent | 40c9f61eae9098212b6906f29f30f08f7a19b5e2 (diff) | |
| parent | 84a1caf1453c3d44050bd22db958af4a7f99315c (diff) | |
Merge branch 'v3.6-rc7' into tty-next
This is to sync up on Linus's branch to get the other tty and core changes.
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'arch/arm/kernel/signal.c')
| -rw-r--r-- | arch/arm/kernel/signal.c | 46 | 
1 files changed, 40 insertions, 6 deletions
| diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index fd2392a17ac1..536c5d6b340b 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -27,6 +27,7 @@   */  #define SWI_SYS_SIGRETURN	(0xef000000|(__NR_sigreturn)|(__NR_OABI_SYSCALL_BASE))  #define SWI_SYS_RT_SIGRETURN	(0xef000000|(__NR_rt_sigreturn)|(__NR_OABI_SYSCALL_BASE)) +#define SWI_SYS_RESTART		(0xef000000|__NR_restart_syscall|__NR_OABI_SYSCALL_BASE)  /*   * With EABI, the syscall number has to be loaded into r7. @@ -47,6 +48,18 @@ const unsigned long sigreturn_codes[7] = {  };  /* + * Either we support OABI only, or we have EABI with the OABI + * compat layer enabled.  In the later case we don't know if + * user space is EABI or not, and if not we must not clobber r7. + * Always using the OABI syscall solves that issue and works for + * all those cases. + */ +const unsigned long syscall_restart_code[2] = { +	SWI_SYS_RESTART,	/* swi	__NR_restart_syscall */ +	0xe49df004,		/* ldr	pc, [sp], #4 */ +}; + +/*   * atomically swap in the new signal mask, and wait for a signal.   */  asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask) @@ -592,10 +605,12 @@ static void do_signal(struct pt_regs *regs, int syscall)  		case -ERESTARTNOHAND:  		case -ERESTARTSYS:  		case -ERESTARTNOINTR: -		case -ERESTART_RESTARTBLOCK:  			regs->ARM_r0 = regs->ARM_ORIG_r0;  			regs->ARM_pc = restart_addr;  			break; +		case -ERESTART_RESTARTBLOCK: +			regs->ARM_r0 = -EINTR; +			break;  		}  	} @@ -611,14 +626,12 @@ static void do_signal(struct pt_regs *regs, int syscall)  		 * debugger has chosen to restart at a different PC.  		 */  		if (regs->ARM_pc == restart_addr) { -			if (retval == -ERESTARTNOHAND || -			    retval == -ERESTART_RESTARTBLOCK +			if (retval == -ERESTARTNOHAND  			    || (retval == -ERESTARTSYS  				&& !(ka.sa.sa_flags & SA_RESTART))) {  				regs->ARM_r0 = -EINTR;  				regs->ARM_pc = continue_addr;  			} -			clear_thread_flag(TIF_SYSCALL_RESTARTSYS);  		}  		handle_signal(signr, &ka, &info, regs); @@ -632,8 +645,29 @@ static void do_signal(struct pt_regs *regs, int syscall)  		 * ignore the restart.  		 */  		if (retval == -ERESTART_RESTARTBLOCK -		    && regs->ARM_pc == restart_addr) -			set_thread_flag(TIF_SYSCALL_RESTARTSYS); +		    && regs->ARM_pc == continue_addr) { +			if (thumb_mode(regs)) { +				regs->ARM_r7 = __NR_restart_syscall - __NR_SYSCALL_BASE; +				regs->ARM_pc -= 2; +			} else { +#if defined(CONFIG_AEABI) && !defined(CONFIG_OABI_COMPAT) +				regs->ARM_r7 = __NR_restart_syscall; +				regs->ARM_pc -= 4; +#else +				u32 __user *usp; + +				regs->ARM_sp -= 4; +				usp = (u32 __user *)regs->ARM_sp; + +				if (put_user(regs->ARM_pc, usp) == 0) { +					regs->ARM_pc = KERN_RESTART_CODE; +				} else { +					regs->ARM_sp += 4; +					force_sigsegv(0, current); +				} +#endif +			} +		}  	}  	restore_saved_sigmask(); | 
