aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorK.Prasad <prasad@linux.vnet.ibm.com>2010-06-15 02:05:19 -0400
committerPaul Mackerras <paulus@samba.org>2010-06-22 05:40:50 -0400
commit5aae8a53708025d4e718f0d2e7c2f766779ddc71 (patch)
treed151e2c29e78248cee620cf5094a15316abd17d2 /arch/powerpc
parentf7136c5150c29846d7a1d09109449d96b2f63445 (diff)
powerpc, hw_breakpoints: Implement hw_breakpoints for 64-bit server processors
Implement perf-events based hw-breakpoint interfaces for PowerPC 64-bit server (Book III S) processors. This allows access to a given location to be used as an event that can be counted or profiled by the perf_events subsystem. This is done using the DABR (data breakpoint register), which can also be used for process debugging via ptrace. When perf_event hw_breakpoint support is configured in, the perf_event subsystem manages the DABR and arbitrates access to it, and ptrace then creates a perf_event when it is requested to set a data breakpoint. [Adopted suggestions from Paul Mackerras <paulus@samba.org> to - emulate_step() all system-wide breakpoints and single-step only the per-task breakpoints - perform arch-specific cleanup before unregistration through arch_unregister_hw_breakpoint() ] Signed-off-by: K.Prasad <prasad@linux.vnet.ibm.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/Kconfig1
-rw-r--r--arch/powerpc/include/asm/cputable.h4
-rw-r--r--arch/powerpc/include/asm/hw_breakpoint.h73
-rw-r--r--arch/powerpc/include/asm/processor.h8
-rw-r--r--arch/powerpc/kernel/Makefile1
-rw-r--r--arch/powerpc/kernel/exceptions-64s.S1
-rw-r--r--arch/powerpc/kernel/hw_breakpoint.c325
-rw-r--r--arch/powerpc/kernel/machine_kexec_64.c3
-rw-r--r--arch/powerpc/kernel/process.c14
-rw-r--r--arch/powerpc/kernel/ptrace.c64
-rw-r--r--arch/powerpc/lib/Makefile1
11 files changed, 495 insertions, 0 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 328774bd41ee..7949afc861dd 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -141,6 +141,7 @@ config PPC
141 select GENERIC_ATOMIC64 if PPC32 141 select GENERIC_ATOMIC64 if PPC32
142 select HAVE_PERF_EVENTS 142 select HAVE_PERF_EVENTS
143 select HAVE_REGS_AND_STACK_ACCESS_API 143 select HAVE_REGS_AND_STACK_ACCESS_API
144 select HAVE_HW_BREAKPOINT if PERF_EVENTS && PPC_BOOK3S_64
144 145
145config EARLY_PRINTK 146config EARLY_PRINTK
146 bool 147 bool
diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index b0b21134f61a..5e2e2cfcc81b 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -517,6 +517,10 @@ static inline int cpu_has_feature(unsigned long feature)
517 & feature); 517 & feature);
518} 518}
519 519
520#ifdef CONFIG_HAVE_HW_BREAKPOINT
521#define HBP_NUM 1
522#endif /* CONFIG_HAVE_HW_BREAKPOINT */
523
520#endif /* !__ASSEMBLY__ */ 524#endif /* !__ASSEMBLY__ */
521 525
522#endif /* __KERNEL__ */ 526#endif /* __KERNEL__ */
diff --git a/arch/powerpc/include/asm/hw_breakpoint.h b/arch/powerpc/include/asm/hw_breakpoint.h
new file mode 100644
index 000000000000..b111713b593e
--- /dev/null
+++ b/arch/powerpc/include/asm/hw_breakpoint.h
@@ -0,0 +1,73 @@
1/*
2 * PowerPC BookIII S hardware breakpoint definitions
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 *
18 * Copyright 2010, IBM Corporation.
19 * Author: K.Prasad <prasad@linux.vnet.ibm.com>
20 *
21 */
22
23#ifndef _PPC_BOOK3S_64_HW_BREAKPOINT_H
24#define _PPC_BOOK3S_64_HW_BREAKPOINT_H
25
26#ifdef __KERNEL__
27#ifdef CONFIG_HAVE_HW_BREAKPOINT
28
29struct arch_hw_breakpoint {
30 u8 len; /* length of the target data symbol */
31 int type;
32 unsigned long address;
33};
34
35#include <linux/kdebug.h>
36#include <asm/reg.h>
37#include <asm/system.h>
38
39static inline int hw_breakpoint_slots(int type)
40{
41 return HBP_NUM;
42}
43struct perf_event;
44struct pmu;
45struct perf_sample_data;
46
47#define HW_BREAKPOINT_ALIGN 0x7
48/* Maximum permissible length of any HW Breakpoint */
49#define HW_BREAKPOINT_LEN 0x8
50
51extern int arch_bp_generic_fields(int type, int *gen_bp_type);
52extern int arch_check_bp_in_kernelspace(struct perf_event *bp);
53extern int arch_validate_hwbkpt_settings(struct perf_event *bp);
54extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
55 unsigned long val, void *data);
56int arch_install_hw_breakpoint(struct perf_event *bp);
57void arch_uninstall_hw_breakpoint(struct perf_event *bp);
58void hw_breakpoint_pmu_read(struct perf_event *bp);
59extern void flush_ptrace_hw_breakpoint(struct task_struct *tsk);
60
61extern struct pmu perf_ops_bp;
62extern void ptrace_triggered(struct perf_event *bp, int nmi,
63 struct perf_sample_data *data, struct pt_regs *regs);
64static inline void hw_breakpoint_disable(void)
65{
66 set_dabr(0);
67}
68
69#else /* CONFIG_HAVE_HW_BREAKPOINT */
70static inline void hw_breakpoint_disable(void) { }
71#endif /* CONFIG_HAVE_HW_BREAKPOINT */
72#endif /* __KERNEL__ */
73#endif /* _PPC_BOOK3S_64_HW_BREAKPOINT_H */
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index 7492fe8ad6e4..19c05b0f74be 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -209,6 +209,14 @@ struct thread_struct {
209#ifdef CONFIG_PPC64 209#ifdef CONFIG_PPC64
210 unsigned long start_tb; /* Start purr when proc switched in */ 210 unsigned long start_tb; /* Start purr when proc switched in */
211 unsigned long accum_tb; /* Total accumilated purr for process */ 211 unsigned long accum_tb; /* Total accumilated purr for process */
212#ifdef CONFIG_HAVE_HW_BREAKPOINT
213 struct perf_event *ptrace_bps[HBP_NUM];
214 /*
215 * Helps identify source of single-step exception and subsequent
216 * hw-breakpoint enablement
217 */
218 struct perf_event *last_hit_ubp;
219#endif /* CONFIG_HAVE_HW_BREAKPOINT */
212#endif 220#endif
213 unsigned long dabr; /* Data address breakpoint register */ 221 unsigned long dabr; /* Data address breakpoint register */
214#ifdef CONFIG_ALTIVEC 222#ifdef CONFIG_ALTIVEC
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 58d0572de6f9..01006040f59e 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -34,6 +34,7 @@ obj-y += vdso32/
34obj-$(CONFIG_PPC64) += setup_64.o sys_ppc32.o \ 34obj-$(CONFIG_PPC64) += setup_64.o sys_ppc32.o \
35 signal_64.o ptrace32.o \ 35 signal_64.o ptrace32.o \
36 paca.o nvram_64.o firmware.o 36 paca.o nvram_64.o firmware.o
37obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
37obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_ppc970.o cpu_setup_pa6t.o 38obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_ppc970.o cpu_setup_pa6t.o
38obj64-$(CONFIG_RELOCATABLE) += reloc_64.o 39obj64-$(CONFIG_RELOCATABLE) += reloc_64.o
39obj-$(CONFIG_PPC_BOOK3E_64) += exceptions-64e.o 40obj-$(CONFIG_PPC_BOOK3E_64) += exceptions-64e.o
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index 3e423fbad6bc..f53029a01554 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -828,6 +828,7 @@ END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES)
828 828
829/* We have a data breakpoint exception - handle it */ 829/* We have a data breakpoint exception - handle it */
830handle_dabr_fault: 830handle_dabr_fault:
831 bl .save_nvgprs
831 ld r4,_DAR(r1) 832 ld r4,_DAR(r1)
832 ld r5,_DSISR(r1) 833 ld r5,_DSISR(r1)
833 addi r3,r1,STACK_FRAME_OVERHEAD 834 addi r3,r1,STACK_FRAME_OVERHEAD
diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c
new file mode 100644
index 000000000000..7a2ad5e84c16
--- /dev/null
+++ b/arch/powerpc/kernel/hw_breakpoint.c
@@ -0,0 +1,325 @@
1/*
2 * HW_breakpoint: a unified kernel/user-space hardware breakpoint facility,
3 * using the CPU's debug registers. Derived from
4 * "arch/x86/kernel/hw_breakpoint.c"
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 *
20 * Copyright 2010 IBM Corporation
21 * Author: K.Prasad <prasad@linux.vnet.ibm.com>
22 *
23 */
24
25#include <linux/hw_breakpoint.h>
26#include <linux/notifier.h>
27#include <linux/kprobes.h>
28#include <linux/percpu.h>
29#include <linux/kernel.h>
30#include <linux/module.h>
31#include <linux/sched.h>
32#include <linux/init.h>
33#include <linux/smp.h>
34
35#include <asm/hw_breakpoint.h>
36#include <asm/processor.h>
37#include <asm/sstep.h>
38#include <asm/uaccess.h>
39
40/*
41 * Stores the breakpoints currently in use on each breakpoint address
42 * register for every cpu
43 */
44static DEFINE_PER_CPU(struct perf_event *, bp_per_reg);
45
46/*
47 * Install a perf counter breakpoint.
48 *
49 * We seek a free debug address register and use it for this
50 * breakpoint.
51 *
52 * Atomic: we hold the counter->ctx->lock and we only handle variables
53 * and registers local to this cpu.
54 */
55int arch_install_hw_breakpoint(struct perf_event *bp)
56{
57 struct arch_hw_breakpoint *info = counter_arch_bp(bp);
58 struct perf_event **slot = &__get_cpu_var(bp_per_reg);
59
60 *slot = bp;
61
62 /*
63 * Do not install DABR values if the instruction must be single-stepped.
64 * If so, DABR will be populated in single_step_dabr_instruction().
65 */
66 if (current->thread.last_hit_ubp != bp)
67 set_dabr(info->address | info->type | DABR_TRANSLATION);
68
69 return 0;
70}
71
72/*
73 * Uninstall the breakpoint contained in the given counter.
74 *
75 * First we search the debug address register it uses and then we disable
76 * it.
77 *
78 * Atomic: we hold the counter->ctx->lock and we only handle variables
79 * and registers local to this cpu.
80 */
81void arch_uninstall_hw_breakpoint(struct perf_event *bp)
82{
83 struct perf_event **slot = &__get_cpu_var(bp_per_reg);
84
85 if (*slot != bp) {
86 WARN_ONCE(1, "Can't find the breakpoint");
87 return;
88 }
89
90 *slot = NULL;
91 set_dabr(0);
92}
93
94/*
95 * Perform cleanup of arch-specific counters during unregistration
96 * of the perf-event
97 */
98void arch_unregister_hw_breakpoint(struct perf_event *bp)
99{
100 /*
101 * If the breakpoint is unregistered between a hw_breakpoint_handler()
102 * and the single_step_dabr_instruction(), then cleanup the breakpoint
103 * restoration variables to prevent dangling pointers.
104 */
105 if (bp->ctx->task)
106 bp->ctx->task->thread.last_hit_ubp = NULL;
107}
108
109/*
110 * Check for virtual address in kernel space.
111 */
112int arch_check_bp_in_kernelspace(struct perf_event *bp)
113{
114 struct arch_hw_breakpoint *info = counter_arch_bp(bp);
115
116 return is_kernel_addr(info->address);
117}
118
119int arch_bp_generic_fields(int type, int *gen_bp_type)
120{
121 switch (type) {
122 case DABR_DATA_READ:
123 *gen_bp_type = HW_BREAKPOINT_R;
124 break;
125 case DABR_DATA_WRITE:
126 *gen_bp_type = HW_BREAKPOINT_W;
127 break;
128 case (DABR_DATA_WRITE | DABR_DATA_READ):
129 *gen_bp_type = (HW_BREAKPOINT_W | HW_BREAKPOINT_R);
130 break;
131 default:
132 return -EINVAL;
133 }
134 return 0;
135}
136
137/*
138 * Validate the arch-specific HW Breakpoint register settings
139 */
140int arch_validate_hwbkpt_settings(struct perf_event *bp)
141{
142 int ret = -EINVAL;
143 struct arch_hw_breakpoint *info = counter_arch_bp(bp);
144
145 if (!bp)
146 return ret;
147
148 switch (bp->attr.bp_type) {
149 case HW_BREAKPOINT_R:
150 info->type = DABR_DATA_READ;
151 break;
152 case HW_BREAKPOINT_W:
153 info->type = DABR_DATA_WRITE;
154 break;
155 case HW_BREAKPOINT_R | HW_BREAKPOINT_W:
156 info->type = (DABR_DATA_READ | DABR_DATA_WRITE);
157 break;
158 default:
159 return ret;
160 }
161
162 info->address = bp->attr.bp_addr;
163 info->len = bp->attr.bp_len;
164
165 /*
166 * Since breakpoint length can be a maximum of HW_BREAKPOINT_LEN(8)
167 * and breakpoint addresses are aligned to nearest double-word
168 * HW_BREAKPOINT_ALIGN by rounding off to the lower address, the
169 * 'symbolsize' should satisfy the check below.
170 */
171 if (info->len >
172 (HW_BREAKPOINT_LEN - (info->address & HW_BREAKPOINT_ALIGN)))
173 return -EINVAL;
174 return 0;
175}
176
177/*
178 * Handle debug exception notifications.
179 */
180int __kprobes hw_breakpoint_handler(struct die_args *args)
181{
182 bool is_ptrace_bp = false;
183 int rc = NOTIFY_STOP;
184 struct perf_event *bp;
185 struct pt_regs *regs = args->regs;
186 int stepped = 1;
187 struct arch_hw_breakpoint *info;
188 unsigned int instr;
189
190 /* Disable breakpoints during exception handling */
191 set_dabr(0);
192 /*
193 * The counter may be concurrently released but that can only
194 * occur from a call_rcu() path. We can then safely fetch
195 * the breakpoint, use its callback, touch its counter
196 * while we are in an rcu_read_lock() path.
197 */
198 rcu_read_lock();
199
200 bp = __get_cpu_var(bp_per_reg);
201 if (!bp)
202 goto out;
203 info = counter_arch_bp(bp);
204 is_ptrace_bp = (bp->overflow_handler == ptrace_triggered) ?
205 true : false;
206
207 /*
208 * Return early after invoking user-callback function without restoring
209 * DABR if the breakpoint is from ptrace which always operates in
210 * one-shot mode. The ptrace-ed process will receive the SIGTRAP signal
211 * generated in do_dabr().
212 */
213 if (is_ptrace_bp) {
214 perf_bp_event(bp, regs);
215 rc = NOTIFY_DONE;
216 goto out;
217 }
218
219 /* Do not emulate user-space instructions, instead single-step them */
220 if (user_mode(regs)) {
221 bp->ctx->task->thread.last_hit_ubp = bp;
222 regs->msr |= MSR_SE;
223 goto out;
224 }
225
226 stepped = 0;
227 instr = 0;
228 if (!__get_user_inatomic(instr, (unsigned int *) regs->nip))
229 stepped = emulate_step(regs, instr);
230
231 /*
232 * emulate_step() could not execute it. We've failed in reliably
233 * handling the hw-breakpoint. Unregister it and throw a warning
234 * message to let the user know about it.
235 */
236 if (!stepped) {
237 WARN(1, "Unable to handle hardware breakpoint. Breakpoint at "
238 "0x%lx will be disabled.", info->address);
239 perf_event_disable(bp);
240 goto out;
241 }
242 /*
243 * As a policy, the callback is invoked in a 'trigger-after-execute'
244 * fashion
245 */
246 perf_bp_event(bp, regs);
247
248 set_dabr(info->address | info->type | DABR_TRANSLATION);
249out:
250 rcu_read_unlock();
251 return rc;
252}
253
254/*
255 * Handle single-step exceptions following a DABR hit.
256 */
257int __kprobes single_step_dabr_instruction(struct die_args *args)
258{
259 struct pt_regs *regs = args->regs;
260 struct perf_event *bp = NULL;
261 struct arch_hw_breakpoint *bp_info;
262
263 bp = current->thread.last_hit_ubp;
264 /*
265 * Check if we are single-stepping as a result of a
266 * previous HW Breakpoint exception
267 */
268 if (!bp)
269 return NOTIFY_DONE;
270
271 bp_info = counter_arch_bp(bp);
272
273 /*
274 * We shall invoke the user-defined callback function in the single
275 * stepping handler to confirm to 'trigger-after-execute' semantics
276 */
277 perf_bp_event(bp, regs);
278
279 /*
280 * Do not disable MSR_SE if the process was already in
281 * single-stepping mode.
282 */
283 if (!test_thread_flag(TIF_SINGLESTEP))
284 regs->msr &= ~MSR_SE;
285
286 set_dabr(bp_info->address | bp_info->type | DABR_TRANSLATION);
287 current->thread.last_hit_ubp = NULL;
288 return NOTIFY_STOP;
289}
290
291/*
292 * Handle debug exception notifications.
293 */
294int __kprobes hw_breakpoint_exceptions_notify(
295 struct notifier_block *unused, unsigned long val, void *data)
296{
297 int ret = NOTIFY_DONE;
298
299 switch (val) {
300 case DIE_DABR_MATCH:
301 ret = hw_breakpoint_handler(data);
302 break;
303 case DIE_SSTEP:
304 ret = single_step_dabr_instruction(data);
305 break;
306 }
307
308 return ret;
309}
310
311/*
312 * Release the user breakpoints used by ptrace
313 */
314void flush_ptrace_hw_breakpoint(struct task_struct *tsk)
315{
316 struct thread_struct *t = &tsk->thread;
317
318 unregister_hw_breakpoint(t->ptrace_bps[0]);
319 t->ptrace_bps[0] = NULL;
320}
321
322void hw_breakpoint_pmu_read(struct perf_event *bp)
323{
324 /* TODO */
325}
diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c
index 26f9900f773c..6c7c546aa1be 100644
--- a/arch/powerpc/kernel/machine_kexec_64.c
+++ b/arch/powerpc/kernel/machine_kexec_64.c
@@ -25,6 +25,7 @@
25#include <asm/sections.h> /* _end */ 25#include <asm/sections.h> /* _end */
26#include <asm/prom.h> 26#include <asm/prom.h>
27#include <asm/smp.h> 27#include <asm/smp.h>
28#include <asm/hw_breakpoint.h>
28 29
29int default_machine_kexec_prepare(struct kimage *image) 30int default_machine_kexec_prepare(struct kimage *image)
30{ 31{
@@ -165,6 +166,7 @@ static void kexec_smp_down(void *arg)
165 while(kexec_all_irq_disabled == 0) 166 while(kexec_all_irq_disabled == 0)
166 cpu_relax(); 167 cpu_relax();
167 mb(); /* make sure all irqs are disabled before this */ 168 mb(); /* make sure all irqs are disabled before this */
169 hw_breakpoint_disable();
168 /* 170 /*
169 * Now every CPU has IRQs off, we can clear out any pending 171 * Now every CPU has IRQs off, we can clear out any pending
170 * IPIs and be sure that no more will come in after this. 172 * IPIs and be sure that no more will come in after this.
@@ -180,6 +182,7 @@ static void kexec_prepare_cpus_wait(int wait_state)
180{ 182{
181 int my_cpu, i, notified=-1; 183 int my_cpu, i, notified=-1;
182 184
185 hw_breakpoint_disable();
183 my_cpu = get_cpu(); 186 my_cpu = get_cpu();
184 /* Make sure each CPU has atleast made it to the state we need */ 187 /* Make sure each CPU has atleast made it to the state we need */
185 for (i=0; i < NR_CPUS; i++) { 188 for (i=0; i < NR_CPUS; i++) {
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 9d255b4f0a0e..cbf3521d50b6 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -37,6 +37,7 @@
37#include <linux/kernel_stat.h> 37#include <linux/kernel_stat.h>
38#include <linux/personality.h> 38#include <linux/personality.h>
39#include <linux/random.h> 39#include <linux/random.h>
40#include <linux/hw_breakpoint.h>
40 41
41#include <asm/pgtable.h> 42#include <asm/pgtable.h>
42#include <asm/uaccess.h> 43#include <asm/uaccess.h>
@@ -462,8 +463,14 @@ struct task_struct *__switch_to(struct task_struct *prev,
462#ifdef CONFIG_PPC_ADV_DEBUG_REGS 463#ifdef CONFIG_PPC_ADV_DEBUG_REGS
463 switch_booke_debug_regs(&new->thread); 464 switch_booke_debug_regs(&new->thread);
464#else 465#else
466/*
467 * For PPC_BOOK3S_64, we use the hw-breakpoint interfaces that would
468 * schedule DABR
469 */
470#ifndef CONFIG_HAVE_HW_BREAKPOINT
465 if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr)) 471 if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr))
466 set_dabr(new->thread.dabr); 472 set_dabr(new->thread.dabr);
473#endif /* CONFIG_HAVE_HW_BREAKPOINT */
467#endif 474#endif
468 475
469 476
@@ -642,7 +649,11 @@ void flush_thread(void)
642{ 649{
643 discard_lazy_cpu_state(); 650 discard_lazy_cpu_state();
644 651
652#ifdef CONFIG_HAVE_HW_BREAKPOINTS
653 flush_ptrace_hw_breakpoint(current);
654#else /* CONFIG_HAVE_HW_BREAKPOINTS */
645 set_debug_reg_defaults(&current->thread); 655 set_debug_reg_defaults(&current->thread);
656#endif /* CONFIG_HAVE_HW_BREAKPOINTS */
646} 657}
647 658
648void 659void
@@ -660,6 +671,9 @@ void prepare_to_copy(struct task_struct *tsk)
660 flush_altivec_to_thread(current); 671 flush_altivec_to_thread(current);
661 flush_vsx_to_thread(current); 672 flush_vsx_to_thread(current);
662 flush_spe_to_thread(current); 673 flush_spe_to_thread(current);
674#ifdef CONFIG_HAVE_HW_BREAKPOINT
675 flush_ptrace_hw_breakpoint(tsk);
676#endif /* CONFIG_HAVE_HW_BREAKPOINT */
663} 677}
664 678
665/* 679/*
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 7a0c0199ea28..11f3cd9c832f 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -32,6 +32,8 @@
32#ifdef CONFIG_PPC32 32#ifdef CONFIG_PPC32
33#include <linux/module.h> 33#include <linux/module.h>
34#endif 34#endif
35#include <linux/hw_breakpoint.h>
36#include <linux/perf_event.h>
35 37
36#include <asm/uaccess.h> 38#include <asm/uaccess.h>
37#include <asm/page.h> 39#include <asm/page.h>
@@ -866,9 +868,34 @@ void user_disable_single_step(struct task_struct *task)
866 clear_tsk_thread_flag(task, TIF_SINGLESTEP); 868 clear_tsk_thread_flag(task, TIF_SINGLESTEP);
867} 869}
868 870
871#ifdef CONFIG_HAVE_HW_BREAKPOINT
872void ptrace_triggered(struct perf_event *bp, int nmi,
873 struct perf_sample_data *data, struct pt_regs *regs)
874{
875 struct perf_event_attr attr;
876
877 /*
878 * Disable the breakpoint request here since ptrace has defined a
879 * one-shot behaviour for breakpoint exceptions in PPC64.
880 * The SIGTRAP signal is generated automatically for us in do_dabr().
881 * We don't have to do anything about that here
882 */
883 attr = bp->attr;
884 attr.disabled = true;
885 modify_user_hw_breakpoint(bp, &attr);
886}
887#endif /* CONFIG_HAVE_HW_BREAKPOINT */
888
869int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, 889int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
870 unsigned long data) 890 unsigned long data)
871{ 891{
892#ifdef CONFIG_HAVE_HW_BREAKPOINT
893 int ret;
894 struct thread_struct *thread = &(task->thread);
895 struct perf_event *bp;
896 struct perf_event_attr attr;
897#endif /* CONFIG_HAVE_HW_BREAKPOINT */
898
872 /* For ppc64 we support one DABR and no IABR's at the moment (ppc64). 899 /* For ppc64 we support one DABR and no IABR's at the moment (ppc64).
873 * For embedded processors we support one DAC and no IAC's at the 900 * For embedded processors we support one DAC and no IAC's at the
874 * moment. 901 * moment.
@@ -896,6 +923,43 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
896 /* Ensure breakpoint translation bit is set */ 923 /* Ensure breakpoint translation bit is set */
897 if (data && !(data & DABR_TRANSLATION)) 924 if (data && !(data & DABR_TRANSLATION))
898 return -EIO; 925 return -EIO;
926#ifdef CONFIG_HAVE_HW_BREAKPOINT
927 bp = thread->ptrace_bps[0];
928 if ((!data) || !(data & (DABR_DATA_WRITE | DABR_DATA_READ))) {
929 if (bp) {
930 unregister_hw_breakpoint(bp);
931 thread->ptrace_bps[0] = NULL;
932 }
933 return 0;
934 }
935 if (bp) {
936 attr = bp->attr;
937 attr.bp_addr = data & ~HW_BREAKPOINT_ALIGN;
938 arch_bp_generic_fields(data &
939 (DABR_DATA_WRITE | DABR_DATA_READ),
940 &attr.bp_type);
941 ret = modify_user_hw_breakpoint(bp, &attr);
942 if (ret)
943 return ret;
944 thread->ptrace_bps[0] = bp;
945 thread->dabr = data;
946 return 0;
947 }
948
949 /* Create a new breakpoint request if one doesn't exist already */
950 hw_breakpoint_init(&attr);
951 attr.bp_addr = data & ~HW_BREAKPOINT_ALIGN;
952 arch_bp_generic_fields(data & (DABR_DATA_WRITE | DABR_DATA_READ),
953 &attr.bp_type);
954
955 thread->ptrace_bps[0] = bp = register_user_hw_breakpoint(&attr,
956 ptrace_triggered, task);
957 if (IS_ERR(bp)) {
958 thread->ptrace_bps[0] = NULL;
959 return PTR_ERR(bp);
960 }
961
962#endif /* CONFIG_HAVE_HW_BREAKPOINT */
899 963
900 /* Move contents to the DABR register */ 964 /* Move contents to the DABR register */
901 task->thread.dabr = data; 965 task->thread.dabr = data;
diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
index 7581dbffa18e..a52ed2e47ac6 100644
--- a/arch/powerpc/lib/Makefile
+++ b/arch/powerpc/lib/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_PPC64) += copypage_64.o copyuser_64.o \
20 memcpy_64.o usercopy_64.o mem_64.o string.o 20 memcpy_64.o usercopy_64.o mem_64.o string.o
21obj-$(CONFIG_XMON) += sstep.o ldstfp.o 21obj-$(CONFIG_XMON) += sstep.o ldstfp.o
22obj-$(CONFIG_KPROBES) += sstep.o ldstfp.o 22obj-$(CONFIG_KPROBES) += sstep.o ldstfp.o
23obj-$(CONFIG_HAVE_HW_BREAKPOINT) += sstep.o ldstfp.o
23 24
24ifeq ($(CONFIG_PPC64),y) 25ifeq ($(CONFIG_PPC64),y)
25obj-$(CONFIG_SMP) += locks.o 26obj-$(CONFIG_SMP) += locks.o