aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/kgdb.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/kgdb.c')
-rw-r--r--arch/x86/kernel/kgdb.c103
1 files changed, 64 insertions, 39 deletions
diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c
index b2258ca91003..4f4af75b9482 100644
--- a/arch/x86/kernel/kgdb.c
+++ b/arch/x86/kernel/kgdb.c
@@ -47,20 +47,8 @@
47#include <asm/debugreg.h> 47#include <asm/debugreg.h>
48#include <asm/apicdef.h> 48#include <asm/apicdef.h>
49#include <asm/system.h> 49#include <asm/system.h>
50
51#include <asm/apic.h> 50#include <asm/apic.h>
52 51
53/*
54 * Put the error code here just in case the user cares:
55 */
56static int gdb_x86errcode;
57
58/*
59 * Likewise, the vector number here (since GDB only gets the signal
60 * number through the usual means, and that's not very specific):
61 */
62static int gdb_x86vector = -1;
63
64/** 52/**
65 * pt_regs_to_gdb_regs - Convert ptrace regs to GDB regs 53 * pt_regs_to_gdb_regs - Convert ptrace regs to GDB regs
66 * @gdb_regs: A pointer to hold the registers in the order GDB wants. 54 * @gdb_regs: A pointer to hold the registers in the order GDB wants.
@@ -211,6 +199,8 @@ static struct hw_breakpoint {
211 struct perf_event **pev; 199 struct perf_event **pev;
212} breakinfo[4]; 200} breakinfo[4];
213 201
202static unsigned long early_dr7;
203
214static void kgdb_correct_hw_break(void) 204static void kgdb_correct_hw_break(void)
215{ 205{
216 int breakno; 206 int breakno;
@@ -222,6 +212,14 @@ static void kgdb_correct_hw_break(void)
222 int cpu = raw_smp_processor_id(); 212 int cpu = raw_smp_processor_id();
223 if (!breakinfo[breakno].enabled) 213 if (!breakinfo[breakno].enabled)
224 continue; 214 continue;
215 if (dbg_is_early) {
216 set_debugreg(breakinfo[breakno].addr, breakno);
217 early_dr7 |= encode_dr7(breakno,
218 breakinfo[breakno].len,
219 breakinfo[breakno].type);
220 set_debugreg(early_dr7, 7);
221 continue;
222 }
225 bp = *per_cpu_ptr(breakinfo[breakno].pev, cpu); 223 bp = *per_cpu_ptr(breakinfo[breakno].pev, cpu);
226 info = counter_arch_bp(bp); 224 info = counter_arch_bp(bp);
227 if (bp->attr.disabled != 1) 225 if (bp->attr.disabled != 1)
@@ -236,7 +234,8 @@ static void kgdb_correct_hw_break(void)
236 if (!val) 234 if (!val)
237 bp->attr.disabled = 0; 235 bp->attr.disabled = 0;
238 } 236 }
239 hw_breakpoint_restore(); 237 if (!dbg_is_early)
238 hw_breakpoint_restore();
240} 239}
241 240
242static int hw_break_reserve_slot(int breakno) 241static int hw_break_reserve_slot(int breakno)
@@ -245,6 +244,9 @@ static int hw_break_reserve_slot(int breakno)
245 int cnt = 0; 244 int cnt = 0;
246 struct perf_event **pevent; 245 struct perf_event **pevent;
247 246
247 if (dbg_is_early)
248 return 0;
249
248 for_each_online_cpu(cpu) { 250 for_each_online_cpu(cpu) {
249 cnt++; 251 cnt++;
250 pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu); 252 pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu);
@@ -270,6 +272,9 @@ static int hw_break_release_slot(int breakno)
270 struct perf_event **pevent; 272 struct perf_event **pevent;
271 int cpu; 273 int cpu;
272 274
275 if (dbg_is_early)
276 return 0;
277
273 for_each_online_cpu(cpu) { 278 for_each_online_cpu(cpu) {
274 pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu); 279 pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu);
275 if (dbg_release_bp_slot(*pevent)) 280 if (dbg_release_bp_slot(*pevent))
@@ -314,7 +319,11 @@ static void kgdb_remove_all_hw_break(void)
314 bp = *per_cpu_ptr(breakinfo[i].pev, cpu); 319 bp = *per_cpu_ptr(breakinfo[i].pev, cpu);
315 if (bp->attr.disabled == 1) 320 if (bp->attr.disabled == 1)
316 continue; 321 continue;
317 arch_uninstall_hw_breakpoint(bp); 322 if (dbg_is_early)
323 early_dr7 &= ~encode_dr7(i, breakinfo[i].len,
324 breakinfo[i].type);
325 else
326 arch_uninstall_hw_breakpoint(bp);
318 bp->attr.disabled = 1; 327 bp->attr.disabled = 1;
319 } 328 }
320} 329}
@@ -391,6 +400,11 @@ void kgdb_disable_hw_debug(struct pt_regs *regs)
391 for (i = 0; i < 4; i++) { 400 for (i = 0; i < 4; i++) {
392 if (!breakinfo[i].enabled) 401 if (!breakinfo[i].enabled)
393 continue; 402 continue;
403 if (dbg_is_early) {
404 early_dr7 &= ~encode_dr7(i, breakinfo[i].len,
405 breakinfo[i].type);
406 continue;
407 }
394 bp = *per_cpu_ptr(breakinfo[i].pev, cpu); 408 bp = *per_cpu_ptr(breakinfo[i].pev, cpu);
395 if (bp->attr.disabled == 1) 409 if (bp->attr.disabled == 1)
396 continue; 410 continue;
@@ -399,23 +413,6 @@ void kgdb_disable_hw_debug(struct pt_regs *regs)
399 } 413 }
400} 414}
401 415
402/**
403 * kgdb_post_primary_code - Save error vector/code numbers.
404 * @regs: Original pt_regs.
405 * @e_vector: Original error vector.
406 * @err_code: Original error code.
407 *
408 * This is needed on architectures which support SMP and KGDB.
409 * This function is called after all the slave cpus have been put
410 * to a know spin state and the primary CPU has control over KGDB.
411 */
412void kgdb_post_primary_code(struct pt_regs *regs, int e_vector, int err_code)
413{
414 /* primary processor is completely in the debugger */
415 gdb_x86vector = e_vector;
416 gdb_x86errcode = err_code;
417}
418
419#ifdef CONFIG_SMP 416#ifdef CONFIG_SMP
420/** 417/**
421 * kgdb_roundup_cpus - Get other CPUs into a holding pattern 418 * kgdb_roundup_cpus - Get other CPUs into a holding pattern
@@ -567,7 +564,7 @@ static int __kgdb_notify(struct die_args *args, unsigned long cmd)
567 return NOTIFY_DONE; 564 return NOTIFY_DONE;
568 } 565 }
569 566
570 if (kgdb_handle_exception(args->trapnr, args->signr, args->err, regs)) 567 if (kgdb_handle_exception(args->trapnr, args->signr, cmd, regs))
571 return NOTIFY_DONE; 568 return NOTIFY_DONE;
572 569
573 /* Must touch watchdog before return to normal operation */ 570 /* Must touch watchdog before return to normal operation */
@@ -575,6 +572,26 @@ static int __kgdb_notify(struct die_args *args, unsigned long cmd)
575 return NOTIFY_STOP; 572 return NOTIFY_STOP;
576} 573}
577 574
575#ifdef CONFIG_KGDB_LOW_LEVEL_TRAP
576int kgdb_ll_trap(int cmd, const char *str,
577 struct pt_regs *regs, long err, int trap, int sig)
578{
579 struct die_args args = {
580 .regs = regs,
581 .str = str,
582 .err = err,
583 .trapnr = trap,
584 .signr = sig,
585
586 };
587
588 if (!kgdb_io_module_registered)
589 return NOTIFY_DONE;
590
591 return __kgdb_notify(&args, cmd);
592}
593#endif /* CONFIG_KGDB_LOW_LEVEL_TRAP */
594
578static int 595static int
579kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr) 596kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr)
580{ 597{
@@ -605,14 +622,15 @@ static struct notifier_block kgdb_notifier = {
605 */ 622 */
606int kgdb_arch_init(void) 623int kgdb_arch_init(void)
607{ 624{
625 return register_die_notifier(&kgdb_notifier);
626}
627
628void kgdb_arch_late(void)
629{
608 int i, cpu; 630 int i, cpu;
609 int ret;
610 struct perf_event_attr attr; 631 struct perf_event_attr attr;
611 struct perf_event **pevent; 632 struct perf_event **pevent;
612 633
613 ret = register_die_notifier(&kgdb_notifier);
614 if (ret != 0)
615 return ret;
616 /* 634 /*
617 * Pre-allocate the hw breakpoint structions in the non-atomic 635 * Pre-allocate the hw breakpoint structions in the non-atomic
618 * portion of kgdb because this operation requires mutexs to 636 * portion of kgdb because this operation requires mutexs to
@@ -624,12 +642,15 @@ int kgdb_arch_init(void)
624 attr.bp_type = HW_BREAKPOINT_W; 642 attr.bp_type = HW_BREAKPOINT_W;
625 attr.disabled = 1; 643 attr.disabled = 1;
626 for (i = 0; i < 4; i++) { 644 for (i = 0; i < 4; i++) {
645 if (breakinfo[i].pev)
646 continue;
627 breakinfo[i].pev = register_wide_hw_breakpoint(&attr, NULL); 647 breakinfo[i].pev = register_wide_hw_breakpoint(&attr, NULL);
628 if (IS_ERR(breakinfo[i].pev)) { 648 if (IS_ERR(breakinfo[i].pev)) {
629 printk(KERN_ERR "kgdb: Could not allocate hw breakpoints\n"); 649 printk(KERN_ERR "kgdb: Could not allocate hw"
650 "breakpoints\nDisabling the kernel debugger\n");
630 breakinfo[i].pev = NULL; 651 breakinfo[i].pev = NULL;
631 kgdb_arch_exit(); 652 kgdb_arch_exit();
632 return -1; 653 return;
633 } 654 }
634 for_each_online_cpu(cpu) { 655 for_each_online_cpu(cpu) {
635 pevent = per_cpu_ptr(breakinfo[i].pev, cpu); 656 pevent = per_cpu_ptr(breakinfo[i].pev, cpu);
@@ -640,7 +661,6 @@ int kgdb_arch_init(void)
640 } 661 }
641 } 662 }
642 } 663 }
643 return ret;
644} 664}
645 665
646/** 666/**
@@ -690,6 +710,11 @@ unsigned long kgdb_arch_pc(int exception, struct pt_regs *regs)
690 return instruction_pointer(regs); 710 return instruction_pointer(regs);
691} 711}
692 712
713void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip)
714{
715 regs->ip = ip;
716}
717
693struct kgdb_arch arch_kgdb_ops = { 718struct kgdb_arch arch_kgdb_ops = {
694 /* Breakpoint instruction: */ 719 /* Breakpoint instruction: */
695 .gdb_bpt_instr = { 0xcc }, 720 .gdb_bpt_instr = { 0xcc },