diff options
Diffstat (limited to 'arch/s390/kernel/traps.c')
-rw-r--r-- | arch/s390/kernel/traps.c | 37 |
1 files changed, 27 insertions, 10 deletions
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 01775c04a90e..29af52628e8b 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c | |||
@@ -57,6 +57,23 @@ static int kstack_depth_to_print = 12; | |||
57 | static int kstack_depth_to_print = 20; | 57 | static int kstack_depth_to_print = 20; |
58 | #endif /* CONFIG_64BIT */ | 58 | #endif /* CONFIG_64BIT */ |
59 | 59 | ||
60 | static inline void __user *get_trap_ip(struct pt_regs *regs) | ||
61 | { | ||
62 | #ifdef CONFIG_64BIT | ||
63 | unsigned long address; | ||
64 | |||
65 | if (regs->int_code & 0x200) | ||
66 | address = *(unsigned long *)(current->thread.trap_tdb + 24); | ||
67 | else | ||
68 | address = regs->psw.addr; | ||
69 | return (void __user *) | ||
70 | ((address - (regs->int_code >> 16)) & PSW_ADDR_INSN); | ||
71 | #else | ||
72 | return (void __user *) | ||
73 | ((regs->psw.addr - (regs->int_code >> 16)) & PSW_ADDR_INSN); | ||
74 | #endif | ||
75 | } | ||
76 | |||
60 | /* | 77 | /* |
61 | * For show_trace we have tree different stack to consider: | 78 | * For show_trace we have tree different stack to consider: |
62 | * - the panic stack which is used if the kernel stack has overflown | 79 | * - the panic stack which is used if the kernel stack has overflown |
@@ -285,12 +302,6 @@ int is_valid_bugaddr(unsigned long addr) | |||
285 | return 1; | 302 | return 1; |
286 | } | 303 | } |
287 | 304 | ||
288 | static inline void __user *get_psw_address(struct pt_regs *regs) | ||
289 | { | ||
290 | return (void __user *) | ||
291 | ((regs->psw.addr - (regs->int_code >> 16)) & PSW_ADDR_INSN); | ||
292 | } | ||
293 | |||
294 | static void __kprobes do_trap(struct pt_regs *regs, | 305 | static void __kprobes do_trap(struct pt_regs *regs, |
295 | int si_signo, int si_code, char *str) | 306 | int si_signo, int si_code, char *str) |
296 | { | 307 | { |
@@ -304,7 +315,7 @@ static void __kprobes do_trap(struct pt_regs *regs, | |||
304 | info.si_signo = si_signo; | 315 | info.si_signo = si_signo; |
305 | info.si_errno = 0; | 316 | info.si_errno = 0; |
306 | info.si_code = si_code; | 317 | info.si_code = si_code; |
307 | info.si_addr = get_psw_address(regs); | 318 | info.si_addr = get_trap_ip(regs); |
308 | force_sig_info(si_signo, &info, current); | 319 | force_sig_info(si_signo, &info, current); |
309 | report_user_fault(regs, si_signo); | 320 | report_user_fault(regs, si_signo); |
310 | } else { | 321 | } else { |
@@ -381,6 +392,11 @@ DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN, | |||
381 | DO_ERROR_INFO(translation_exception, SIGILL, ILL_ILLOPN, | 392 | DO_ERROR_INFO(translation_exception, SIGILL, ILL_ILLOPN, |
382 | "translation exception") | 393 | "translation exception") |
383 | 394 | ||
395 | #ifdef CONFIG_64BIT | ||
396 | DO_ERROR_INFO(transaction_exception, SIGILL, ILL_ILLOPN, | ||
397 | "transaction constraint exception") | ||
398 | #endif | ||
399 | |||
384 | static inline void do_fp_trap(struct pt_regs *regs, int fpc) | 400 | static inline void do_fp_trap(struct pt_regs *regs, int fpc) |
385 | { | 401 | { |
386 | int si_code = 0; | 402 | int si_code = 0; |
@@ -408,7 +424,7 @@ static void __kprobes illegal_op(struct pt_regs *regs) | |||
408 | __u16 __user *location; | 424 | __u16 __user *location; |
409 | int signal = 0; | 425 | int signal = 0; |
410 | 426 | ||
411 | location = get_psw_address(regs); | 427 | location = get_trap_ip(regs); |
412 | 428 | ||
413 | if (user_mode(regs)) { | 429 | if (user_mode(regs)) { |
414 | if (get_user(*((__u16 *) opcode), (__u16 __user *) location)) | 430 | if (get_user(*((__u16 *) opcode), (__u16 __user *) location)) |
@@ -476,7 +492,7 @@ void specification_exception(struct pt_regs *regs) | |||
476 | __u16 __user *location = NULL; | 492 | __u16 __user *location = NULL; |
477 | int signal = 0; | 493 | int signal = 0; |
478 | 494 | ||
479 | location = (__u16 __user *) get_psw_address(regs); | 495 | location = (__u16 __user *) get_trap_ip(regs); |
480 | 496 | ||
481 | if (user_mode(regs)) { | 497 | if (user_mode(regs)) { |
482 | get_user(*((__u16 *) opcode), location); | 498 | get_user(*((__u16 *) opcode), location); |
@@ -525,7 +541,7 @@ static void data_exception(struct pt_regs *regs) | |||
525 | __u16 __user *location; | 541 | __u16 __user *location; |
526 | int signal = 0; | 542 | int signal = 0; |
527 | 543 | ||
528 | location = get_psw_address(regs); | 544 | location = get_trap_ip(regs); |
529 | 545 | ||
530 | if (MACHINE_HAS_IEEE) | 546 | if (MACHINE_HAS_IEEE) |
531 | asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc)); | 547 | asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc)); |
@@ -641,6 +657,7 @@ void __init trap_init(void) | |||
641 | pgm_check_table[0x12] = &translation_exception; | 657 | pgm_check_table[0x12] = &translation_exception; |
642 | pgm_check_table[0x13] = &special_op_exception; | 658 | pgm_check_table[0x13] = &special_op_exception; |
643 | #ifdef CONFIG_64BIT | 659 | #ifdef CONFIG_64BIT |
660 | pgm_check_table[0x18] = &transaction_exception; | ||
644 | pgm_check_table[0x38] = &do_asce_exception; | 661 | pgm_check_table[0x38] = &do_asce_exception; |
645 | pgm_check_table[0x39] = &do_dat_exception; | 662 | pgm_check_table[0x39] = &do_dat_exception; |
646 | pgm_check_table[0x3A] = &do_dat_exception; | 663 | pgm_check_table[0x3A] = &do_dat_exception; |