diff options
Diffstat (limited to 'arch/s390/mm/fault.c')
-rw-r--r-- | arch/s390/mm/fault.c | 40 |
1 files changed, 39 insertions, 1 deletions
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 7cd82575813d..44f0cda7e72e 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c | |||
@@ -25,10 +25,12 @@ | |||
25 | #include <linux/console.h> | 25 | #include <linux/console.h> |
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/hardirq.h> | 27 | #include <linux/hardirq.h> |
28 | #include <linux/kprobes.h> | ||
28 | 29 | ||
29 | #include <asm/system.h> | 30 | #include <asm/system.h> |
30 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
31 | #include <asm/pgtable.h> | 32 | #include <asm/pgtable.h> |
33 | #include <asm/kdebug.h> | ||
32 | 34 | ||
33 | #ifndef CONFIG_64BIT | 35 | #ifndef CONFIG_64BIT |
34 | #define __FAIL_ADDR_MASK 0x7ffff000 | 36 | #define __FAIL_ADDR_MASK 0x7ffff000 |
@@ -48,6 +50,38 @@ extern int sysctl_userprocess_debug; | |||
48 | 50 | ||
49 | extern void die(const char *,struct pt_regs *,long); | 51 | extern void die(const char *,struct pt_regs *,long); |
50 | 52 | ||
53 | #ifdef CONFIG_KPROBES | ||
54 | ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain); | ||
55 | int register_page_fault_notifier(struct notifier_block *nb) | ||
56 | { | ||
57 | return atomic_notifier_chain_register(¬ify_page_fault_chain, nb); | ||
58 | } | ||
59 | |||
60 | int unregister_page_fault_notifier(struct notifier_block *nb) | ||
61 | { | ||
62 | return atomic_notifier_chain_unregister(¬ify_page_fault_chain, nb); | ||
63 | } | ||
64 | |||
65 | static inline int notify_page_fault(enum die_val val, const char *str, | ||
66 | struct pt_regs *regs, long err, int trap, int sig) | ||
67 | { | ||
68 | struct die_args args = { | ||
69 | .regs = regs, | ||
70 | .str = str, | ||
71 | .err = err, | ||
72 | .trapnr = trap, | ||
73 | .signr = sig | ||
74 | }; | ||
75 | return atomic_notifier_call_chain(¬ify_page_fault_chain, val, &args); | ||
76 | } | ||
77 | #else | ||
78 | static inline int notify_page_fault(enum die_val val, const char *str, | ||
79 | struct pt_regs *regs, long err, int trap, int sig) | ||
80 | { | ||
81 | return NOTIFY_DONE; | ||
82 | } | ||
83 | #endif | ||
84 | |||
51 | extern spinlock_t timerlist_lock; | 85 | extern spinlock_t timerlist_lock; |
52 | 86 | ||
53 | /* | 87 | /* |
@@ -159,7 +193,7 @@ static void do_sigsegv(struct pt_regs *regs, unsigned long error_code, | |||
159 | * 11 Page translation -> Not present (nullification) | 193 | * 11 Page translation -> Not present (nullification) |
160 | * 3b Region third trans. -> Not present (nullification) | 194 | * 3b Region third trans. -> Not present (nullification) |
161 | */ | 195 | */ |
162 | static inline void | 196 | static inline void __kprobes |
163 | do_exception(struct pt_regs *regs, unsigned long error_code, int is_protection) | 197 | do_exception(struct pt_regs *regs, unsigned long error_code, int is_protection) |
164 | { | 198 | { |
165 | struct task_struct *tsk; | 199 | struct task_struct *tsk; |
@@ -173,6 +207,10 @@ do_exception(struct pt_regs *regs, unsigned long error_code, int is_protection) | |||
173 | tsk = current; | 207 | tsk = current; |
174 | mm = tsk->mm; | 208 | mm = tsk->mm; |
175 | 209 | ||
210 | if (notify_page_fault(DIE_PAGE_FAULT, "page fault", regs, error_code, 14, | ||
211 | SIGSEGV) == NOTIFY_STOP) | ||
212 | return; | ||
213 | |||
176 | /* | 214 | /* |
177 | * Check for low-address protection. This needs to be treated | 215 | * Check for low-address protection. This needs to be treated |
178 | * as a special case because the translation exception code | 216 | * as a special case because the translation exception code |