diff options
-rw-r--r-- | arch/x86/kernel/kgdb.c | 17 | ||||
-rw-r--r-- | include/linux/kgdb.h | 14 | ||||
-rw-r--r-- | init/main.c | 4 | ||||
-rw-r--r-- | kernel/debug/debug_core.c | 16 |
4 files changed, 42 insertions, 9 deletions
diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c index 95b89d4cb8f1..2b71ec41869f 100644 --- a/arch/x86/kernel/kgdb.c +++ b/arch/x86/kernel/kgdb.c | |||
@@ -596,14 +596,15 @@ static struct notifier_block kgdb_notifier = { | |||
596 | */ | 596 | */ |
597 | int kgdb_arch_init(void) | 597 | int kgdb_arch_init(void) |
598 | { | 598 | { |
599 | return register_die_notifier(&kgdb_notifier); | ||
600 | } | ||
601 | |||
602 | void kgdb_arch_late(void) | ||
603 | { | ||
599 | int i, cpu; | 604 | int i, cpu; |
600 | int ret; | ||
601 | struct perf_event_attr attr; | 605 | struct perf_event_attr attr; |
602 | struct perf_event **pevent; | 606 | struct perf_event **pevent; |
603 | 607 | ||
604 | ret = register_die_notifier(&kgdb_notifier); | ||
605 | if (ret != 0) | ||
606 | return ret; | ||
607 | /* | 608 | /* |
608 | * Pre-allocate the hw breakpoint structions in the non-atomic | 609 | * Pre-allocate the hw breakpoint structions in the non-atomic |
609 | * portion of kgdb because this operation requires mutexs to | 610 | * portion of kgdb because this operation requires mutexs to |
@@ -615,12 +616,15 @@ int kgdb_arch_init(void) | |||
615 | attr.bp_type = HW_BREAKPOINT_W; | 616 | attr.bp_type = HW_BREAKPOINT_W; |
616 | attr.disabled = 1; | 617 | attr.disabled = 1; |
617 | for (i = 0; i < 4; i++) { | 618 | for (i = 0; i < 4; i++) { |
619 | if (breakinfo[i].pev) | ||
620 | continue; | ||
618 | breakinfo[i].pev = register_wide_hw_breakpoint(&attr, NULL); | 621 | breakinfo[i].pev = register_wide_hw_breakpoint(&attr, NULL); |
619 | if (IS_ERR(breakinfo[i].pev)) { | 622 | if (IS_ERR(breakinfo[i].pev)) { |
620 | printk(KERN_ERR "kgdb: Could not allocate hw breakpoints\n"); | 623 | printk(KERN_ERR "kgdb: Could not allocate hw" |
624 | "breakpoints\nDisabling the kernel debugger\n"); | ||
621 | breakinfo[i].pev = NULL; | 625 | breakinfo[i].pev = NULL; |
622 | kgdb_arch_exit(); | 626 | kgdb_arch_exit(); |
623 | return -1; | 627 | return; |
624 | } | 628 | } |
625 | for_each_online_cpu(cpu) { | 629 | for_each_online_cpu(cpu) { |
626 | pevent = per_cpu_ptr(breakinfo[i].pev, cpu); | 630 | pevent = per_cpu_ptr(breakinfo[i].pev, cpu); |
@@ -631,7 +635,6 @@ int kgdb_arch_init(void) | |||
631 | } | 635 | } |
632 | } | 636 | } |
633 | } | 637 | } |
634 | return ret; | ||
635 | } | 638 | } |
636 | 639 | ||
637 | /** | 640 | /** |
diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h index 6c784ab6856a..9340f34d1bb5 100644 --- a/include/linux/kgdb.h +++ b/include/linux/kgdb.h | |||
@@ -208,6 +208,17 @@ extern int kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr); | |||
208 | extern int kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle); | 208 | extern int kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle); |
209 | 209 | ||
210 | /** | 210 | /** |
211 | * kgdb_arch_late - Perform any architecture specific initalization. | ||
212 | * | ||
213 | * This function will handle the late initalization of any | ||
214 | * architecture specific callbacks. This is an optional function for | ||
215 | * handling things like late initialization of hw breakpoints. The | ||
216 | * default implementation does nothing. | ||
217 | */ | ||
218 | extern void kgdb_arch_late(void); | ||
219 | |||
220 | |||
221 | /** | ||
211 | * struct kgdb_arch - Describe architecture specific values. | 222 | * struct kgdb_arch - Describe architecture specific values. |
212 | * @gdb_bpt_instr: The instruction to trigger a breakpoint. | 223 | * @gdb_bpt_instr: The instruction to trigger a breakpoint. |
213 | * @flags: Flags for the breakpoint, currently just %KGDB_HW_BREAKPOINT. | 224 | * @flags: Flags for the breakpoint, currently just %KGDB_HW_BREAKPOINT. |
@@ -285,7 +296,10 @@ extern int kgdb_single_step; | |||
285 | extern atomic_t kgdb_active; | 296 | extern atomic_t kgdb_active; |
286 | #define in_dbg_master() \ | 297 | #define in_dbg_master() \ |
287 | (raw_smp_processor_id() == atomic_read(&kgdb_active)) | 298 | (raw_smp_processor_id() == atomic_read(&kgdb_active)) |
299 | extern bool dbg_is_early; | ||
300 | extern void __init dbg_late_init(void); | ||
288 | #else /* ! CONFIG_KGDB */ | 301 | #else /* ! CONFIG_KGDB */ |
289 | #define in_dbg_master() (0) | 302 | #define in_dbg_master() (0) |
303 | #define dbg_late_init() | ||
290 | #endif /* ! CONFIG_KGDB */ | 304 | #endif /* ! CONFIG_KGDB */ |
291 | #endif /* _KGDB_H_ */ | 305 | #endif /* _KGDB_H_ */ |
diff --git a/init/main.c b/init/main.c index 372771333d98..22881b5e95e3 100644 --- a/init/main.c +++ b/init/main.c | |||
@@ -62,7 +62,7 @@ | |||
62 | #include <linux/sched.h> | 62 | #include <linux/sched.h> |
63 | #include <linux/signal.h> | 63 | #include <linux/signal.h> |
64 | #include <linux/idr.h> | 64 | #include <linux/idr.h> |
65 | #include <linux/kdb.h> | 65 | #include <linux/kgdb.h> |
66 | #include <linux/ftrace.h> | 66 | #include <linux/ftrace.h> |
67 | #include <linux/async.h> | 67 | #include <linux/async.h> |
68 | #include <linux/kmemcheck.h> | 68 | #include <linux/kmemcheck.h> |
@@ -676,7 +676,7 @@ asmlinkage void __init start_kernel(void) | |||
676 | buffer_init(); | 676 | buffer_init(); |
677 | key_init(); | 677 | key_init(); |
678 | security_init(); | 678 | security_init(); |
679 | kdb_init(KDB_INIT_FULL); | 679 | dbg_late_init(); |
680 | vfs_caches_init(totalram_pages); | 680 | vfs_caches_init(totalram_pages); |
681 | signals_init(); | 681 | signals_init(); |
682 | /* rootfs populating might need page-writeback */ | 682 | /* rootfs populating might need page-writeback */ |
diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c index 64b5588c9638..5cb7cd1de10c 100644 --- a/kernel/debug/debug_core.c +++ b/kernel/debug/debug_core.c | |||
@@ -78,6 +78,8 @@ static DEFINE_SPINLOCK(kgdb_registration_lock); | |||
78 | static int kgdb_con_registered; | 78 | static int kgdb_con_registered; |
79 | /* determine if kgdb console output should be used */ | 79 | /* determine if kgdb console output should be used */ |
80 | static int kgdb_use_con; | 80 | static int kgdb_use_con; |
81 | /* Flag for alternate operations for early debugging */ | ||
82 | bool dbg_is_early = true; | ||
81 | /* Next cpu to become the master debug core */ | 83 | /* Next cpu to become the master debug core */ |
82 | int dbg_switch_cpu; | 84 | int dbg_switch_cpu; |
83 | 85 | ||
@@ -777,11 +779,25 @@ static struct notifier_block kgdb_panic_event_nb = { | |||
777 | .priority = INT_MAX, | 779 | .priority = INT_MAX, |
778 | }; | 780 | }; |
779 | 781 | ||
782 | void __weak kgdb_arch_late(void) | ||
783 | { | ||
784 | } | ||
785 | |||
786 | void __init dbg_late_init(void) | ||
787 | { | ||
788 | dbg_is_early = false; | ||
789 | if (kgdb_io_module_registered) | ||
790 | kgdb_arch_late(); | ||
791 | kdb_init(KDB_INIT_FULL); | ||
792 | } | ||
793 | |||
780 | static void kgdb_register_callbacks(void) | 794 | static void kgdb_register_callbacks(void) |
781 | { | 795 | { |
782 | if (!kgdb_io_module_registered) { | 796 | if (!kgdb_io_module_registered) { |
783 | kgdb_io_module_registered = 1; | 797 | kgdb_io_module_registered = 1; |
784 | kgdb_arch_init(); | 798 | kgdb_arch_init(); |
799 | if (!dbg_is_early) | ||
800 | kgdb_arch_late(); | ||
785 | atomic_notifier_chain_register(&panic_notifier_list, | 801 | atomic_notifier_chain_register(&panic_notifier_list, |
786 | &kgdb_panic_event_nb); | 802 | &kgdb_panic_event_nb); |
787 | #ifdef CONFIG_MAGIC_SYSRQ | 803 | #ifdef CONFIG_MAGIC_SYSRQ |