Merge branch 'submit1' of viper:/spare/repo/irq-remove-2.6 into irqcleanups
[powerpc.git] / arch / s390 / kernel / traps.c
index b763043..05bf3cc 100644 (file)
@@ -14,7 +14,6 @@
  * 'Traps.c' handles hardware traps and faults after we have saved some
  * state in 'asm.s'.
  */
-#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
@@ -30,6 +29,7 @@
 #include <linux/module.h>
 #include <linux/kallsyms.h>
 #include <linux/reboot.h>
+#include <linux/kprobes.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -40,6 +40,7 @@
 #include <asm/s390_ext.h>
 #include <asm/lowcore.h>
 #include <asm/debug.h>
+#include <asm/kdebug.h>
 
 /* Called from entry.S only */
 extern void handle_per_exception(struct pt_regs *regs);
@@ -60,7 +61,7 @@ extern pgm_check_handler_t do_dat_exception;
 #ifdef CONFIG_PFAULT
 extern int pfault_init(void);
 extern void pfault_fini(void);
-extern void pfault_interrupt(struct pt_regs *regs, __u16 error_code);
+extern void pfault_interrupt(__u16 error_code);
 static ext_int_info_t ext_int_pfault;
 #endif
 extern pgm_check_handler_t do_monitor_call;
@@ -75,6 +76,20 @@ static int kstack_depth_to_print = 12;
 static int kstack_depth_to_print = 20;
 #endif /* CONFIG_64BIT */
 
+ATOMIC_NOTIFIER_HEAD(s390die_chain);
+
+int register_die_notifier(struct notifier_block *nb)
+{
+       return atomic_notifier_chain_register(&s390die_chain, nb);
+}
+EXPORT_SYMBOL(register_die_notifier);
+
+int unregister_die_notifier(struct notifier_block *nb)
+{
+       return atomic_notifier_chain_unregister(&s390die_chain, nb);
+}
+EXPORT_SYMBOL(unregister_die_notifier);
+
 /*
  * For show_trace we have tree different stack to consider:
  *   - the panic stack which is used if the kernel stack has overflown
@@ -171,7 +186,7 @@ void show_stack(struct task_struct *task, unsigned long *sp)
  */
 void dump_stack(void)
 {
-       show_stack(0, 0);
+       show_stack(NULL, NULL);
 }
 
 EXPORT_SYMBOL(dump_stack);
@@ -306,8 +321,9 @@ report_user_fault(long interruption_code, struct pt_regs *regs)
 #endif
 }
 
-static void inline do_trap(long interruption_code, int signr, char *str,
-                           struct pt_regs *regs, siginfo_t *info)
+static void __kprobes inline do_trap(long interruption_code, int signr,
+                                       char *str, struct pt_regs *regs,
+                                       siginfo_t *info)
 {
        /*
         * We got all needed information from the lowcore and can
@@ -316,6 +332,10 @@ static void inline do_trap(long interruption_code, int signr, char *str,
         if (regs->psw.mask & PSW_MASK_PSTATE)
                local_irq_enable();
 
+       if (notify_die(DIE_TRAP, str, regs, interruption_code,
+                               interruption_code, signr) == NOTIFY_STOP)
+               return;
+
         if (regs->psw.mask & PSW_MASK_PSTATE) {
                 struct task_struct *tsk = current;
 
@@ -332,13 +352,17 @@ static void inline do_trap(long interruption_code, int signr, char *str,
         }
 }
 
-static inline void *get_check_address(struct pt_regs *regs)
+static inline void __user *get_check_address(struct pt_regs *regs)
 {
-       return (void *)((regs->psw.addr-S390_lowcore.pgm_ilc) & PSW_ADDR_INSN);
+       return (void __user *)((regs->psw.addr-S390_lowcore.pgm_ilc) & PSW_ADDR_INSN);
 }
 
-void do_single_step(struct pt_regs *regs)
+void __kprobes do_single_step(struct pt_regs *regs)
 {
+       if (notify_die(DIE_SSTEP, "sstep", regs, 0, 0,
+                                       SIGTRAP) == NOTIFY_STOP){
+               return;
+       }
        if ((current->ptrace & PT_PTRACED) != 0)
                force_sig(SIGTRAP, current);
 }
@@ -361,7 +385,7 @@ asmlinkage void name(struct pt_regs * regs, long interruption_code) \
         info.si_signo = signr; \
         info.si_errno = 0; \
         info.si_code = sicode; \
-        info.si_addr = (void *)siaddr; \
+       info.si_addr = siaddr; \
         do_trap(interruption_code, signr, str, regs, &info); \
 }
 
@@ -393,7 +417,7 @@ DO_ERROR_INFO(SIGILL,  "translation exception", translation_exception,
              ILL_ILLOPN, get_check_address(regs))
 
 static inline void
-do_fp_trap(struct pt_regs *regs, void *location,
+do_fp_trap(struct pt_regs *regs, void __user *location,
            int fpc, long interruption_code)
 {
        siginfo_t si;
@@ -425,10 +449,10 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
 {
        siginfo_t info;
         __u8 opcode[6];
-       __u16 *location;
+       __u16 __user *location;
        int signal = 0;
 
-       location = (__u16 *) get_check_address(regs);
+       location = get_check_address(regs);
 
        /*
         * We got all needed information from the lowcore and can
@@ -560,10 +584,10 @@ DO_ERROR_INFO(SIGILL, "specification exception", specification_exception,
 
 asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
 {
-       __u16 *location;
+       __u16 __user *location;
        int signal = 0;
 
-       location = (__u16 *) get_check_address(regs);
+       location = get_check_address(regs);
 
        /*
         * We got all needed information from the lowcore and can
@@ -573,8 +597,7 @@ asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
                local_irq_enable();
 
        if (MACHINE_HAS_IEEE)
-               __asm__ volatile ("stfpc %0\n\t" 
-                                 : "=m" (current->thread.fp_regs.fpc));
+               asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc));
 
 #ifdef CONFIG_MATHEMU
         else if (regs->psw.mask & PSW_MASK_PSTATE) {