diff options
Diffstat (limited to 'arch/s390/kernel/traps.c')
-rw-r--r-- | arch/s390/kernel/traps.c | 41 |
1 files changed, 29 insertions, 12 deletions
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 01775c04a90e..3d2b0fa37db0 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -57,6 +57,23 @@ static int kstack_depth_to_print = 12; static int kstack_depth_to_print = 20; #endif /* CONFIG_64BIT */ +static inline void __user *get_trap_ip(struct pt_regs *regs) +{ +#ifdef CONFIG_64BIT + unsigned long address; + + if (regs->int_code & 0x200) + address = *(unsigned long *)(current->thread.trap_tdb + 24); + else + address = regs->psw.addr; + return (void __user *) + ((address - (regs->int_code >> 16)) & PSW_ADDR_INSN); +#else + return (void __user *) + ((regs->psw.addr - (regs->int_code >> 16)) & PSW_ADDR_INSN); +#endif +} + /* * For show_trace we have tree different stack to consider: * - the panic stack which is used if the kernel stack has overflown @@ -214,7 +231,6 @@ void show_registers(struct pt_regs *regs) void show_regs(struct pt_regs *regs) { - print_modules(); printk("CPU: %d %s %s %.*s\n", task_thread_info(current)->cpu, print_tainted(), init_utsname()->release, @@ -254,6 +270,7 @@ void die(struct pt_regs *regs, const char *str) #endif printk("\n"); notify_die(DIE_OOPS, str, regs, 0, regs->int_code & 0xffff, SIGSEGV); + print_modules(); show_regs(regs); bust_spinlocks(0); add_taint(TAINT_DIE); @@ -285,12 +302,6 @@ int is_valid_bugaddr(unsigned long addr) return 1; } -static inline void __user *get_psw_address(struct pt_regs *regs) -{ - 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) { @@ -304,14 +315,14 @@ static void __kprobes do_trap(struct pt_regs *regs, info.si_signo = si_signo; info.si_errno = 0; info.si_code = si_code; - info.si_addr = get_psw_address(regs); + info.si_addr = get_trap_ip(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); if (fixup) - regs->psw.addr = fixup->fixup | PSW_ADDR_AMODE; + regs->psw.addr = extable_fixup(fixup) | PSW_ADDR_AMODE; else { enum bug_trap_type btt; @@ -381,6 +392,11 @@ DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN, DO_ERROR_INFO(translation_exception, SIGILL, ILL_ILLOPN, "translation exception") +#ifdef CONFIG_64BIT +DO_ERROR_INFO(transaction_exception, SIGILL, ILL_ILLOPN, + "transaction constraint exception") +#endif + static inline void do_fp_trap(struct pt_regs *regs, int fpc) { int si_code = 0; @@ -408,7 +424,7 @@ static void __kprobes illegal_op(struct pt_regs *regs) __u16 __user *location; int signal = 0; - location = get_psw_address(regs); + location = get_trap_ip(regs); if (user_mode(regs)) { if (get_user(*((__u16 *) opcode), (__u16 __user *) location)) @@ -476,7 +492,7 @@ void specification_exception(struct pt_regs *regs) __u16 __user *location = NULL; int signal = 0; - location = (__u16 __user *) get_psw_address(regs); + location = (__u16 __user *) get_trap_ip(regs); if (user_mode(regs)) { get_user(*((__u16 *) opcode), location); @@ -525,7 +541,7 @@ static void data_exception(struct pt_regs *regs) __u16 __user *location; int signal = 0; - location = get_psw_address(regs); + location = get_trap_ip(regs); if (MACHINE_HAS_IEEE) asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc)); @@ -641,6 +657,7 @@ void __init trap_init(void) pgm_check_table[0x12] = &translation_exception; pgm_check_table[0x13] = &special_op_exception; #ifdef CONFIG_64BIT + pgm_check_table[0x18] = &transaction_exception; pgm_check_table[0x38] = &do_asce_exception; pgm_check_table[0x39] = &do_dat_exception; pgm_check_table[0x3A] = &do_dat_exception; |