Merge branch 'dbg-early-merge' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/linux-2.6-kgdb
* 'dbg-early-merge' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/linux-2.6-kgdb: echi-dbgp: Add kernel debugger support for the usb debug port earlyprintk,vga,kdb: Fix \b and \r for earlyprintk=vga with kdb kgdboc: Add ekgdboc for early use of the kernel debugger x86,early dr regs,kgdb: Allow kernel debugger early dr register access x86,kgdb: Implement early hardware breakpoint debugging x86, kgdb, init: Add early and late debug states x86, kgdb: early trap init for early debug
This commit is contained in:
Коммит
ac3ee84c60
|
@ -713,6 +713,12 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
The VGA output is eventually overwritten by the real
|
||||
console.
|
||||
|
||||
ekgdboc= [X86,KGDB] Allow early kernel console debugging
|
||||
ekgdboc=kbd
|
||||
|
||||
This is desgined to be used in conjunction with
|
||||
the boot argument: earlyprintk=vga
|
||||
|
||||
eata= [HW,SCSI]
|
||||
|
||||
edd= [EDD]
|
||||
|
@ -1121,6 +1127,17 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
use the HighMem zone if it exists, and the Normal
|
||||
zone if it does not.
|
||||
|
||||
kgdbdbgp= [KGDB,HW] kgdb over EHCI usb debug port.
|
||||
Format: <Controller#>[,poll interval]
|
||||
The controller # is the number of the ehci usb debug
|
||||
port as it is probed via PCI. The poll interval is
|
||||
optional and is the number seconds in between
|
||||
each poll cycle to the debug port in case you need
|
||||
the functionality for interrupting the kernel with
|
||||
gdb or control-c on the dbgp connection. When
|
||||
not using this parameter you use sysrq-g to break into
|
||||
the kernel debugger.
|
||||
|
||||
kgdboc= [KGDB,HW] kgdb over consoles.
|
||||
Requires a tty driver that supports console polling,
|
||||
or a supported polling keyboard driver (non-usb).
|
||||
|
|
|
@ -789,6 +789,8 @@ static inline void wbinvd_halt(void)
|
|||
extern void enable_sep_cpu(void);
|
||||
extern int sysenter_setup(void);
|
||||
|
||||
extern void early_trap_init(void);
|
||||
|
||||
/* Defined in head.S */
|
||||
extern struct desc_ptr early_gdt_descr;
|
||||
|
||||
|
|
|
@ -1084,6 +1084,20 @@ static void clear_all_debug_regs(void)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KGDB
|
||||
/*
|
||||
* Restore debug regs if using kgdbwait and you have a kernel debugger
|
||||
* connection established.
|
||||
*/
|
||||
static void dbg_restore_debug_regs(void)
|
||||
{
|
||||
if (unlikely(kgdb_connected && arch_kgdb_ops.correct_hw_break))
|
||||
arch_kgdb_ops.correct_hw_break();
|
||||
}
|
||||
#else /* ! CONFIG_KGDB */
|
||||
#define dbg_restore_debug_regs()
|
||||
#endif /* ! CONFIG_KGDB */
|
||||
|
||||
/*
|
||||
* cpu_init() initializes state that is per-CPU. Some data is already
|
||||
* initialized (naturally) in the bootstrap process, such as the GDT
|
||||
|
@ -1174,18 +1188,8 @@ void __cpuinit cpu_init(void)
|
|||
load_TR_desc();
|
||||
load_LDT(&init_mm.context);
|
||||
|
||||
#ifdef CONFIG_KGDB
|
||||
/*
|
||||
* If the kgdb is connected no debug regs should be altered. This
|
||||
* is only applicable when KGDB and a KGDB I/O module are built
|
||||
* into the kernel and you are using early debugging with
|
||||
* kgdbwait. KGDB will control the kernel HW breakpoint registers.
|
||||
*/
|
||||
if (kgdb_connected && arch_kgdb_ops.correct_hw_break)
|
||||
arch_kgdb_ops.correct_hw_break();
|
||||
else
|
||||
#endif
|
||||
clear_all_debug_regs();
|
||||
clear_all_debug_regs();
|
||||
dbg_restore_debug_regs();
|
||||
|
||||
fpu_init();
|
||||
|
||||
|
@ -1239,6 +1243,7 @@ void __cpuinit cpu_init(void)
|
|||
#endif
|
||||
|
||||
clear_all_debug_regs();
|
||||
dbg_restore_debug_regs();
|
||||
|
||||
/*
|
||||
* Force FPU initialization:
|
||||
|
|
|
@ -41,6 +41,14 @@ static void early_vga_write(struct console *con, const char *str, unsigned n)
|
|||
writew(0x720, VGABASE + 2*(max_xpos*j + i));
|
||||
current_ypos = max_ypos-1;
|
||||
}
|
||||
#ifdef CONFIG_KGDB_KDB
|
||||
if (c == '\b') {
|
||||
if (current_xpos > 0)
|
||||
current_xpos--;
|
||||
} else if (c == '\r') {
|
||||
current_xpos = 0;
|
||||
} else
|
||||
#endif
|
||||
if (c == '\n') {
|
||||
current_xpos = 0;
|
||||
current_ypos++;
|
||||
|
|
|
@ -199,6 +199,8 @@ static struct hw_breakpoint {
|
|||
struct perf_event **pev;
|
||||
} breakinfo[4];
|
||||
|
||||
static unsigned long early_dr7;
|
||||
|
||||
static void kgdb_correct_hw_break(void)
|
||||
{
|
||||
int breakno;
|
||||
|
@ -210,6 +212,14 @@ static void kgdb_correct_hw_break(void)
|
|||
int cpu = raw_smp_processor_id();
|
||||
if (!breakinfo[breakno].enabled)
|
||||
continue;
|
||||
if (dbg_is_early) {
|
||||
set_debugreg(breakinfo[breakno].addr, breakno);
|
||||
early_dr7 |= encode_dr7(breakno,
|
||||
breakinfo[breakno].len,
|
||||
breakinfo[breakno].type);
|
||||
set_debugreg(early_dr7, 7);
|
||||
continue;
|
||||
}
|
||||
bp = *per_cpu_ptr(breakinfo[breakno].pev, cpu);
|
||||
info = counter_arch_bp(bp);
|
||||
if (bp->attr.disabled != 1)
|
||||
|
@ -224,7 +234,8 @@ static void kgdb_correct_hw_break(void)
|
|||
if (!val)
|
||||
bp->attr.disabled = 0;
|
||||
}
|
||||
hw_breakpoint_restore();
|
||||
if (!dbg_is_early)
|
||||
hw_breakpoint_restore();
|
||||
}
|
||||
|
||||
static int hw_break_reserve_slot(int breakno)
|
||||
|
@ -233,6 +244,9 @@ static int hw_break_reserve_slot(int breakno)
|
|||
int cnt = 0;
|
||||
struct perf_event **pevent;
|
||||
|
||||
if (dbg_is_early)
|
||||
return 0;
|
||||
|
||||
for_each_online_cpu(cpu) {
|
||||
cnt++;
|
||||
pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu);
|
||||
|
@ -258,6 +272,9 @@ static int hw_break_release_slot(int breakno)
|
|||
struct perf_event **pevent;
|
||||
int cpu;
|
||||
|
||||
if (dbg_is_early)
|
||||
return 0;
|
||||
|
||||
for_each_online_cpu(cpu) {
|
||||
pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu);
|
||||
if (dbg_release_bp_slot(*pevent))
|
||||
|
@ -302,7 +319,11 @@ static void kgdb_remove_all_hw_break(void)
|
|||
bp = *per_cpu_ptr(breakinfo[i].pev, cpu);
|
||||
if (bp->attr.disabled == 1)
|
||||
continue;
|
||||
arch_uninstall_hw_breakpoint(bp);
|
||||
if (dbg_is_early)
|
||||
early_dr7 &= ~encode_dr7(i, breakinfo[i].len,
|
||||
breakinfo[i].type);
|
||||
else
|
||||
arch_uninstall_hw_breakpoint(bp);
|
||||
bp->attr.disabled = 1;
|
||||
}
|
||||
}
|
||||
|
@ -379,6 +400,11 @@ void kgdb_disable_hw_debug(struct pt_regs *regs)
|
|||
for (i = 0; i < 4; i++) {
|
||||
if (!breakinfo[i].enabled)
|
||||
continue;
|
||||
if (dbg_is_early) {
|
||||
early_dr7 &= ~encode_dr7(i, breakinfo[i].len,
|
||||
breakinfo[i].type);
|
||||
continue;
|
||||
}
|
||||
bp = *per_cpu_ptr(breakinfo[i].pev, cpu);
|
||||
if (bp->attr.disabled == 1)
|
||||
continue;
|
||||
|
@ -595,15 +621,16 @@ static struct notifier_block kgdb_notifier = {
|
|||
* specific callbacks.
|
||||
*/
|
||||
int kgdb_arch_init(void)
|
||||
{
|
||||
return register_die_notifier(&kgdb_notifier);
|
||||
}
|
||||
|
||||
void kgdb_arch_late(void)
|
||||
{
|
||||
int i, cpu;
|
||||
int ret;
|
||||
struct perf_event_attr attr;
|
||||
struct perf_event **pevent;
|
||||
|
||||
ret = register_die_notifier(&kgdb_notifier);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
/*
|
||||
* Pre-allocate the hw breakpoint structions in the non-atomic
|
||||
* portion of kgdb because this operation requires mutexs to
|
||||
|
@ -615,12 +642,15 @@ int kgdb_arch_init(void)
|
|||
attr.bp_type = HW_BREAKPOINT_W;
|
||||
attr.disabled = 1;
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (breakinfo[i].pev)
|
||||
continue;
|
||||
breakinfo[i].pev = register_wide_hw_breakpoint(&attr, NULL);
|
||||
if (IS_ERR(breakinfo[i].pev)) {
|
||||
printk(KERN_ERR "kgdb: Could not allocate hw breakpoints\n");
|
||||
printk(KERN_ERR "kgdb: Could not allocate hw"
|
||||
"breakpoints\nDisabling the kernel debugger\n");
|
||||
breakinfo[i].pev = NULL;
|
||||
kgdb_arch_exit();
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
for_each_online_cpu(cpu) {
|
||||
pevent = per_cpu_ptr(breakinfo[i].pev, cpu);
|
||||
|
@ -631,7 +661,6 @@ int kgdb_arch_init(void)
|
|||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -725,6 +725,7 @@ void __init setup_arch(char **cmdline_p)
|
|||
/* VMI may relocate the fixmap; do this before touching ioremap area */
|
||||
vmi_init();
|
||||
|
||||
early_trap_init();
|
||||
early_cpu_init();
|
||||
early_ioremap_init();
|
||||
|
||||
|
|
|
@ -808,6 +808,16 @@ dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Set of traps needed for early debugging. */
|
||||
void __init early_trap_init(void)
|
||||
{
|
||||
set_intr_gate_ist(1, &debug, DEBUG_STACK);
|
||||
/* int3 can be called from all */
|
||||
set_system_intr_gate_ist(3, &int3, DEBUG_STACK);
|
||||
set_intr_gate(14, &page_fault);
|
||||
load_idt(&idt_descr);
|
||||
}
|
||||
|
||||
void __init trap_init(void)
|
||||
{
|
||||
int i;
|
||||
|
@ -821,10 +831,7 @@ void __init trap_init(void)
|
|||
#endif
|
||||
|
||||
set_intr_gate(0, ÷_error);
|
||||
set_intr_gate_ist(1, &debug, DEBUG_STACK);
|
||||
set_intr_gate_ist(2, &nmi, NMI_STACK);
|
||||
/* int3 can be called from all */
|
||||
set_system_intr_gate_ist(3, &int3, DEBUG_STACK);
|
||||
/* int4 can be called from all */
|
||||
set_system_intr_gate(4, &overflow);
|
||||
set_intr_gate(5, &bounds);
|
||||
|
@ -840,7 +847,6 @@ void __init trap_init(void)
|
|||
set_intr_gate(11, &segment_not_present);
|
||||
set_intr_gate_ist(12, &stack_segment, STACKFAULT_STACK);
|
||||
set_intr_gate(13, &general_protection);
|
||||
set_intr_gate(14, &page_fault);
|
||||
set_intr_gate(15, &spurious_interrupt_bug);
|
||||
set_intr_gate(16, &coprocessor_error);
|
||||
set_intr_gate(17, &alignment_check);
|
||||
|
|
|
@ -223,6 +223,25 @@ static struct kgdb_io kgdboc_io_ops = {
|
|||
.post_exception = kgdboc_post_exp_handler,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_KGDB_SERIAL_CONSOLE
|
||||
/* This is only available if kgdboc is a built in for early debugging */
|
||||
int __init kgdboc_early_init(char *opt)
|
||||
{
|
||||
/* save the first character of the config string because the
|
||||
* init routine can destroy it.
|
||||
*/
|
||||
char save_ch;
|
||||
|
||||
kgdboc_option_setup(opt);
|
||||
save_ch = config[0];
|
||||
init_kgdboc();
|
||||
config[0] = save_ch;
|
||||
return 0;
|
||||
}
|
||||
|
||||
early_param("ekgdboc", kgdboc_early_init);
|
||||
#endif /* CONFIG_KGDB_SERIAL_CONSOLE */
|
||||
|
||||
module_init(init_kgdboc);
|
||||
module_exit(cleanup_kgdboc);
|
||||
module_param_call(kgdboc, param_set_kgdboc_var, param_get_string, &kps, 0644);
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/ehci_def.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/kgdb.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/pci-direct.h>
|
||||
#include <asm/fixmap.h>
|
||||
|
@ -55,6 +58,7 @@ static struct ehci_regs __iomem *ehci_regs;
|
|||
static struct ehci_dbg_port __iomem *ehci_debug;
|
||||
static int dbgp_not_safe; /* Cannot use debug device during ehci reset */
|
||||
static unsigned int dbgp_endpoint_out;
|
||||
static unsigned int dbgp_endpoint_in;
|
||||
|
||||
struct ehci_dev {
|
||||
u32 bus;
|
||||
|
@ -91,6 +95,13 @@ static inline u32 dbgp_len_update(u32 x, u32 len)
|
|||
return (x & ~0x0f) | (len & 0x0f);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KGDB
|
||||
static struct kgdb_io kgdbdbgp_io_ops;
|
||||
#define dbgp_kgdb_mode (dbg_io_ops == &kgdbdbgp_io_ops)
|
||||
#else
|
||||
#define dbgp_kgdb_mode (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* USB Packet IDs (PIDs)
|
||||
*/
|
||||
|
@ -182,11 +193,10 @@ static void dbgp_breath(void)
|
|||
/* Sleep to give the debug port a chance to breathe */
|
||||
}
|
||||
|
||||
static int dbgp_wait_until_done(unsigned ctrl)
|
||||
static int dbgp_wait_until_done(unsigned ctrl, int loop)
|
||||
{
|
||||
u32 pids, lpid;
|
||||
int ret;
|
||||
int loop = DBGP_LOOPS;
|
||||
|
||||
retry:
|
||||
writel(ctrl | DBGP_GO, &ehci_debug->control);
|
||||
|
@ -276,13 +286,13 @@ static int dbgp_bulk_write(unsigned devnum, unsigned endpoint,
|
|||
dbgp_set_data(bytes, size);
|
||||
writel(addr, &ehci_debug->address);
|
||||
writel(pids, &ehci_debug->pids);
|
||||
ret = dbgp_wait_until_done(ctrl);
|
||||
ret = dbgp_wait_until_done(ctrl, DBGP_LOOPS);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data,
|
||||
int size)
|
||||
int size, int loops)
|
||||
{
|
||||
u32 pids, addr, ctrl;
|
||||
int ret;
|
||||
|
@ -302,7 +312,7 @@ static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data,
|
|||
|
||||
writel(addr, &ehci_debug->address);
|
||||
writel(pids, &ehci_debug->pids);
|
||||
ret = dbgp_wait_until_done(ctrl);
|
||||
ret = dbgp_wait_until_done(ctrl, loops);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -343,12 +353,12 @@ static int dbgp_control_msg(unsigned devnum, int requesttype,
|
|||
dbgp_set_data(&req, sizeof(req));
|
||||
writel(addr, &ehci_debug->address);
|
||||
writel(pids, &ehci_debug->pids);
|
||||
ret = dbgp_wait_until_done(ctrl);
|
||||
ret = dbgp_wait_until_done(ctrl, DBGP_LOOPS);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Read the result */
|
||||
return dbgp_bulk_read(devnum, 0, data, size);
|
||||
return dbgp_bulk_read(devnum, 0, data, size, DBGP_LOOPS);
|
||||
}
|
||||
|
||||
/* Find a PCI capability */
|
||||
|
@ -559,6 +569,7 @@ try_again:
|
|||
goto err;
|
||||
}
|
||||
dbgp_endpoint_out = dbgp_desc.bDebugOutEndpoint;
|
||||
dbgp_endpoint_in = dbgp_desc.bDebugInEndpoint;
|
||||
|
||||
/* Move the device to 127 if it isn't already there */
|
||||
if (devnum != USB_DEBUG_DEVNUM) {
|
||||
|
@ -968,8 +979,9 @@ int dbgp_reset_prep(void)
|
|||
if (!ehci_debug)
|
||||
return 0;
|
||||
|
||||
if (early_dbgp_console.index != -1 &&
|
||||
!(early_dbgp_console.flags & CON_BOOT))
|
||||
if ((early_dbgp_console.index != -1 &&
|
||||
!(early_dbgp_console.flags & CON_BOOT)) ||
|
||||
dbgp_kgdb_mode)
|
||||
return 1;
|
||||
/* This means the console is not initialized, or should get
|
||||
* shutdown so as to allow for reuse of the usb device, which
|
||||
|
@ -982,3 +994,93 @@ int dbgp_reset_prep(void)
|
|||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dbgp_reset_prep);
|
||||
|
||||
#ifdef CONFIG_KGDB
|
||||
|
||||
static char kgdbdbgp_buf[DBGP_MAX_PACKET];
|
||||
static int kgdbdbgp_buf_sz;
|
||||
static int kgdbdbgp_buf_idx;
|
||||
static int kgdbdbgp_loop_cnt = DBGP_LOOPS;
|
||||
|
||||
static int kgdbdbgp_read_char(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (kgdbdbgp_buf_idx < kgdbdbgp_buf_sz) {
|
||||
char ch = kgdbdbgp_buf[kgdbdbgp_buf_idx++];
|
||||
return ch;
|
||||
}
|
||||
|
||||
ret = dbgp_bulk_read(USB_DEBUG_DEVNUM, dbgp_endpoint_in,
|
||||
&kgdbdbgp_buf, DBGP_MAX_PACKET,
|
||||
kgdbdbgp_loop_cnt);
|
||||
if (ret <= 0)
|
||||
return NO_POLL_CHAR;
|
||||
kgdbdbgp_buf_sz = ret;
|
||||
kgdbdbgp_buf_idx = 1;
|
||||
return kgdbdbgp_buf[0];
|
||||
}
|
||||
|
||||
static void kgdbdbgp_write_char(u8 chr)
|
||||
{
|
||||
early_dbgp_write(NULL, &chr, 1);
|
||||
}
|
||||
|
||||
static struct kgdb_io kgdbdbgp_io_ops = {
|
||||
.name = "kgdbdbgp",
|
||||
.read_char = kgdbdbgp_read_char,
|
||||
.write_char = kgdbdbgp_write_char,
|
||||
};
|
||||
|
||||
static int kgdbdbgp_wait_time;
|
||||
|
||||
static int __init kgdbdbgp_parse_config(char *str)
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
if (!ehci_debug) {
|
||||
if (early_dbgp_init(str))
|
||||
return -1;
|
||||
}
|
||||
ptr = strchr(str, ',');
|
||||
if (ptr) {
|
||||
ptr++;
|
||||
kgdbdbgp_wait_time = simple_strtoul(ptr, &ptr, 10);
|
||||
}
|
||||
kgdb_register_io_module(&kgdbdbgp_io_ops);
|
||||
kgdbdbgp_io_ops.is_console = early_dbgp_console.index != -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
early_param("kgdbdbgp", kgdbdbgp_parse_config);
|
||||
|
||||
static int kgdbdbgp_reader_thread(void *ptr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
while (readl(&ehci_debug->control) & DBGP_ENABLED) {
|
||||
kgdbdbgp_loop_cnt = 1;
|
||||
ret = kgdbdbgp_read_char();
|
||||
kgdbdbgp_loop_cnt = DBGP_LOOPS;
|
||||
if (ret != NO_POLL_CHAR) {
|
||||
if (ret == 0x3 || ret == '$') {
|
||||
if (ret == '$')
|
||||
kgdbdbgp_buf_idx--;
|
||||
kgdb_breakpoint();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
schedule_timeout_interruptible(kgdbdbgp_wait_time * HZ);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init kgdbdbgp_start_thread(void)
|
||||
{
|
||||
if (dbgp_kgdb_mode && kgdbdbgp_wait_time)
|
||||
kthread_run(kgdbdbgp_reader_thread, NULL, "%s", "dbgp");
|
||||
|
||||
return 0;
|
||||
}
|
||||
module_init(kgdbdbgp_start_thread);
|
||||
#endif /* CONFIG_KGDB */
|
||||
|
|
|
@ -207,6 +207,17 @@ extern int kgdb_validate_break_address(unsigned long addr);
|
|||
extern int kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr);
|
||||
extern int kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle);
|
||||
|
||||
/**
|
||||
* kgdb_arch_late - Perform any architecture specific initalization.
|
||||
*
|
||||
* This function will handle the late initalization of any
|
||||
* architecture specific callbacks. This is an optional function for
|
||||
* handling things like late initialization of hw breakpoints. The
|
||||
* default implementation does nothing.
|
||||
*/
|
||||
extern void kgdb_arch_late(void);
|
||||
|
||||
|
||||
/**
|
||||
* struct kgdb_arch - Describe architecture specific values.
|
||||
* @gdb_bpt_instr: The instruction to trigger a breakpoint.
|
||||
|
@ -285,7 +296,10 @@ extern int kgdb_single_step;
|
|||
extern atomic_t kgdb_active;
|
||||
#define in_dbg_master() \
|
||||
(raw_smp_processor_id() == atomic_read(&kgdb_active))
|
||||
extern bool dbg_is_early;
|
||||
extern void __init dbg_late_init(void);
|
||||
#else /* ! CONFIG_KGDB */
|
||||
#define in_dbg_master() (0)
|
||||
#define dbg_late_init()
|
||||
#endif /* ! CONFIG_KGDB */
|
||||
#endif /* _KGDB_H_ */
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
#include <linux/sched.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/kdb.h>
|
||||
#include <linux/kgdb.h>
|
||||
#include <linux/ftrace.h>
|
||||
#include <linux/async.h>
|
||||
#include <linux/kmemcheck.h>
|
||||
|
@ -676,7 +676,7 @@ asmlinkage void __init start_kernel(void)
|
|||
buffer_init();
|
||||
key_init();
|
||||
security_init();
|
||||
kdb_init(KDB_INIT_FULL);
|
||||
dbg_late_init();
|
||||
vfs_caches_init(totalram_pages);
|
||||
signals_init();
|
||||
/* rootfs populating might need page-writeback */
|
||||
|
|
|
@ -78,6 +78,8 @@ static DEFINE_SPINLOCK(kgdb_registration_lock);
|
|||
static int kgdb_con_registered;
|
||||
/* determine if kgdb console output should be used */
|
||||
static int kgdb_use_con;
|
||||
/* Flag for alternate operations for early debugging */
|
||||
bool dbg_is_early = true;
|
||||
/* Next cpu to become the master debug core */
|
||||
int dbg_switch_cpu;
|
||||
|
||||
|
@ -777,11 +779,25 @@ static struct notifier_block kgdb_panic_event_nb = {
|
|||
.priority = INT_MAX,
|
||||
};
|
||||
|
||||
void __weak kgdb_arch_late(void)
|
||||
{
|
||||
}
|
||||
|
||||
void __init dbg_late_init(void)
|
||||
{
|
||||
dbg_is_early = false;
|
||||
if (kgdb_io_module_registered)
|
||||
kgdb_arch_late();
|
||||
kdb_init(KDB_INIT_FULL);
|
||||
}
|
||||
|
||||
static void kgdb_register_callbacks(void)
|
||||
{
|
||||
if (!kgdb_io_module_registered) {
|
||||
kgdb_io_module_registered = 1;
|
||||
kgdb_arch_init();
|
||||
if (!dbg_is_early)
|
||||
kgdb_arch_late();
|
||||
atomic_notifier_chain_register(&panic_notifier_list,
|
||||
&kgdb_panic_event_nb);
|
||||
#ifdef CONFIG_MAGIC_SYSRQ
|
||||
|
|
Загрузка…
Ссылка в новой задаче