Skip to content

Commit 0b4b382

Browse files
committed
x86, kgdb, init: Add early and late debug states
The kernel debugger can operate well before mm_init(), but the x86 hardware breakpoint code which uses the perf api requires that the kernel allocators are initialized. This means the kernel debug core needs to provide an optional arch specific call back to allow the initialization functions to run after the kernel has been further initialized. The kdb shell already had a similar restriction with an early initialization and late initialization. The kdb_init() was moved into the debug core's version of the late init which is called dbg_late_init(); CC: kgdb-bugreport@lists.sourceforge.net Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
1 parent 29c8439 commit 0b4b382

4 files changed

Lines changed: 42 additions & 9 deletions

File tree

arch/x86/kernel/kgdb.c

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -595,15 +595,16 @@ static struct notifier_block kgdb_notifier = {
595595
* specific callbacks.
596596
*/
597597
int kgdb_arch_init(void)
598+
{
599+
return register_die_notifier(&kgdb_notifier);
600+
}
601+
602+
void kgdb_arch_late(void)
598603
{
599604
int i, cpu;
600-
int ret;
601605
struct perf_event_attr attr;
602606
struct perf_event **pevent;
603607

604-
ret = register_die_notifier(&kgdb_notifier);
605-
if (ret != 0)
606-
return ret;
607608
/*
608609
* Pre-allocate the hw breakpoint structions in the non-atomic
609610
* portion of kgdb because this operation requires mutexs to
@@ -615,12 +616,15 @@ int kgdb_arch_init(void)
615616
attr.bp_type = HW_BREAKPOINT_W;
616617
attr.disabled = 1;
617618
for (i = 0; i < 4; i++) {
619+
if (breakinfo[i].pev)
620+
continue;
618621
breakinfo[i].pev = register_wide_hw_breakpoint(&attr, NULL);
619622
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");
621625
breakinfo[i].pev = NULL;
622626
kgdb_arch_exit();
623-
return -1;
627+
return;
624628
}
625629
for_each_online_cpu(cpu) {
626630
pevent = per_cpu_ptr(breakinfo[i].pev, cpu);
@@ -631,7 +635,6 @@ int kgdb_arch_init(void)
631635
}
632636
}
633637
}
634-
return ret;
635638
}
636639

637640
/**

include/linux/kgdb.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,17 @@ extern int kgdb_validate_break_address(unsigned long addr);
207207
extern int kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr);
208208
extern int kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle);
209209

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+
210221
/**
211222
* struct kgdb_arch - Describe architecture specific values.
212223
* @gdb_bpt_instr: The instruction to trigger a breakpoint.
@@ -285,7 +296,10 @@ extern int kgdb_single_step;
285296
extern atomic_t kgdb_active;
286297
#define in_dbg_master() \
287298
(raw_smp_processor_id() == atomic_read(&kgdb_active))
299+
extern bool dbg_is_early;
300+
extern void __init dbg_late_init(void);
288301
#else /* ! CONFIG_KGDB */
289302
#define in_dbg_master() (0)
303+
#define dbg_late_init()
290304
#endif /* ! CONFIG_KGDB */
291305
#endif /* _KGDB_H_ */

init/main.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
#include <linux/sched.h>
6363
#include <linux/signal.h>
6464
#include <linux/idr.h>
65-
#include <linux/kdb.h>
65+
#include <linux/kgdb.h>
6666
#include <linux/ftrace.h>
6767
#include <linux/async.h>
6868
#include <linux/kmemcheck.h>
@@ -676,7 +676,7 @@ asmlinkage void __init start_kernel(void)
676676
buffer_init();
677677
key_init();
678678
security_init();
679-
kdb_init(KDB_INIT_FULL);
679+
dbg_late_init();
680680
vfs_caches_init(totalram_pages);
681681
signals_init();
682682
/* rootfs populating might need page-writeback */

kernel/debug/debug_core.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ static DEFINE_SPINLOCK(kgdb_registration_lock);
7878
static int kgdb_con_registered;
7979
/* determine if kgdb console output should be used */
8080
static int kgdb_use_con;
81+
/* Flag for alternate operations for early debugging */
82+
bool dbg_is_early = true;
8183
/* Next cpu to become the master debug core */
8284
int dbg_switch_cpu;
8385

@@ -777,11 +779,25 @@ static struct notifier_block kgdb_panic_event_nb = {
777779
.priority = INT_MAX,
778780
};
779781

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+
780794
static void kgdb_register_callbacks(void)
781795
{
782796
if (!kgdb_io_module_registered) {
783797
kgdb_io_module_registered = 1;
784798
kgdb_arch_init();
799+
if (!dbg_is_early)
800+
kgdb_arch_late();
785801
atomic_notifier_chain_register(&panic_notifier_list,
786802
&kgdb_panic_event_nb);
787803
#ifdef CONFIG_MAGIC_SYSRQ

0 commit comments

Comments
 (0)