diff options
-rw-r--r-- | arch/powerpc/include/asm/hw_breakpoint.h | 3 | ||||
-rw-r--r-- | arch/powerpc/kernel/hw_breakpoint.c | 18 | ||||
-rw-r--r-- | arch/powerpc/kernel/signal.c | 3 |
3 files changed, 24 insertions, 0 deletions
diff --git a/arch/powerpc/include/asm/hw_breakpoint.h b/arch/powerpc/include/asm/hw_breakpoint.h index b111713b593e..6576bad1069c 100644 --- a/arch/powerpc/include/asm/hw_breakpoint.h +++ b/arch/powerpc/include/asm/hw_breakpoint.h | |||
@@ -65,9 +65,12 @@ static inline void hw_breakpoint_disable(void) | |||
65 | { | 65 | { |
66 | set_dabr(0); | 66 | set_dabr(0); |
67 | } | 67 | } |
68 | extern void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs); | ||
68 | 69 | ||
69 | #else /* CONFIG_HAVE_HW_BREAKPOINT */ | 70 | #else /* CONFIG_HAVE_HW_BREAKPOINT */ |
70 | static inline void hw_breakpoint_disable(void) { } | 71 | static inline void hw_breakpoint_disable(void) { } |
72 | static inline void thread_change_pc(struct task_struct *tsk, | ||
73 | struct pt_regs *regs) { } | ||
71 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ | 74 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ |
72 | #endif /* __KERNEL__ */ | 75 | #endif /* __KERNEL__ */ |
73 | #endif /* _PPC_BOOK3S_64_HW_BREAKPOINT_H */ | 76 | #endif /* _PPC_BOOK3S_64_HW_BREAKPOINT_H */ |
diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c index 7a2ad5e84c16..7bd01a56d194 100644 --- a/arch/powerpc/kernel/hw_breakpoint.c +++ b/arch/powerpc/kernel/hw_breakpoint.c | |||
@@ -175,6 +175,24 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) | |||
175 | } | 175 | } |
176 | 176 | ||
177 | /* | 177 | /* |
178 | * Restores the breakpoint on the debug registers. | ||
179 | * Invoke this function if it is known that the execution context is | ||
180 | * about to change to cause loss of MSR_SE settings. | ||
181 | */ | ||
182 | void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs) | ||
183 | { | ||
184 | struct arch_hw_breakpoint *info; | ||
185 | |||
186 | if (likely(!tsk->thread.last_hit_ubp)) | ||
187 | return; | ||
188 | |||
189 | info = counter_arch_bp(tsk->thread.last_hit_ubp); | ||
190 | regs->msr &= ~MSR_SE; | ||
191 | set_dabr(info->address | info->type | DABR_TRANSLATION); | ||
192 | tsk->thread.last_hit_ubp = NULL; | ||
193 | } | ||
194 | |||
195 | /* | ||
178 | * Handle debug exception notifications. | 196 | * Handle debug exception notifications. |
179 | */ | 197 | */ |
180 | int __kprobes hw_breakpoint_handler(struct die_args *args) | 198 | int __kprobes hw_breakpoint_handler(struct die_args *args) |
diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c index a0afb555a7c9..7109f5b1baa8 100644 --- a/arch/powerpc/kernel/signal.c +++ b/arch/powerpc/kernel/signal.c | |||
@@ -11,6 +11,7 @@ | |||
11 | 11 | ||
12 | #include <linux/tracehook.h> | 12 | #include <linux/tracehook.h> |
13 | #include <linux/signal.h> | 13 | #include <linux/signal.h> |
14 | #include <asm/hw_breakpoint.h> | ||
14 | #include <asm/uaccess.h> | 15 | #include <asm/uaccess.h> |
15 | #include <asm/unistd.h> | 16 | #include <asm/unistd.h> |
16 | 17 | ||
@@ -149,6 +150,8 @@ static int do_signal_pending(sigset_t *oldset, struct pt_regs *regs) | |||
149 | if (current->thread.dabr) | 150 | if (current->thread.dabr) |
150 | set_dabr(current->thread.dabr); | 151 | set_dabr(current->thread.dabr); |
151 | #endif | 152 | #endif |
153 | /* Re-enable the breakpoints for the signal stack */ | ||
154 | thread_change_pc(current, regs); | ||
152 | 155 | ||
153 | if (is32) { | 156 | if (is32) { |
154 | if (ka.sa.sa_flags & SA_SIGINFO) | 157 | if (ka.sa.sa_flags & SA_SIGINFO) |