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 |
