]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blob - kernel/hw_breakpoint.c
hw-breakpoints: Rewrite the hw-breakpoints layer on top of perf events
[mirror_ubuntu-zesty-kernel.git] / kernel / hw_breakpoint.c
1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 *
16 * Copyright (C) 2007 Alan Stern
17 * Copyright (C) IBM Corporation, 2009
18 * Copyright (C) 2009, Frederic Weisbecker <fweisbec@gmail.com>
19 */
20
21 /*
22 * HW_breakpoint: a unified kernel/user-space hardware breakpoint facility,
23 * using the CPU's debug registers.
24 * This file contains the arch-independent routines.
25 */
26
27 #include <linux/irqflags.h>
28 #include <linux/kallsyms.h>
29 #include <linux/notifier.h>
30 #include <linux/kprobes.h>
31 #include <linux/kdebug.h>
32 #include <linux/kernel.h>
33 #include <linux/module.h>
34 #include <linux/percpu.h>
35 #include <linux/sched.h>
36 #include <linux/init.h>
37 #include <linux/smp.h>
38
39 #include <linux/hw_breakpoint.h>
40
41 #include <asm/processor.h>
42
43 #ifdef CONFIG_X86
44 #include <asm/debugreg.h>
45 #endif
46
47 static atomic_t bp_slot;
48
49 int reserve_bp_slot(struct perf_event *bp)
50 {
51 if (atomic_inc_return(&bp_slot) == HBP_NUM) {
52 atomic_dec(&bp_slot);
53
54 return -ENOSPC;
55 }
56
57 return 0;
58 }
59
60 void release_bp_slot(struct perf_event *bp)
61 {
62 atomic_dec(&bp_slot);
63 }
64
65 int __register_perf_hw_breakpoint(struct perf_event *bp)
66 {
67 int ret;
68
69 ret = reserve_bp_slot(bp);
70 if (ret)
71 return ret;
72
73 if (!bp->attr.disabled)
74 ret = arch_validate_hwbkpt_settings(bp, bp->ctx->task);
75
76 return ret;
77 }
78
79 int register_perf_hw_breakpoint(struct perf_event *bp)
80 {
81 bp->callback = perf_bp_event;
82
83 return __register_perf_hw_breakpoint(bp);
84 }
85
86 /*
87 * Register a breakpoint bound to a task and a given cpu.
88 * If cpu is -1, the breakpoint is active for the task in every cpu
89 * If the task is -1, the breakpoint is active for every tasks in the given
90 * cpu.
91 */
92 static struct perf_event *
93 register_user_hw_breakpoint_cpu(unsigned long addr,
94 int len,
95 int type,
96 perf_callback_t triggered,
97 pid_t pid,
98 int cpu,
99 bool active)
100 {
101 struct perf_event_attr *attr;
102 struct perf_event *bp;
103
104 attr = kzalloc(sizeof(*attr), GFP_KERNEL);
105 if (!attr)
106 return ERR_PTR(-ENOMEM);
107
108 attr->type = PERF_TYPE_BREAKPOINT;
109 attr->size = sizeof(*attr);
110 attr->bp_addr = addr;
111 attr->bp_len = len;
112 attr->bp_type = type;
113 /*
114 * Such breakpoints are used by debuggers to trigger signals when
115 * we hit the excepted memory op. We can't miss such events, they
116 * must be pinned.
117 */
118 attr->pinned = 1;
119
120 if (!active)
121 attr->disabled = 1;
122
123 bp = perf_event_create_kernel_counter(attr, cpu, pid, triggered);
124 kfree(attr);
125
126 return bp;
127 }
128
129 /**
130 * register_user_hw_breakpoint - register a hardware breakpoint for user space
131 * @addr: is the memory address that triggers the breakpoint
132 * @len: the length of the access to the memory (1 byte, 2 bytes etc...)
133 * @type: the type of the access to the memory (read/write/exec)
134 * @triggered: callback to trigger when we hit the breakpoint
135 * @tsk: pointer to 'task_struct' of the process to which the address belongs
136 * @active: should we activate it while registering it
137 *
138 */
139 struct perf_event *
140 register_user_hw_breakpoint(unsigned long addr,
141 int len,
142 int type,
143 perf_callback_t triggered,
144 struct task_struct *tsk,
145 bool active)
146 {
147 return register_user_hw_breakpoint_cpu(addr, len, type, triggered,
148 tsk->pid, -1, active);
149 }
150 EXPORT_SYMBOL_GPL(register_user_hw_breakpoint);
151
152 /**
153 * modify_user_hw_breakpoint - modify a user-space hardware breakpoint
154 * @bp: the breakpoint structure to modify
155 * @addr: is the memory address that triggers the breakpoint
156 * @len: the length of the access to the memory (1 byte, 2 bytes etc...)
157 * @type: the type of the access to the memory (read/write/exec)
158 * @triggered: callback to trigger when we hit the breakpoint
159 * @tsk: pointer to 'task_struct' of the process to which the address belongs
160 * @active: should we activate it while registering it
161 */
162 struct perf_event *
163 modify_user_hw_breakpoint(struct perf_event *bp,
164 unsigned long addr,
165 int len,
166 int type,
167 perf_callback_t triggered,
168 struct task_struct *tsk,
169 bool active)
170 {
171 /*
172 * FIXME: do it without unregistering
173 * - We don't want to lose our slot
174 * - If the new bp is incorrect, don't lose the older one
175 */
176 unregister_hw_breakpoint(bp);
177
178 return register_user_hw_breakpoint(addr, len, type, triggered,
179 tsk, active);
180 }
181 EXPORT_SYMBOL_GPL(modify_user_hw_breakpoint);
182
183 /**
184 * unregister_hw_breakpoint - unregister a user-space hardware breakpoint
185 * @bp: the breakpoint structure to unregister
186 */
187 void unregister_hw_breakpoint(struct perf_event *bp)
188 {
189 if (!bp)
190 return;
191 perf_event_release_kernel(bp);
192 }
193 EXPORT_SYMBOL_GPL(unregister_hw_breakpoint);
194
195 static struct perf_event *
196 register_kernel_hw_breakpoint_cpu(unsigned long addr,
197 int len,
198 int type,
199 perf_callback_t triggered,
200 int cpu,
201 bool active)
202 {
203 return register_user_hw_breakpoint_cpu(addr, len, type, triggered,
204 -1, cpu, active);
205 }
206
207 /**
208 * register_wide_hw_breakpoint - register a wide breakpoint in the kernel
209 * @addr: is the memory address that triggers the breakpoint
210 * @len: the length of the access to the memory (1 byte, 2 bytes etc...)
211 * @type: the type of the access to the memory (read/write/exec)
212 * @triggered: callback to trigger when we hit the breakpoint
213 * @active: should we activate it while registering it
214 *
215 * @return a set of per_cpu pointers to perf events
216 */
217 struct perf_event **
218 register_wide_hw_breakpoint(unsigned long addr,
219 int len,
220 int type,
221 perf_callback_t triggered,
222 bool active)
223 {
224 struct perf_event **cpu_events, **pevent, *bp;
225 long err;
226 int cpu;
227
228 cpu_events = alloc_percpu(typeof(*cpu_events));
229 if (!cpu_events)
230 return ERR_PTR(-ENOMEM);
231
232 for_each_possible_cpu(cpu) {
233 pevent = per_cpu_ptr(cpu_events, cpu);
234 bp = register_kernel_hw_breakpoint_cpu(addr, len, type,
235 triggered, cpu, active);
236
237 *pevent = bp;
238
239 if (IS_ERR(bp) || !bp) {
240 err = PTR_ERR(bp);
241 goto fail;
242 }
243 }
244
245 return cpu_events;
246
247 fail:
248 for_each_possible_cpu(cpu) {
249 pevent = per_cpu_ptr(cpu_events, cpu);
250 if (IS_ERR(*pevent) || !*pevent)
251 break;
252 unregister_hw_breakpoint(*pevent);
253 }
254 free_percpu(cpu_events);
255 /* return the error if any */
256 return ERR_PTR(err);
257 }
258
259 /**
260 * unregister_wide_hw_breakpoint - unregister a wide breakpoint in the kernel
261 * @cpu_events: the per cpu set of events to unregister
262 */
263 void unregister_wide_hw_breakpoint(struct perf_event **cpu_events)
264 {
265 int cpu;
266 struct perf_event **pevent;
267
268 for_each_possible_cpu(cpu) {
269 pevent = per_cpu_ptr(cpu_events, cpu);
270 unregister_hw_breakpoint(*pevent);
271 }
272 free_percpu(cpu_events);
273 }
274
275
276 static struct notifier_block hw_breakpoint_exceptions_nb = {
277 .notifier_call = hw_breakpoint_exceptions_notify,
278 /* we need to be notified first */
279 .priority = 0x7fffffff
280 };
281
282 static int __init init_hw_breakpoint(void)
283 {
284 return register_die_notifier(&hw_breakpoint_exceptions_nb);
285 }
286 core_initcall(init_hw_breakpoint);
287
288
289 struct pmu perf_ops_bp = {
290 .enable = arch_install_hw_breakpoint,
291 .disable = arch_uninstall_hw_breakpoint,
292 .read = hw_breakpoint_pmu_read,
293 .unthrottle = hw_breakpoint_pmu_unthrottle
294 };