Blame view

arch/powerpc/kernel/hw_breakpoint.c 9.34 KB
5aae8a537   K.Prasad   powerpc, hw_break...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
  /*
   * HW_breakpoint: a unified kernel/user-space hardware breakpoint facility,
   * using the CPU's debug registers. Derived from
   * "arch/x86/kernel/hw_breakpoint.c"
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
   *
   * Copyright 2010 IBM Corporation
   * Author: K.Prasad <prasad@linux.vnet.ibm.com>
   *
   */
  
  #include <linux/hw_breakpoint.h>
  #include <linux/notifier.h>
  #include <linux/kprobes.h>
  #include <linux/percpu.h>
  #include <linux/kernel.h>
5aae8a537   K.Prasad   powerpc, hw_break...
30
  #include <linux/sched.h>
5aae8a537   K.Prasad   powerpc, hw_break...
31
32
33
34
35
36
37
38
39
40
41
42
43
44
  #include <linux/smp.h>
  
  #include <asm/hw_breakpoint.h>
  #include <asm/processor.h>
  #include <asm/sstep.h>
  #include <asm/uaccess.h>
  
  /*
   * Stores the breakpoints currently in use on each breakpoint address
   * register for every cpu
   */
  static DEFINE_PER_CPU(struct perf_event *, bp_per_reg);
  
  /*
d09ec7387   Paul Mackerras   powerpc, hw_break...
45
46
47
48
49
50
51
52
53
54
   * Returns total number of data or instruction breakpoints available.
   */
  int hw_breakpoint_slots(int type)
  {
  	if (type == TYPE_DATA)
  		return HBP_NUM;
  	return 0;		/* no instruction breakpoints available */
  }
  
  /*
5aae8a537   K.Prasad   powerpc, hw_break...
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
   * Install a perf counter breakpoint.
   *
   * We seek a free debug address register and use it for this
   * breakpoint.
   *
   * Atomic: we hold the counter->ctx->lock and we only handle variables
   * and registers local to this cpu.
   */
  int arch_install_hw_breakpoint(struct perf_event *bp)
  {
  	struct arch_hw_breakpoint *info = counter_arch_bp(bp);
  	struct perf_event **slot = &__get_cpu_var(bp_per_reg);
  
  	*slot = bp;
  
  	/*
  	 * Do not install DABR values if the instruction must be single-stepped.
  	 * If so, DABR will be populated in single_step_dabr_instruction().
  	 */
  	if (current->thread.last_hit_ubp != bp)
21f585073   Paul Gortmaker   powerpc: Fix smp_...
75
  		__set_breakpoint(info);
5aae8a537   K.Prasad   powerpc, hw_break...
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
  
  	return 0;
  }
  
  /*
   * Uninstall the breakpoint contained in the given counter.
   *
   * First we search the debug address register it uses and then we disable
   * it.
   *
   * Atomic: we hold the counter->ctx->lock and we only handle variables
   * and registers local to this cpu.
   */
  void arch_uninstall_hw_breakpoint(struct perf_event *bp)
  {
  	struct perf_event **slot = &__get_cpu_var(bp_per_reg);
  
  	if (*slot != bp) {
  		WARN_ONCE(1, "Can't find the breakpoint");
  		return;
  	}
  
  	*slot = NULL;
9422de3e9   Michael Neuling   powerpc: Hardware...
99
  	hw_breakpoint_disable();
5aae8a537   K.Prasad   powerpc, hw_break...
100
101
102
103
104
105
106
107
108
109
110
111
112
  }
  
  /*
   * Perform cleanup of arch-specific counters during unregistration
   * of the perf-event
   */
  void arch_unregister_hw_breakpoint(struct perf_event *bp)
  {
  	/*
  	 * If the breakpoint is unregistered between a hw_breakpoint_handler()
  	 * and the single_step_dabr_instruction(), then cleanup the breakpoint
  	 * restoration variables to prevent dangling pointers.
  	 */
ac84aa2b3   Naveen N. Rao   powerpc/hw_breakp...
113
  	if (bp->ctx && bp->ctx->task)
5aae8a537   K.Prasad   powerpc, hw_break...
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
  		bp->ctx->task->thread.last_hit_ubp = NULL;
  }
  
  /*
   * Check for virtual address in kernel space.
   */
  int arch_check_bp_in_kernelspace(struct perf_event *bp)
  {
  	struct arch_hw_breakpoint *info = counter_arch_bp(bp);
  
  	return is_kernel_addr(info->address);
  }
  
  int arch_bp_generic_fields(int type, int *gen_bp_type)
  {
9422de3e9   Michael Neuling   powerpc: Hardware...
129
130
131
132
133
134
  	*gen_bp_type = 0;
  	if (type & HW_BRK_TYPE_READ)
  		*gen_bp_type |= HW_BREAKPOINT_R;
  	if (type & HW_BRK_TYPE_WRITE)
  		*gen_bp_type |= HW_BREAKPOINT_W;
  	if (*gen_bp_type == 0)
5aae8a537   K.Prasad   powerpc, hw_break...
135
  		return -EINVAL;
5aae8a537   K.Prasad   powerpc, hw_break...
136
137
138
139
140
141
142
143
  	return 0;
  }
  
  /*
   * Validate the arch-specific HW Breakpoint register settings
   */
  int arch_validate_hwbkpt_settings(struct perf_event *bp)
  {
4ae7ebe95   Michael Neuling   powerpc: Change h...
144
  	int ret = -EINVAL, length_max;
5aae8a537   K.Prasad   powerpc, hw_break...
145
146
147
148
  	struct arch_hw_breakpoint *info = counter_arch_bp(bp);
  
  	if (!bp)
  		return ret;
9422de3e9   Michael Neuling   powerpc: Hardware...
149
150
151
152
153
154
155
  	info->type = HW_BRK_TYPE_TRANSLATE;
  	if (bp->attr.bp_type & HW_BREAKPOINT_R)
  		info->type |= HW_BRK_TYPE_READ;
  	if (bp->attr.bp_type & HW_BREAKPOINT_W)
  		info->type |= HW_BRK_TYPE_WRITE;
  	if (info->type == HW_BRK_TYPE_TRANSLATE)
  		/* must set alteast read or write */
5aae8a537   K.Prasad   powerpc, hw_break...
156
  		return ret;
9422de3e9   Michael Neuling   powerpc: Hardware...
157
158
159
160
161
162
  	if (!(bp->attr.exclude_user))
  		info->type |= HW_BRK_TYPE_USER;
  	if (!(bp->attr.exclude_kernel))
  		info->type |= HW_BRK_TYPE_KERNEL;
  	if (!(bp->attr.exclude_hv))
  		info->type |= HW_BRK_TYPE_HYP;
5aae8a537   K.Prasad   powerpc, hw_break...
163
164
165
166
167
168
169
170
171
  	info->address = bp->attr.bp_addr;
  	info->len = bp->attr.bp_len;
  
  	/*
  	 * Since breakpoint length can be a maximum of HW_BREAKPOINT_LEN(8)
  	 * and breakpoint addresses are aligned to nearest double-word
  	 * HW_BREAKPOINT_ALIGN by rounding off to the lower address, the
  	 * 'symbolsize' should satisfy the check below.
  	 */
4ae7ebe95   Michael Neuling   powerpc: Change h...
172
173
174
175
176
  	length_max = 8; /* DABR */
  	if (cpu_has_feature(CPU_FTR_DAWR)) {
  		length_max = 512 ; /* 64 doublewords */
  		/* DAWR region can't cross 512 boundary */
  		if ((bp->attr.bp_addr >> 10) != 
e2a800bea   Michael Neuling   powerpc/hw_brk: F...
177
  		    ((bp->attr.bp_addr + bp->attr.bp_len - 1) >> 10))
4ae7ebe95   Michael Neuling   powerpc: Change h...
178
179
  			return -EINVAL;
  	}
5aae8a537   K.Prasad   powerpc, hw_break...
180
  	if (info->len >
4ae7ebe95   Michael Neuling   powerpc: Change h...
181
  	    (length_max - (info->address & HW_BREAKPOINT_ALIGN)))
5aae8a537   K.Prasad   powerpc, hw_break...
182
183
184
185
186
  		return -EINVAL;
  	return 0;
  }
  
  /*
06532a674   K.Prasad   powerpc, hw_break...
187
188
189
190
191
192
193
194
195
196
197
198
199
   * Restores the breakpoint on the debug registers.
   * Invoke this function if it is known that the execution context is
   * about to change to cause loss of MSR_SE settings.
   */
  void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs)
  {
  	struct arch_hw_breakpoint *info;
  
  	if (likely(!tsk->thread.last_hit_ubp))
  		return;
  
  	info = counter_arch_bp(tsk->thread.last_hit_ubp);
  	regs->msr &= ~MSR_SE;
21f585073   Paul Gortmaker   powerpc: Fix smp_...
200
  	__set_breakpoint(info);
06532a674   K.Prasad   powerpc, hw_break...
201
202
203
204
  	tsk->thread.last_hit_ubp = NULL;
  }
  
  /*
5aae8a537   K.Prasad   powerpc, hw_break...
205
206
207
208
   * Handle debug exception notifications.
   */
  int __kprobes hw_breakpoint_handler(struct die_args *args)
  {
5aae8a537   K.Prasad   powerpc, hw_break...
209
210
211
212
213
214
  	int rc = NOTIFY_STOP;
  	struct perf_event *bp;
  	struct pt_regs *regs = args->regs;
  	int stepped = 1;
  	struct arch_hw_breakpoint *info;
  	unsigned int instr;
e3e94084a   K.Prasad   powerpc, hw_break...
215
  	unsigned long dar = regs->dar;
5aae8a537   K.Prasad   powerpc, hw_break...
216
217
  
  	/* Disable breakpoints during exception handling */
9422de3e9   Michael Neuling   powerpc: Hardware...
218
  	hw_breakpoint_disable();
574cb2489   Paul Mackerras   powerpc, hw_break...
219

5aae8a537   K.Prasad   powerpc, hw_break...
220
221
222
223
224
225
226
227
228
229
230
231
  	/*
  	 * The counter may be concurrently released but that can only
  	 * occur from a call_rcu() path. We can then safely fetch
  	 * the breakpoint, use its callback, touch its counter
  	 * while we are in an rcu_read_lock() path.
  	 */
  	rcu_read_lock();
  
  	bp = __get_cpu_var(bp_per_reg);
  	if (!bp)
  		goto out;
  	info = counter_arch_bp(bp);
5aae8a537   K.Prasad   powerpc, hw_break...
232
233
234
235
236
237
238
  
  	/*
  	 * Return early after invoking user-callback function without restoring
  	 * DABR if the breakpoint is from ptrace which always operates in
  	 * one-shot mode. The ptrace-ed process will receive the SIGTRAP signal
  	 * generated in do_dabr().
  	 */
574cb2489   Paul Mackerras   powerpc, hw_break...
239
  	if (bp->overflow_handler == ptrace_triggered) {
5aae8a537   K.Prasad   powerpc, hw_break...
240
241
242
243
  		perf_bp_event(bp, regs);
  		rc = NOTIFY_DONE;
  		goto out;
  	}
e3e94084a   K.Prasad   powerpc, hw_break...
244
245
  	/*
  	 * Verify if dar lies within the address range occupied by the symbol
574cb2489   Paul Mackerras   powerpc, hw_break...
246
247
248
  	 * being watched to filter extraneous exceptions.  If it doesn't,
  	 * we still need to single-step the instruction, but we don't
  	 * generate an event.
e3e94084a   K.Prasad   powerpc, hw_break...
249
  	 */
540e07c67   Michael Neuling   powerpc/hw_brk: F...
250
  	info->type &= ~HW_BRK_TYPE_EXTRANEOUS_IRQ;
9422de3e9   Michael Neuling   powerpc: Hardware...
251
252
253
  	if (!((bp->attr.bp_addr <= dar) &&
  	      (dar - bp->attr.bp_addr < bp->attr.bp_len)))
  		info->type |= HW_BRK_TYPE_EXTRANEOUS_IRQ;
e3e94084a   K.Prasad   powerpc, hw_break...
254

5aae8a537   K.Prasad   powerpc, hw_break...
255
256
  	/* Do not emulate user-space instructions, instead single-step them */
  	if (user_mode(regs)) {
6d9c00c67   Michael Neuling   powerpc: Fix null...
257
  		current->thread.last_hit_ubp = bp;
5aae8a537   K.Prasad   powerpc, hw_break...
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
  		regs->msr |= MSR_SE;
  		goto out;
  	}
  
  	stepped = 0;
  	instr = 0;
  	if (!__get_user_inatomic(instr, (unsigned int *) regs->nip))
  		stepped = emulate_step(regs, instr);
  
  	/*
  	 * emulate_step() could not execute it. We've failed in reliably
  	 * handling the hw-breakpoint. Unregister it and throw a warning
  	 * message to let the user know about it.
  	 */
  	if (!stepped) {
  		WARN(1, "Unable to handle hardware breakpoint. Breakpoint at "
  			"0x%lx will be disabled.", info->address);
  		perf_event_disable(bp);
  		goto out;
  	}
  	/*
  	 * As a policy, the callback is invoked in a 'trigger-after-execute'
  	 * fashion
  	 */
9422de3e9   Michael Neuling   powerpc: Hardware...
282
  	if (!(info->type & HW_BRK_TYPE_EXTRANEOUS_IRQ))
e3e94084a   K.Prasad   powerpc, hw_break...
283
  		perf_bp_event(bp, regs);
5aae8a537   K.Prasad   powerpc, hw_break...
284

21f585073   Paul Gortmaker   powerpc: Fix smp_...
285
  	__set_breakpoint(info);
5aae8a537   K.Prasad   powerpc, hw_break...
286
287
288
289
290
291
292
293
294
295
296
297
  out:
  	rcu_read_unlock();
  	return rc;
  }
  
  /*
   * Handle single-step exceptions following a DABR hit.
   */
  int __kprobes single_step_dabr_instruction(struct die_args *args)
  {
  	struct pt_regs *regs = args->regs;
  	struct perf_event *bp = NULL;
3f4693eee   Michael Neuling   powerpc: Use cons...
298
  	struct arch_hw_breakpoint *info;
5aae8a537   K.Prasad   powerpc, hw_break...
299
300
301
302
303
304
305
306
  
  	bp = current->thread.last_hit_ubp;
  	/*
  	 * Check if we are single-stepping as a result of a
  	 * previous HW Breakpoint exception
  	 */
  	if (!bp)
  		return NOTIFY_DONE;
3f4693eee   Michael Neuling   powerpc: Use cons...
307
  	info = counter_arch_bp(bp);
5aae8a537   K.Prasad   powerpc, hw_break...
308
309
310
311
312
  
  	/*
  	 * We shall invoke the user-defined callback function in the single
  	 * stepping handler to confirm to 'trigger-after-execute' semantics
  	 */
9422de3e9   Michael Neuling   powerpc: Hardware...
313
  	if (!(info->type & HW_BRK_TYPE_EXTRANEOUS_IRQ))
e3e94084a   K.Prasad   powerpc, hw_break...
314
  		perf_bp_event(bp, regs);
5aae8a537   K.Prasad   powerpc, hw_break...
315

21f585073   Paul Gortmaker   powerpc: Fix smp_...
316
  	__set_breakpoint(info);
76b0f1337   Paul Mackerras   powerpc, hw_break...
317
  	current->thread.last_hit_ubp = NULL;
5aae8a537   K.Prasad   powerpc, hw_break...
318
  	/*
76b0f1337   Paul Mackerras   powerpc, hw_break...
319
320
  	 * If the process was being single-stepped by ptrace, let the
  	 * other single-step actions occur (e.g. generate SIGTRAP).
5aae8a537   K.Prasad   powerpc, hw_break...
321
  	 */
76b0f1337   Paul Mackerras   powerpc, hw_break...
322
323
  	if (test_thread_flag(TIF_SINGLESTEP))
  		return NOTIFY_DONE;
5aae8a537   K.Prasad   powerpc, hw_break...
324

5aae8a537   K.Prasad   powerpc, hw_break...
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
  	return NOTIFY_STOP;
  }
  
  /*
   * Handle debug exception notifications.
   */
  int __kprobes hw_breakpoint_exceptions_notify(
  		struct notifier_block *unused, unsigned long val, void *data)
  {
  	int ret = NOTIFY_DONE;
  
  	switch (val) {
  	case DIE_DABR_MATCH:
  		ret = hw_breakpoint_handler(data);
  		break;
  	case DIE_SSTEP:
  		ret = single_step_dabr_instruction(data);
  		break;
  	}
  
  	return ret;
  }
  
  /*
   * Release the user breakpoints used by ptrace
   */
  void flush_ptrace_hw_breakpoint(struct task_struct *tsk)
  {
  	struct thread_struct *t = &tsk->thread;
  
  	unregister_hw_breakpoint(t->ptrace_bps[0]);
  	t->ptrace_bps[0] = NULL;
  }
  
  void hw_breakpoint_pmu_read(struct perf_event *bp)
  {
  	/* TODO */
  }