diff options
Diffstat (limited to 'arch/s390/kernel/traps.c')
| -rw-r--r-- | arch/s390/kernel/traps.c | 170 | 
1 files changed, 60 insertions, 110 deletions
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index a9807dd8627..5ce3750b181 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -43,9 +43,9 @@  #include <asm/debug.h>  #include "entry.h" -void (*pgm_check_table[128])(struct pt_regs *, long, unsigned long); +void (*pgm_check_table[128])(struct pt_regs *regs); -int show_unhandled_signals; +int show_unhandled_signals = 1;  #define stack_pointer ({ void **sp; asm("la %0,0(15)" : "=&d" (sp)); sp; }) @@ -234,7 +234,7 @@ void show_regs(struct pt_regs *regs)  static DEFINE_SPINLOCK(die_lock); -void die(const char * str, struct pt_regs * regs, long err) +void die(struct pt_regs *regs, const char *str)  {  	static int die_counter; @@ -243,7 +243,7 @@ void die(const char * str, struct pt_regs * regs, long err)  	console_verbose();  	spin_lock_irq(&die_lock);  	bust_spinlocks(1); -	printk("%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter); +	printk("%s: %04x [#%d] ", str, regs->int_code & 0xffff, ++die_counter);  #ifdef CONFIG_PREEMPT  	printk("PREEMPT ");  #endif @@ -254,7 +254,7 @@ void die(const char * str, struct pt_regs * regs, long err)  	printk("DEBUG_PAGEALLOC");  #endif  	printk("\n"); -	notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV); +	notify_die(DIE_OOPS, str, regs, 0, regs->int_code & 0xffff, SIGSEGV);  	show_regs(regs);  	bust_spinlocks(0);  	add_taint(TAINT_DIE); @@ -267,8 +267,7 @@ void die(const char * str, struct pt_regs * regs, long err)  	do_exit(SIGSEGV);  } -static void inline report_user_fault(struct pt_regs *regs, long int_code, -				     int signr) +static inline void report_user_fault(struct pt_regs *regs, int signr)  {  	if ((task_pid_nr(current) > 1) && !show_unhandled_signals)  		return; @@ -276,7 +275,7 @@ static void inline report_user_fault(struct pt_regs *regs, long int_code,  		return;  	if (!printk_ratelimit())  		return; -	printk("User process fault: interruption code 0x%lX ", int_code); +	printk("User process fault: interruption code 0x%X ", regs->int_code);  	print_vma_addr("in ", regs->psw.addr & PSW_ADDR_INSN);  	printk("\n");  	show_regs(regs); @@ -287,19 +286,28 @@ int is_valid_bugaddr(unsigned long addr)  	return 1;  } -static inline void __kprobes do_trap(long pgm_int_code, int signr, char *str, -				     struct pt_regs *regs, siginfo_t *info) +static inline void __user *get_psw_address(struct pt_regs *regs)  { -	if (notify_die(DIE_TRAP, str, regs, pgm_int_code, -		       pgm_int_code, signr) == NOTIFY_STOP) +	return (void __user *) +		((regs->psw.addr - (regs->int_code >> 16)) & PSW_ADDR_INSN); +} + +static void __kprobes do_trap(struct pt_regs *regs, +			      int si_signo, int si_code, char *str) +{ +	siginfo_t info; + +	if (notify_die(DIE_TRAP, str, regs, 0, +		       regs->int_code, si_signo) == NOTIFY_STOP)  		return;          if (regs->psw.mask & PSW_MASK_PSTATE) { -                struct task_struct *tsk = current; - -		tsk->thread.trap_no = pgm_int_code & 0xffff; -		force_sig_info(signr, info, tsk); -		report_user_fault(regs, pgm_int_code, signr); +		info.si_signo = si_signo; +		info.si_errno = 0; +		info.si_code = si_code; +		info.si_addr = get_psw_address(regs); +		force_sig_info(si_signo, &info, current); +		report_user_fault(regs, si_signo);          } else {                  const struct exception_table_entry *fixup;                  fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN); @@ -311,18 +319,11 @@ static inline void __kprobes do_trap(long pgm_int_code, int signr, char *str,  			btt = report_bug(regs->psw.addr & PSW_ADDR_INSN, regs);  			if (btt == BUG_TRAP_TYPE_WARN)  				return; -			die(str, regs, pgm_int_code); +			die(regs, str);  		}          }  } -static inline void __user *get_psw_address(struct pt_regs *regs, -					   long pgm_int_code) -{ -	return (void __user *) -		((regs->psw.addr - (pgm_int_code >> 16)) & PSW_ADDR_INSN); -} -  void __kprobes do_per_trap(struct pt_regs *regs)  {  	siginfo_t info; @@ -339,26 +340,19 @@ void __kprobes do_per_trap(struct pt_regs *regs)  	force_sig_info(SIGTRAP, &info, current);  } -static void default_trap_handler(struct pt_regs *regs, long pgm_int_code, -				 unsigned long trans_exc_code) +static void default_trap_handler(struct pt_regs *regs)  {          if (regs->psw.mask & PSW_MASK_PSTATE) { -		report_user_fault(regs, pgm_int_code, SIGSEGV); +		report_user_fault(regs, SIGSEGV);  		do_exit(SIGSEGV);  	} else -		die("Unknown program exception", regs, pgm_int_code); +		die(regs, "Unknown program exception");  }  #define DO_ERROR_INFO(name, signr, sicode, str) \ -static void name(struct pt_regs *regs, long pgm_int_code, \ -		 unsigned long trans_exc_code) \ +static void name(struct pt_regs *regs) \  { \ -        siginfo_t info; \ -        info.si_signo = signr; \ -        info.si_errno = 0; \ -        info.si_code = sicode; \ -	info.si_addr = get_psw_address(regs, pgm_int_code); \ -	do_trap(pgm_int_code, signr, str, regs, &info);	    \ +	do_trap(regs, signr, sicode, str); \  }  DO_ERROR_INFO(addressing_exception, SIGILL, ILL_ILLADR, @@ -388,42 +382,34 @@ DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN,  DO_ERROR_INFO(translation_exception, SIGILL, ILL_ILLOPN,  	      "translation exception") -static inline void do_fp_trap(struct pt_regs *regs, void __user *location, -			      int fpc, long pgm_int_code) +static inline void do_fp_trap(struct pt_regs *regs, int fpc)  { -	siginfo_t si; - -	si.si_signo = SIGFPE; -	si.si_errno = 0; -	si.si_addr = location; -	si.si_code = 0; +	int si_code = 0;  	/* FPC[2] is Data Exception Code */  	if ((fpc & 0x00000300) == 0) {  		/* bits 6 and 7 of DXC are 0 iff IEEE exception */  		if (fpc & 0x8000) /* invalid fp operation */ -			si.si_code = FPE_FLTINV; +			si_code = FPE_FLTINV;  		else if (fpc & 0x4000) /* div by 0 */ -			si.si_code = FPE_FLTDIV; +			si_code = FPE_FLTDIV;  		else if (fpc & 0x2000) /* overflow */ -			si.si_code = FPE_FLTOVF; +			si_code = FPE_FLTOVF;  		else if (fpc & 0x1000) /* underflow */ -			si.si_code = FPE_FLTUND; +			si_code = FPE_FLTUND;  		else if (fpc & 0x0800) /* inexact */ -			si.si_code = FPE_FLTRES; +			si_code = FPE_FLTRES;  	} -	do_trap(pgm_int_code, SIGFPE, -		"floating point exception", regs, &si); +	do_trap(regs, SIGFPE, si_code, "floating point exception");  } -static void __kprobes illegal_op(struct pt_regs *regs, long pgm_int_code, -				 unsigned long trans_exc_code) +static void __kprobes illegal_op(struct pt_regs *regs)  {  	siginfo_t info;          __u8 opcode[6];  	__u16 __user *location;  	int signal = 0; -	location = get_psw_address(regs, pgm_int_code); +	location = get_psw_address(regs);  	if (regs->psw.mask & PSW_MASK_PSTATE) {  		if (get_user(*((__u16 *) opcode), (__u16 __user *) location)) @@ -467,44 +453,31 @@ static void __kprobes illegal_op(struct pt_regs *regs, long pgm_int_code,  		 * If we get an illegal op in kernel mode, send it through the  		 * kprobes notifier. If kprobes doesn't pick it up, SIGILL  		 */ -		if (notify_die(DIE_BPT, "bpt", regs, pgm_int_code, +		if (notify_die(DIE_BPT, "bpt", regs, 0,  			       3, SIGTRAP) != NOTIFY_STOP)  			signal = SIGILL;  	}  #ifdef CONFIG_MATHEMU          if (signal == SIGFPE) -		do_fp_trap(regs, location, -			   current->thread.fp_regs.fpc, pgm_int_code); -        else if (signal == SIGSEGV) { -		info.si_signo = signal; -		info.si_errno = 0; -		info.si_code = SEGV_MAPERR; -		info.si_addr = (void __user *) location; -		do_trap(pgm_int_code, signal, -			"user address fault", regs, &info); -	} else +		do_fp_trap(regs, current->thread.fp_regs.fpc); +	else if (signal == SIGSEGV) +		do_trap(regs, signal, SEGV_MAPERR, "user address fault"); +	else  #endif -        if (signal) { -		info.si_signo = signal; -		info.si_errno = 0; -		info.si_code = ILL_ILLOPC; -		info.si_addr = (void __user *) location; -		do_trap(pgm_int_code, signal, -			"illegal operation", regs, &info); -	} +	if (signal) +		do_trap(regs, signal, ILL_ILLOPC, "illegal operation");  }  #ifdef CONFIG_MATHEMU -void specification_exception(struct pt_regs *regs, long pgm_int_code, -			     unsigned long trans_exc_code) +void specification_exception(struct pt_regs *regs)  {          __u8 opcode[6];  	__u16 __user *location = NULL;  	int signal = 0; -	location = (__u16 __user *) get_psw_address(regs, pgm_int_code); +	location = (__u16 __user *) get_psw_address(regs);          if (regs->psw.mask & PSW_MASK_PSTATE) {  		get_user(*((__u16 *) opcode), location); @@ -539,30 +512,21 @@ void specification_exception(struct pt_regs *regs, long pgm_int_code,  		signal = SIGILL;          if (signal == SIGFPE) -		do_fp_trap(regs, location, -			   current->thread.fp_regs.fpc, pgm_int_code); -        else if (signal) { -		siginfo_t info; -		info.si_signo = signal; -		info.si_errno = 0; -		info.si_code = ILL_ILLOPN; -		info.si_addr = location; -		do_trap(pgm_int_code, signal, -			"specification exception", regs, &info); -	} +		do_fp_trap(regs, current->thread.fp_regs.fpc); +	else if (signal) +		do_trap(regs, signal, ILL_ILLOPN, "specification exception");  }  #else  DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN,  	      "specification exception");  #endif -static void data_exception(struct pt_regs *regs, long pgm_int_code, -			   unsigned long trans_exc_code) +static void data_exception(struct pt_regs *regs)  {  	__u16 __user *location;  	int signal = 0; -	location = get_psw_address(regs, pgm_int_code); +	location = get_psw_address(regs);  	if (MACHINE_HAS_IEEE)  		asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc)); @@ -627,32 +591,18 @@ static void data_exception(struct pt_regs *regs, long pgm_int_code,  	else  		signal = SIGILL;          if (signal == SIGFPE) -		do_fp_trap(regs, location, -			   current->thread.fp_regs.fpc, pgm_int_code); -        else if (signal) { -		siginfo_t info; -		info.si_signo = signal; -		info.si_errno = 0; -		info.si_code = ILL_ILLOPN; -		info.si_addr = location; -		do_trap(pgm_int_code, signal, "data exception", regs, &info); -	} +		do_fp_trap(regs, current->thread.fp_regs.fpc); +	else if (signal) +		do_trap(regs, signal, ILL_ILLOPN, "data exception");  } -static void space_switch_exception(struct pt_regs *regs, long pgm_int_code, -				   unsigned long trans_exc_code) +static void space_switch_exception(struct pt_regs *regs)  { -        siginfo_t info; -  	/* Set user psw back to home space mode. */  	if (regs->psw.mask & PSW_MASK_PSTATE)  		regs->psw.mask |= PSW_ASC_HOME;  	/* Send SIGILL. */ -        info.si_signo = SIGILL; -        info.si_errno = 0; -        info.si_code = ILL_PRVOPC; -	info.si_addr = get_psw_address(regs, pgm_int_code); -	do_trap(pgm_int_code, SIGILL, "space switch event", regs, &info); +	do_trap(regs, SIGILL, ILL_PRVOPC, "space switch event");  }  void __kprobes kernel_stack_overflow(struct pt_regs * regs)  |