diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-08 08:24:38 +0900 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-08 08:24:38 +0900 | 
| commit | 280c84d1c1726be7ada045735858acdc8cfdd65a (patch) | |
| tree | b9afa3fb97b08272b6952d5c8d1fe31f6a8092fa /arch/s390/kernel/signal.c | |
| parent | 8efdf2b759409f85953b84d52a14ea4d39c80474 (diff) | |
| parent | de9587a2f54d2d0063f0dbc775328129b9daaaa2 (diff) | |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 updates from Martin Schwidefsky:
 "The bulk of the patches for the 3.13 merge window.
  Heiko spent quite a bit of work to improve the code generation for the
  kernel.  That includes the exploitation of the interlocked-access
  facility for the atomics and bitops implementation and the improvement
  for the -march and -mtune compiler settings.
  Another important change is the removal of the user_mode=home option,
  user processes now always run in primary space.  The storage keys are
  not initialized at system startup any more, with that the storage key
  removal work is complete.  For the PCI support the hibernation hooks
  have been implemented.
  And as usual cleanup and fixes"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (62 commits)
  s390/scm_blk: fix endless loop for requests != REQ_TYPE_FS
  s390/mm,tlb: correct tlb flush on page table upgrade
  s390/mm: page_table_realloc returns failure
  s390: allow to set gcc -mtune flag
  s390/percpu: remove this_cpu_xor() implementation
  s390/vtime: correct idle time calculation
  s390/time: fix get_tod_clock_ext inline assembly
  tty/hvc_iucv: remove redundant NULL check
  s390/dasd: Write to profile data area only if it is available
  s390: convert use of typedef ctl_table to struct ctl_table
  s390/pci: cleanup function information block
  s390/pci: remove CONFIG_PCI_DEBUG dependancy
  s390/pci: message cleanup
  Update default configuration
  s390: add a couple of useful defconfigs
  s390/percpu: make use of interlocked-access facility 1 instructions
  s390/percpu: use generic percpu ops for CONFIG_32BIT
  s390/compat: make psw32_user_bits a constant value again
  s390: fix handling of runtime instrumentation psw bit
  s390: fix save and restore of the floating-point-control register
  ...
Diffstat (limited to 'arch/s390/kernel/signal.c')
| -rw-r--r-- | arch/s390/kernel/signal.c | 49 | 
1 files changed, 28 insertions, 21 deletions
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index c45becf82e01..fb535874a246 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c @@ -57,40 +57,48 @@ static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs)  	/* Copy a 'clean' PSW mask to the user to avoid leaking  	   information about whether PER is currently on.  */ -	user_sregs.regs.psw.mask = psw_user_bits | -		(regs->psw.mask & PSW_MASK_USER); +	user_sregs.regs.psw.mask = PSW_USER_BITS | +		(regs->psw.mask & (PSW_MASK_USER | PSW_MASK_RI));  	user_sregs.regs.psw.addr = regs->psw.addr;  	memcpy(&user_sregs.regs.gprs, ®s->gprs, sizeof(sregs->regs.gprs));  	memcpy(&user_sregs.regs.acrs, current->thread.acrs, -	       sizeof(sregs->regs.acrs)); +	       sizeof(user_sregs.regs.acrs));  	/*   	 * We have to store the fp registers to current->thread.fp_regs  	 * to merge them with the emulated registers.  	 */ -	save_fp_regs(¤t->thread.fp_regs); +	save_fp_ctl(¤t->thread.fp_regs.fpc); +	save_fp_regs(current->thread.fp_regs.fprs);  	memcpy(&user_sregs.fpregs, ¤t->thread.fp_regs, -	       sizeof(s390_fp_regs)); -	return __copy_to_user(sregs, &user_sregs, sizeof(_sigregs)); +	       sizeof(user_sregs.fpregs)); +	if (__copy_to_user(sregs, &user_sregs, sizeof(_sigregs))) +		return -EFAULT; +	return 0;  } -/* Returns positive number on error */  static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs)  { -	int err;  	_sigregs user_sregs;  	/* Alwys make any pending restarted system call return -EINTR */  	current_thread_info()->restart_block.fn = do_no_restart_syscall; -	err = __copy_from_user(&user_sregs, sregs, sizeof(_sigregs)); -	if (err) -		return err; -	/* Use regs->psw.mask instead of psw_user_bits to preserve PER bit. */ +	if (__copy_from_user(&user_sregs, sregs, sizeof(user_sregs))) +		return -EFAULT; + +	if (!is_ri_task(current) && (user_sregs.regs.psw.mask & PSW_MASK_RI)) +		return -EINVAL; + +	/* Loading the floating-point-control word can fail. Do that first. */ +	if (restore_fp_ctl(&user_sregs.fpregs.fpc)) +		return -EINVAL; + +	/* Use regs->psw.mask instead of PSW_USER_BITS to preserve PER bit. */  	regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) | -		(user_sregs.regs.psw.mask & PSW_MASK_USER); +		(user_sregs.regs.psw.mask & (PSW_MASK_USER | PSW_MASK_RI));  	/* Check for invalid user address space control. */ -	if ((regs->psw.mask & PSW_MASK_ASC) >= (psw_kernel_bits & PSW_MASK_ASC)) -		regs->psw.mask = (psw_user_bits & PSW_MASK_ASC) | +	if ((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_HOME) +		regs->psw.mask = PSW_ASC_PRIMARY |  			(regs->psw.mask & ~PSW_MASK_ASC);  	/* Check for invalid amode */  	if (regs->psw.mask & PSW_MASK_EA) @@ -98,14 +106,13 @@ static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs)  	regs->psw.addr = user_sregs.regs.psw.addr;  	memcpy(®s->gprs, &user_sregs.regs.gprs, sizeof(sregs->regs.gprs));  	memcpy(¤t->thread.acrs, &user_sregs.regs.acrs, -	       sizeof(sregs->regs.acrs)); +	       sizeof(current->thread.acrs));  	restore_access_regs(current->thread.acrs);  	memcpy(¤t->thread.fp_regs, &user_sregs.fpregs, -	       sizeof(s390_fp_regs)); -	current->thread.fp_regs.fpc &= FPC_VALID_MASK; +	       sizeof(current->thread.fp_regs)); -	restore_fp_regs(¤t->thread.fp_regs); +	restore_fp_regs(current->thread.fp_regs.fprs);  	clear_thread_flag(TIF_SYSCALL);	/* No longer in a system call */  	return 0;  } @@ -224,7 +231,7 @@ static int setup_frame(int sig, struct k_sigaction *ka,  	regs->gprs[15] = (unsigned long) frame;  	/* Force default amode and default user address space control. */  	regs->psw.mask = PSW_MASK_EA | PSW_MASK_BA | -		(psw_user_bits & PSW_MASK_ASC) | +		(PSW_USER_BITS & PSW_MASK_ASC) |  		(regs->psw.mask & ~PSW_MASK_ASC);  	regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE; @@ -295,7 +302,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,  	regs->gprs[15] = (unsigned long) frame;  	/* Force default amode and default user address space control. */  	regs->psw.mask = PSW_MASK_EA | PSW_MASK_BA | -		(psw_user_bits & PSW_MASK_ASC) | +		(PSW_USER_BITS & PSW_MASK_ASC) |  		(regs->psw.mask & ~PSW_MASK_ASC);  	regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE;  | 
