aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorJason Wessel <jason.wessel@windriver.com>2010-01-28 18:04:42 -0500
committerIngo Molnar <mingo@elte.hu>2010-01-30 02:42:20 -0500
commitcc0967490c1c3824bc5b75718b6ca8a51d9f2617 (patch)
tree1224a5764dbcd779b842be6bd569d753da33de8c /arch/x86
parentb23ff0e9330e4b11e18af984d50573598e10e7f9 (diff)
x86, hw_breakpoints, kgdb: Fix kgdb to use hw_breakpoint API
In the 2.6.33 kernel, the hw_breakpoint API is now used for the performance event counters. The hw_breakpoint_handler() now consumes the hw breakpoints that were previously set by kgdb arch specific code. In order for kgdb to work in conjunction with this core API change, kgdb must use some of the low level functions of the hw_breakpoint API to install, uninstall, and deal with hw breakpoint reservations. The kgdb core required a change to call kgdb_disable_hw_debug anytime a slave cpu enters kgdb_wait() in order to keep all the hw breakpoints in sync as well as to prevent hitting a hw breakpoint while kgdb is active. During the architecture specific initialization of kgdb, it will pre-allocate 4 disabled (struct perf event **) structures. Kgdb will use these to manage the capabilities for the 4 hw breakpoint registers, per cpu. Right now the hw_breakpoint API does not have a way to ask how many breakpoints are available, on each CPU so it is possible that the install of a breakpoint might fail when kgdb restores the system to the run state. The intent of this patch is to first get the basic functionality of hw breakpoints working and leave it to the person debugging the kernel to understand what hw breakpoints are in use and what restrictions have been imposed as a result. Breakpoint constraints will be dealt with in a future patch. While atomic, the x86 specific kgdb code will call arch_uninstall_hw_breakpoint() and arch_install_hw_breakpoint() to manage the cpu specific hw breakpoints. The net result of these changes allow kgdb to use the same pool of hw_breakpoints that are used by the perf event API, but neither knows about future reservations for the available hw breakpoint slots. Signed-off-by: Jason Wessel <jason.wessel@windriver.com> Acked-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: kgdb-bugreport@lists.sourceforge.net Cc: K.Prasad <prasad@linux.vnet.ibm.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Alan Stern <stern@rowland.harvard.edu> Cc: torvalds@linux-foundation.org LKML-Reference: <1264719883-7285-2-git-send-email-jason.wessel@windriver.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/kernel/kgdb.c171
1 files changed, 114 insertions, 57 deletions
diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c
index dd74fe7273b1..62bea7307eaa 100644
--- a/arch/x86/kernel/kgdb.c
+++ b/arch/x86/kernel/kgdb.c
@@ -42,6 +42,7 @@
42#include <linux/init.h> 42#include <linux/init.h>
43#include <linux/smp.h> 43#include <linux/smp.h>
44#include <linux/nmi.h> 44#include <linux/nmi.h>
45#include <linux/hw_breakpoint.h>
45 46
46#include <asm/debugreg.h> 47#include <asm/debugreg.h>
47#include <asm/apicdef.h> 48#include <asm/apicdef.h>
@@ -204,40 +205,38 @@ void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
204 205
205static struct hw_breakpoint { 206static struct hw_breakpoint {
206 unsigned enabled; 207 unsigned enabled;
207 unsigned type;
208 unsigned len;
209 unsigned long addr; 208 unsigned long addr;
209 int len;
210 int type;
211 struct perf_event **pev;
210} breakinfo[4]; 212} breakinfo[4];
211 213
212static void kgdb_correct_hw_break(void) 214static void kgdb_correct_hw_break(void)
213{ 215{
214 unsigned long dr7;
215 int correctit = 0;
216 int breakbit;
217 int breakno; 216 int breakno;
218 217
219 get_debugreg(dr7, 7);
220 for (breakno = 0; breakno < 4; breakno++) { 218 for (breakno = 0; breakno < 4; breakno++) {
221 breakbit = 2 << (breakno << 1); 219 struct perf_event *bp;
222 if (!(dr7 & breakbit) && breakinfo[breakno].enabled) { 220 struct arch_hw_breakpoint *info;
223 correctit = 1; 221 int val;
224 dr7 |= breakbit; 222 int cpu = raw_smp_processor_id();
225 dr7 &= ~(0xf0000 << (breakno << 2)); 223 if (!breakinfo[breakno].enabled)
226 dr7 |= ((breakinfo[breakno].len << 2) | 224 continue;
227 breakinfo[breakno].type) << 225 bp = *per_cpu_ptr(breakinfo[breakno].pev, cpu);
228 ((breakno << 2) + 16); 226 info = counter_arch_bp(bp);
229 set_debugreg(breakinfo[breakno].addr, breakno); 227 if (bp->attr.disabled != 1)
230 228 continue;
231 } else { 229 bp->attr.bp_addr = breakinfo[breakno].addr;
232 if ((dr7 & breakbit) && !breakinfo[breakno].enabled) { 230 bp->attr.bp_len = breakinfo[breakno].len;
233 correctit = 1; 231 bp->attr.bp_type = breakinfo[breakno].type;
234 dr7 &= ~breakbit; 232 info->address = breakinfo[breakno].addr;
235 dr7 &= ~(0xf0000 << (breakno << 2)); 233 info->len = breakinfo[breakno].len;
236 } 234 info->type = breakinfo[breakno].type;
237 } 235 val = arch_install_hw_breakpoint(bp);
236 if (!val)
237 bp->attr.disabled = 0;
238 } 238 }
239 if (correctit) 239 hw_breakpoint_restore();
240 set_debugreg(dr7, 7);
241} 240}
242 241
243static int 242static int
@@ -259,15 +258,23 @@ kgdb_remove_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype)
259static void kgdb_remove_all_hw_break(void) 258static void kgdb_remove_all_hw_break(void)
260{ 259{
261 int i; 260 int i;
261 int cpu = raw_smp_processor_id();
262 struct perf_event *bp;
262 263
263 for (i = 0; i < 4; i++) 264 for (i = 0; i < 4; i++) {
264 memset(&breakinfo[i], 0, sizeof(struct hw_breakpoint)); 265 if (!breakinfo[i].enabled)
266 continue;
267 bp = *per_cpu_ptr(breakinfo[i].pev, cpu);
268 if (bp->attr.disabled == 1)
269 continue;
270 arch_uninstall_hw_breakpoint(bp);
271 bp->attr.disabled = 1;
272 }
265} 273}
266 274
267static int 275static int
268kgdb_set_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype) 276kgdb_set_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype)
269{ 277{
270 unsigned type;
271 int i; 278 int i;
272 279
273 for (i = 0; i < 4; i++) 280 for (i = 0; i < 4; i++)
@@ -278,27 +285,38 @@ kgdb_set_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype)
278 285
279 switch (bptype) { 286 switch (bptype) {
280 case BP_HARDWARE_BREAKPOINT: 287 case BP_HARDWARE_BREAKPOINT:
281 type = 0; 288 len = 1;
282 len = 1; 289 breakinfo[i].type = X86_BREAKPOINT_EXECUTE;
283 break; 290 break;
284 case BP_WRITE_WATCHPOINT: 291 case BP_WRITE_WATCHPOINT:
285 type = 1; 292 breakinfo[i].type = X86_BREAKPOINT_WRITE;
286 break; 293 break;
287 case BP_ACCESS_WATCHPOINT: 294 case BP_ACCESS_WATCHPOINT:
288 type = 3; 295 breakinfo[i].type = X86_BREAKPOINT_RW;
289 break; 296 break;
290 default: 297 default:
291 return -1; 298 return -1;
292 } 299 }
293 300 switch (len) {
294 if (len == 1 || len == 2 || len == 4) 301 case 1:
295 breakinfo[i].len = len - 1; 302 breakinfo[i].len = X86_BREAKPOINT_LEN_1;
296 else 303 break;
304 case 2:
305 breakinfo[i].len = X86_BREAKPOINT_LEN_2;
306 break;
307 case 4:
308 breakinfo[i].len = X86_BREAKPOINT_LEN_4;
309 break;
310#ifdef CONFIG_X86_64
311 case 8:
312 breakinfo[i].len = X86_BREAKPOINT_LEN_8;
313 break;
314#endif
315 default:
297 return -1; 316 return -1;
298 317 }
299 breakinfo[i].enabled = 1;
300 breakinfo[i].addr = addr; 318 breakinfo[i].addr = addr;
301 breakinfo[i].type = type; 319 breakinfo[i].enabled = 1;
302 320
303 return 0; 321 return 0;
304} 322}
@@ -313,8 +331,21 @@ kgdb_set_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype)
313 */ 331 */
314void kgdb_disable_hw_debug(struct pt_regs *regs) 332void kgdb_disable_hw_debug(struct pt_regs *regs)
315{ 333{
334 int i;
335 int cpu = raw_smp_processor_id();
336 struct perf_event *bp;
337
316 /* Disable hardware debugging while we are in kgdb: */ 338 /* Disable hardware debugging while we are in kgdb: */
317 set_debugreg(0UL, 7); 339 set_debugreg(0UL, 7);
340 for (i = 0; i < 4; i++) {
341 if (!breakinfo[i].enabled)
342 continue;
343 bp = *per_cpu_ptr(breakinfo[i].pev, cpu);
344 if (bp->attr.disabled == 1)
345 continue;
346 arch_uninstall_hw_breakpoint(bp);
347 bp->attr.disabled = 1;
348 }
318} 349}
319 350
320/** 351/**
@@ -378,7 +409,6 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
378 struct pt_regs *linux_regs) 409 struct pt_regs *linux_regs)
379{ 410{
380 unsigned long addr; 411 unsigned long addr;
381 unsigned long dr6;
382 char *ptr; 412 char *ptr;
383 int newPC; 413 int newPC;
384 414
@@ -404,20 +434,6 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
404 raw_smp_processor_id()); 434 raw_smp_processor_id());
405 } 435 }
406 436
407 get_debugreg(dr6, 6);
408 if (!(dr6 & 0x4000)) {
409 int breakno;
410
411 for (breakno = 0; breakno < 4; breakno++) {
412 if (dr6 & (1 << breakno) &&
413 breakinfo[breakno].type == 0) {
414 /* Set restore flag: */
415 linux_regs->flags |= X86_EFLAGS_RF;
416 break;
417 }
418 }
419 }
420 set_debugreg(0UL, 6);
421 kgdb_correct_hw_break(); 437 kgdb_correct_hw_break();
422 438
423 return 0; 439 return 0;
@@ -485,8 +501,7 @@ static int __kgdb_notify(struct die_args *args, unsigned long cmd)
485 break; 501 break;
486 502
487 case DIE_DEBUG: 503 case DIE_DEBUG:
488 if (atomic_read(&kgdb_cpu_doing_single_step) == 504 if (atomic_read(&kgdb_cpu_doing_single_step) != -1) {
489 raw_smp_processor_id()) {
490 if (user_mode(regs)) 505 if (user_mode(regs))
491 return single_step_cont(regs, args); 506 return single_step_cont(regs, args);
492 break; 507 break;
@@ -539,7 +554,42 @@ static struct notifier_block kgdb_notifier = {
539 */ 554 */
540int kgdb_arch_init(void) 555int kgdb_arch_init(void)
541{ 556{
542 return register_die_notifier(&kgdb_notifier); 557 int i, cpu;
558 int ret;
559 struct perf_event_attr attr;
560 struct perf_event **pevent;
561
562 ret = register_die_notifier(&kgdb_notifier);
563 if (ret != 0)
564 return ret;
565 /*
566 * Pre-allocate the hw breakpoint structions in the non-atomic
567 * portion of kgdb because this operation requires mutexs to
568 * complete.
569 */
570 attr.bp_addr = (unsigned long)kgdb_arch_init;
571 attr.type = PERF_TYPE_BREAKPOINT;
572 attr.bp_len = HW_BREAKPOINT_LEN_1;
573 attr.bp_type = HW_BREAKPOINT_W;
574 attr.disabled = 1;
575 for (i = 0; i < 4; i++) {
576 breakinfo[i].pev = register_wide_hw_breakpoint(&attr, NULL);
577 if (IS_ERR(breakinfo[i].pev)) {
578 printk(KERN_ERR "kgdb: Could not allocate hw breakpoints\n");
579 breakinfo[i].pev = NULL;
580 kgdb_arch_exit();
581 return -1;
582 }
583 for_each_online_cpu(cpu) {
584 pevent = per_cpu_ptr(breakinfo[i].pev, cpu);
585 pevent[0]->hw.sample_period = 1;
586 if (pevent[0]->destroy != NULL) {
587 pevent[0]->destroy = NULL;
588 release_bp_slot(*pevent);
589 }
590 }
591 }
592 return ret;
543} 593}
544 594
545/** 595/**
@@ -550,6 +600,13 @@ int kgdb_arch_init(void)
550 */ 600 */
551void kgdb_arch_exit(void) 601void kgdb_arch_exit(void)
552{ 602{
603 int i;
604 for (i = 0; i < 4; i++) {
605 if (breakinfo[i].pev) {
606 unregister_wide_hw_breakpoint(breakinfo[i].pev);
607 breakinfo[i].pev = NULL;
608 }
609 }
553 unregister_die_notifier(&kgdb_notifier); 610 unregister_die_notifier(&kgdb_notifier);
554} 611}
555 612