blob: 08f6d01632011719566e65f25fe423288aa6853a [file] [log] [blame]
K.Prasad62a038d2009-06-01 23:43:33 +05301/*
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
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +020018 * Copyright (C) 2009, Frederic Weisbecker <fweisbec@gmail.com>
K.Prasad62a038d2009-06-01 23:43:33 +053019 */
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
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +020039#include <linux/hw_breakpoint.h>
40
K.Prasad62a038d2009-06-01 23:43:33 +053041#include <asm/processor.h>
42
43#ifdef CONFIG_X86
44#include <asm/debugreg.h>
45#endif
K.Prasad62a038d2009-06-01 23:43:33 +053046
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +020047static atomic_t bp_slot;
K.Prasad62a038d2009-06-01 23:43:33 +053048
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +020049int reserve_bp_slot(struct perf_event *bp)
K.Prasad62a038d2009-06-01 23:43:33 +053050{
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +020051 if (atomic_inc_return(&bp_slot) == HBP_NUM) {
52 atomic_dec(&bp_slot);
K.Prasad62a038d2009-06-01 23:43:33 +053053
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +020054 return -ENOSPC;
K.Prasad62a038d2009-06-01 23:43:33 +053055 }
56
K.Prasad62a038d2009-06-01 23:43:33 +053057 return 0;
58}
59
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +020060void release_bp_slot(struct perf_event *bp)
K.Prasad62a038d2009-06-01 23:43:33 +053061{
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +020062 atomic_dec(&bp_slot);
63}
K.Prasad62a038d2009-06-01 23:43:33 +053064
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +020065int __register_perf_hw_breakpoint(struct perf_event *bp)
66{
67 int ret;
K.Prasad62a038d2009-06-01 23:43:33 +053068
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +020069 ret = reserve_bp_slot(bp);
70 if (ret)
71 return ret;
K.Prasad62a038d2009-06-01 23:43:33 +053072
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +020073 if (!bp->attr.disabled)
74 ret = arch_validate_hwbkpt_settings(bp, bp->ctx->task);
K.Prasad62a038d2009-06-01 23:43:33 +053075
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +020076 return ret;
77}
K.Prasad62a038d2009-06-01 23:43:33 +053078
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +020079int register_perf_hw_breakpoint(struct perf_event *bp)
80{
81 bp->callback = perf_bp_event;
82
83 return __register_perf_hw_breakpoint(bp);
K.Prasad62a038d2009-06-01 23:43:33 +053084}
85
86/*
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +020087 * 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.
K.Prasad62a038d2009-06-01 23:43:33 +053091 */
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +020092static struct perf_event *
93register_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)
K.Prasad62a038d2009-06-01 23:43:33 +0530100{
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +0200101 struct perf_event_attr *attr;
102 struct perf_event *bp;
K.Prasad62a038d2009-06-01 23:43:33 +0530103
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +0200104 attr = kzalloc(sizeof(*attr), GFP_KERNEL);
105 if (!attr)
106 return ERR_PTR(-ENOMEM);
K.Prasad62a038d2009-06-01 23:43:33 +0530107
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +0200108 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;
K.Prasad62a038d2009-06-01 23:43:33 +0530113 /*
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +0200114 * 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.
K.Prasad62a038d2009-06-01 23:43:33 +0530117 */
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +0200118 attr->pinned = 1;
K.Prasad62a038d2009-06-01 23:43:33 +0530119
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +0200120 if (!active)
121 attr->disabled = 1;
K.Prasad62a038d2009-06-01 23:43:33 +0530122
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +0200123 bp = perf_event_create_kernel_counter(attr, cpu, pid, triggered);
124 kfree(attr);
K.Prasad62a038d2009-06-01 23:43:33 +0530125
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +0200126 return bp;
K.Prasad62a038d2009-06-01 23:43:33 +0530127}
128
129/**
130 * register_user_hw_breakpoint - register a hardware breakpoint for user space
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +0200131 * @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
K.Prasad62a038d2009-06-01 23:43:33 +0530135 * @tsk: pointer to 'task_struct' of the process to which the address belongs
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +0200136 * @active: should we activate it while registering it
K.Prasad62a038d2009-06-01 23:43:33 +0530137 *
138 */
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +0200139struct perf_event *
140register_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)
K.Prasad62a038d2009-06-01 23:43:33 +0530146{
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +0200147 return register_user_hw_breakpoint_cpu(addr, len, type, triggered,
148 tsk->pid, -1, active);
K.Prasad62a038d2009-06-01 23:43:33 +0530149}
150EXPORT_SYMBOL_GPL(register_user_hw_breakpoint);
151
152/**
153 * modify_user_hw_breakpoint - modify a user-space hardware breakpoint
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +0200154 * @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
K.Prasad62a038d2009-06-01 23:43:33 +0530159 * @tsk: pointer to 'task_struct' of the process to which the address belongs
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +0200160 * @active: should we activate it while registering it
K.Prasad62a038d2009-06-01 23:43:33 +0530161 */
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +0200162struct perf_event *
163modify_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)
K.Prasad62a038d2009-06-01 23:43:33 +0530170{
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +0200171 /*
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);
K.Prasad62a038d2009-06-01 23:43:33 +0530177
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +0200178 return register_user_hw_breakpoint(addr, len, type, triggered,
179 tsk, active);
K.Prasad62a038d2009-06-01 23:43:33 +0530180}
181EXPORT_SYMBOL_GPL(modify_user_hw_breakpoint);
182
183/**
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +0200184 * unregister_hw_breakpoint - unregister a user-space hardware breakpoint
K.Prasad62a038d2009-06-01 23:43:33 +0530185 * @bp: the breakpoint structure to unregister
K.Prasad62a038d2009-06-01 23:43:33 +0530186 */
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +0200187void unregister_hw_breakpoint(struct perf_event *bp)
K.Prasad62a038d2009-06-01 23:43:33 +0530188{
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +0200189 if (!bp)
K.Prasad62a038d2009-06-01 23:43:33 +0530190 return;
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +0200191 perf_event_release_kernel(bp);
192}
193EXPORT_SYMBOL_GPL(unregister_hw_breakpoint);
194
195static struct perf_event *
196register_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 */
217struct perf_event **
218register_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 }
K.Prasad62a038d2009-06-01 23:43:33 +0530243 }
244
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +0200245 return cpu_events;
K.Prasad62a038d2009-06-01 23:43:33 +0530246
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +0200247fail:
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);
K.Prasad62a038d2009-06-01 23:43:33 +0530257}
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +0200258
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 */
263void 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
K.Prasad62a038d2009-06-01 23:43:33 +0530275
276static 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
282static int __init init_hw_breakpoint(void)
283{
284 return register_die_notifier(&hw_breakpoint_exceptions_nb);
285}
K.Prasad62a038d2009-06-01 23:43:33 +0530286core_initcall(init_hw_breakpoint);
Frederic Weisbecker24f1e32c2009-09-09 19:22:48 +0200287
288
289struct 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};