Commit ac3ee84c authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'dbg-early-merge' of...

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
parents 90b9a32d 4fe1da4e
...@@ -713,6 +713,12 @@ and is between 256 and 4096 characters. It is defined in the file ...@@ -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 The VGA output is eventually overwritten by the real
console. 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] eata= [HW,SCSI]
edd= [EDD] edd= [EDD]
...@@ -1121,6 +1127,17 @@ and is between 256 and 4096 characters. It is defined in the file ...@@ -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 use the HighMem zone if it exists, and the Normal
zone if it does not. 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. kgdboc= [KGDB,HW] kgdb over consoles.
Requires a tty driver that supports console polling, Requires a tty driver that supports console polling,
or a supported polling keyboard driver (non-usb). or a supported polling keyboard driver (non-usb).
......
...@@ -789,6 +789,8 @@ static inline void wbinvd_halt(void) ...@@ -789,6 +789,8 @@ static inline void wbinvd_halt(void)
extern void enable_sep_cpu(void); extern void enable_sep_cpu(void);
extern int sysenter_setup(void); extern int sysenter_setup(void);
extern void early_trap_init(void);
/* Defined in head.S */ /* Defined in head.S */
extern struct desc_ptr early_gdt_descr; extern struct desc_ptr early_gdt_descr;
......
...@@ -1084,6 +1084,20 @@ static void clear_all_debug_regs(void) ...@@ -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 * cpu_init() initializes state that is per-CPU. Some data is already
* initialized (naturally) in the bootstrap process, such as the GDT * initialized (naturally) in the bootstrap process, such as the GDT
...@@ -1174,18 +1188,8 @@ void __cpuinit cpu_init(void) ...@@ -1174,18 +1188,8 @@ void __cpuinit cpu_init(void)
load_TR_desc(); load_TR_desc();
load_LDT(&init_mm.context); load_LDT(&init_mm.context);
#ifdef CONFIG_KGDB clear_all_debug_regs();
/* dbg_restore_debug_regs();
* 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();
fpu_init(); fpu_init();
...@@ -1239,6 +1243,7 @@ void __cpuinit cpu_init(void) ...@@ -1239,6 +1243,7 @@ void __cpuinit cpu_init(void)
#endif #endif
clear_all_debug_regs(); clear_all_debug_regs();
dbg_restore_debug_regs();
/* /*
* Force FPU initialization: * Force FPU initialization:
......
...@@ -41,6 +41,14 @@ static void early_vga_write(struct console *con, const char *str, unsigned n) ...@@ -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)); writew(0x720, VGABASE + 2*(max_xpos*j + i));
current_ypos = max_ypos-1; 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') { if (c == '\n') {
current_xpos = 0; current_xpos = 0;
current_ypos++; current_ypos++;
......
...@@ -199,6 +199,8 @@ static struct hw_breakpoint { ...@@ -199,6 +199,8 @@ static struct hw_breakpoint {
struct perf_event **pev; struct perf_event **pev;
} breakinfo[4]; } breakinfo[4];
static unsigned long early_dr7;
static void kgdb_correct_hw_break(void) static void kgdb_correct_hw_break(void)
{ {
int breakno; int breakno;
...@@ -210,6 +212,14 @@ static void kgdb_correct_hw_break(void) ...@@ -210,6 +212,14 @@ static void kgdb_correct_hw_break(void)
int cpu = raw_smp_processor_id(); int cpu = raw_smp_processor_id();
if (!breakinfo[breakno].enabled) if (!breakinfo[breakno].enabled)
continue; 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); bp = *per_cpu_ptr(breakinfo[breakno].pev, cpu);
info = counter_arch_bp(bp); info = counter_arch_bp(bp);
if (bp->attr.disabled != 1) if (bp->attr.disabled != 1)
...@@ -224,7 +234,8 @@ static void kgdb_correct_hw_break(void) ...@@ -224,7 +234,8 @@ static void kgdb_correct_hw_break(void)
if (!val) if (!val)
bp->attr.disabled = 0; bp->attr.disabled = 0;
} }
hw_breakpoint_restore(); if (!dbg_is_early)
hw_breakpoint_restore();
} }
static int hw_break_reserve_slot(int breakno) static int hw_break_reserve_slot(int breakno)
...@@ -233,6 +244,9 @@ static int hw_break_reserve_slot(int breakno) ...@@ -233,6 +244,9 @@ static int hw_break_reserve_slot(int breakno)
int cnt = 0; int cnt = 0;
struct perf_event **pevent; struct perf_event **pevent;
if (dbg_is_early)
return 0;
for_each_online_cpu(cpu) { for_each_online_cpu(cpu) {
cnt++; cnt++;
pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu); pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu);
...@@ -258,6 +272,9 @@ static int hw_break_release_slot(int breakno) ...@@ -258,6 +272,9 @@ static int hw_break_release_slot(int breakno)
struct perf_event **pevent; struct perf_event **pevent;
int cpu; int cpu;
if (dbg_is_early)
return 0;
for_each_online_cpu(cpu) { for_each_online_cpu(cpu) {
pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu); pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu);
if (dbg_release_bp_slot(*pevent)) if (dbg_release_bp_slot(*pevent))
...@@ -302,7 +319,11 @@ static void kgdb_remove_all_hw_break(void) ...@@ -302,7 +319,11 @@ static void kgdb_remove_all_hw_break(void)
bp = *per_cpu_ptr(breakinfo[i].pev, cpu); bp = *per_cpu_ptr(breakinfo[i].pev, cpu);
if (bp->attr.disabled == 1) if (bp->attr.disabled == 1)
continue; 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; bp->attr.disabled = 1;
} }
} }
...@@ -379,6 +400,11 @@ void kgdb_disable_hw_debug(struct pt_regs *regs) ...@@ -379,6 +400,11 @@ void kgdb_disable_hw_debug(struct pt_regs *regs)
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
if (!breakinfo[i].enabled) if (!breakinfo[i].enabled)
continue; 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); bp = *per_cpu_ptr(breakinfo[i].pev, cpu);
if (bp->attr.disabled == 1) if (bp->attr.disabled == 1)
continue; continue;
...@@ -595,15 +621,16 @@ static struct notifier_block kgdb_notifier = { ...@@ -595,15 +621,16 @@ static struct notifier_block kgdb_notifier = {
* specific callbacks. * specific callbacks.
*/ */
int kgdb_arch_init(void) int kgdb_arch_init(void)
{
return register_die_notifier(&kgdb_notifier);
}
void kgdb_arch_late(void)
{ {
int i, cpu; int i, cpu;
int ret;
struct perf_event_attr attr; struct perf_event_attr attr;
struct perf_event **pevent; 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 * Pre-allocate the hw breakpoint structions in the non-atomic
* portion of kgdb because this operation requires mutexs to * portion of kgdb because this operation requires mutexs to
...@@ -615,12 +642,15 @@ int kgdb_arch_init(void) ...@@ -615,12 +642,15 @@ int kgdb_arch_init(void)
attr.bp_type = HW_BREAKPOINT_W; attr.bp_type = HW_BREAKPOINT_W;
attr.disabled = 1; attr.disabled = 1;
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
if (breakinfo[i].pev)
continue;
breakinfo[i].pev = register_wide_hw_breakpoint(&attr, NULL); breakinfo[i].pev = register_wide_hw_breakpoint(&attr, NULL);
if (IS_ERR(breakinfo[i].pev)) { 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; breakinfo[i].pev = NULL;
kgdb_arch_exit(); kgdb_arch_exit();
return -1; return;
} }
for_each_online_cpu(cpu) { for_each_online_cpu(cpu) {
pevent = per_cpu_ptr(breakinfo[i].pev, cpu); pevent = per_cpu_ptr(breakinfo[i].pev, cpu);
...@@ -631,7 +661,6 @@ int kgdb_arch_init(void) ...@@ -631,7 +661,6 @@ int kgdb_arch_init(void)
} }
} }
} }
return ret;
} }
/** /**
......
...@@ -725,6 +725,7 @@ void __init setup_arch(char **cmdline_p) ...@@ -725,6 +725,7 @@ void __init setup_arch(char **cmdline_p)
/* VMI may relocate the fixmap; do this before touching ioremap area */ /* VMI may relocate the fixmap; do this before touching ioremap area */
vmi_init(); vmi_init();
early_trap_init();
early_cpu_init(); early_cpu_init();
early_ioremap_init(); early_ioremap_init();
......
...@@ -808,6 +808,16 @@ dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code) ...@@ -808,6 +808,16 @@ dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code)
} }
#endif #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) void __init trap_init(void)
{ {
int i; int i;
...@@ -821,10 +831,7 @@ void __init trap_init(void) ...@@ -821,10 +831,7 @@ void __init trap_init(void)
#endif #endif
set_intr_gate(0, &divide_error); set_intr_gate(0, &divide_error);
set_intr_gate_ist(1, &debug, DEBUG_STACK);
set_intr_gate_ist(2, &nmi, NMI_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 */ /* int4 can be called from all */
set_system_intr_gate(4, &overflow); set_system_intr_gate(4, &overflow);
set_intr_gate(5, &bounds); set_intr_gate(5, &bounds);
...@@ -840,7 +847,6 @@ void __init trap_init(void) ...@@ -840,7 +847,6 @@ void __init trap_init(void)
set_intr_gate(11, &segment_not_present); set_intr_gate(11, &segment_not_present);
set_intr_gate_ist(12, &stack_segment, STACKFAULT_STACK); set_intr_gate_ist(12, &stack_segment, STACKFAULT_STACK);
set_intr_gate(13, &general_protection); set_intr_gate(13, &general_protection);
set_intr_gate(14, &page_fault);
set_intr_gate(15, &spurious_interrupt_bug); set_intr_gate(15, &spurious_interrupt_bug);
set_intr_gate(16, &coprocessor_error); set_intr_gate(16, &coprocessor_error);
set_intr_gate(17, &alignment_check); set_intr_gate(17, &alignment_check);
......
...@@ -223,6 +223,25 @@ static struct kgdb_io kgdboc_io_ops = { ...@@ -223,6 +223,25 @@ static struct kgdb_io kgdboc_io_ops = {
.post_exception = kgdboc_post_exp_handler, .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_init(init_kgdboc);
module_exit(cleanup_kgdboc); module_exit(cleanup_kgdboc);
module_param_call(kgdboc, param_set_kgdboc_var, param_get_string, &kps, 0644); module_param_call(kgdboc, param_set_kgdboc_var, param_get_string, &kps, 0644);
......
...@@ -19,6 +19,9 @@ ...@@ -19,6 +19,9 @@
#include <linux/usb/ch9.h> #include <linux/usb/ch9.h>
#include <linux/usb/ehci_def.h> #include <linux/usb/ehci_def.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/serial_core.h>
#include <linux/kgdb.h>
#include <linux/kthread.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/pci-direct.h> #include <asm/pci-direct.h>
#include <asm/fixmap.h> #include <asm/fixmap.h>
...@@ -55,6 +58,7 @@ static struct ehci_regs __iomem *ehci_regs; ...@@ -55,6 +58,7 @@ static struct ehci_regs __iomem *ehci_regs;
static struct ehci_dbg_port __iomem *ehci_debug; static struct ehci_dbg_port __iomem *ehci_debug;
static int dbgp_not_safe; /* Cannot use debug device during ehci reset */ static int dbgp_not_safe; /* Cannot use debug device during ehci reset */
static unsigned int dbgp_endpoint_out; static unsigned int dbgp_endpoint_out;
static unsigned int dbgp_endpoint_in;
struct ehci_dev { struct ehci_dev {
u32 bus; u32 bus;
...@@ -91,6 +95,13 @@ static inline u32 dbgp_len_update(u32 x, u32 len) ...@@ -91,6 +95,13 @@ static inline u32 dbgp_len_update(u32 x, u32 len)
return (x & ~0x0f) | (len & 0x0f); 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) * USB Packet IDs (PIDs)
*/ */
...@@ -182,11 +193,10 @@ static void dbgp_breath(void) ...@@ -182,11 +193,10 @@ static void dbgp_breath(void)
/* Sleep to give the debug port a chance to breathe */ /* 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; u32 pids, lpid;
int ret; int ret;
int loop = DBGP_LOOPS;
retry: retry:
writel(ctrl | DBGP_GO, &ehci_debug->control); writel(ctrl | DBGP_GO, &ehci_debug->control);
...@@ -276,13 +286,13 @@ static int dbgp_bulk_write(unsigned devnum, unsigned endpoint, ...@@ -276,13 +286,13 @@ static int dbgp_bulk_write(unsigned devnum, unsigned endpoint,
dbgp_set_data(bytes, size); dbgp_set_data(bytes, size);
writel(addr, &ehci_debug->address); writel(addr, &ehci_debug->address);
writel(pids, &ehci_debug->pids); writel(pids, &ehci_debug->pids);
ret = dbgp_wait_until_done(ctrl); ret = dbgp_wait_until_done(ctrl, DBGP_LOOPS);
return ret; return ret;
} }
static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data, static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data,
int size) int size, int loops)
{ {
u32 pids, addr, ctrl; u32 pids, addr, ctrl;
int ret; int ret;
...@@ -302,7 +312,7 @@ static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data, ...@@ -302,7 +312,7 @@ static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data,
writel(addr, &ehci_debug->address); writel(addr, &ehci_debug->address);
writel(pids, &ehci_debug->pids); writel(pids, &ehci_debug->pids);
ret = dbgp_wait_until_done(ctrl); ret = dbgp_wait_until_done(ctrl, loops);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -343,12 +353,12 @@ static int dbgp_control_msg(unsigned devnum, int requesttype, ...@@ -343,12 +353,12 @@ static int dbgp_control_msg(unsigned devnum, int requesttype,
dbgp_set_data(&req, sizeof(req)); dbgp_set_data(&req, sizeof(req));
writel(addr, &ehci_debug->address); writel(addr, &ehci_debug->address);
writel(pids, &ehci_debug->pids); writel(pids, &ehci_debug->pids);
ret = dbgp_wait_until_done(ctrl); ret = dbgp_wait_until_done(ctrl, DBGP_LOOPS);
if (ret < 0) if (ret < 0)
return ret; return ret;
/* Read the result */ /* 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 */ /* Find a PCI capability */
...@@ -559,6 +569,7 @@ int dbgp_external_startup(void) ...@@ -559,6 +569,7 @@ int dbgp_external_startup(void)
goto err; goto err;
} }
dbgp_endpoint_out = dbgp_desc.bDebugOutEndpoint; dbgp_endpoint_out = dbgp_desc.bDebugOutEndpoint;
dbgp_endpoint_in = dbgp_desc.bDebugInEndpoint;
/* Move the device to 127 if it isn't already there */ /* Move the device to 127 if it isn't already there */
if (devnum != USB_DEBUG_DEVNUM) { if (devnum != USB_DEBUG_DEVNUM) {
...@@ -968,8 +979,9 @@ int dbgp_reset_prep(void) ...@@ -968,8 +979,9 @@ int dbgp_reset_prep(void)
if (!ehci_debug) if (!ehci_debug)
return 0; return 0;
if (early_dbgp_console.index != -1 && if ((early_dbgp_console.index != -1 &&
!(early_dbgp_console.flags & CON_BOOT)) !(early_dbgp_console.flags & CON_BOOT)) ||
dbgp_kgdb_mode)
return 1; return 1;
/* This means the console is not initialized, or should get /* This means the console is not initialized, or should get
* shutdown so as to allow for reuse of the usb device, which * shutdown so as to allow for reuse of the usb device, which
...@@ -982,3 +994,93 @@ int dbgp_reset_prep(void) ...@@ -982,3 +994,93 @@ int dbgp_reset_prep(void)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(dbgp_reset_prep); 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); ...@@ -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_set_breakpoint(unsigned long addr, char *saved_instr);
extern int kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle); 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. * struct kgdb_arch - Describe architecture specific values.
* @gdb_bpt_instr: The instruction to trigger a breakpoint. * @gdb_bpt_instr: The instruction to trigger a breakpoint.
...@@ -285,7 +296,10 @@ extern int kgdb_single_step; ...@@ -285,7 +296,10 @@ extern int kgdb_single_step;
extern atomic_t kgdb_active; extern atomic_t kgdb_active;
#define in_dbg_master() \ #define in_dbg_master() \
(raw_smp_processor_id() == atomic_read(&kgdb_active)) (raw_smp_processor_id() == atomic_read(&kgdb_active))
extern bool dbg_is_early;
extern void __init dbg_late_init(void);
#else /* ! CONFIG_KGDB */ #else /* ! CONFIG_KGDB */
#define in_dbg_master() (0) #define in_dbg_master() (0)
#define dbg_late_init()
#endif /* ! CONFIG_KGDB */ #endif /* ! CONFIG_KGDB */
#endif /* _KGDB_H_ */ #endif /* _KGDB_H_ */
...@@ -62,7 +62,7 @@ ...@@ -62,7 +62,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/signal.h> #include <linux/signal.h>
#include <linux/idr.h> #include <linux/idr.h>
#include <linux/kdb.h> #include <linux/kgdb.h>
#include <linux/ftrace.h> #include <linux/ftrace.h>
#include <linux/async.h> #include <linux/async.h>
#include <linux/kmemcheck.h> #include <linux/kmemcheck.h>
...@@ -676,7 +676,7 @@ asmlinkage void __init start_kernel(void) ...@@ -676,7 +676,7 @@ asmlinkage void __init start_kernel(void)
buffer_init(); buffer_init();
key_init(); key_init();
security_init(); security_init();
kdb_init(KDB_INIT_FULL); dbg_late_init();
vfs_caches_init(totalram_pages); vfs_caches_init(totalram_pages);
signals_init(); signals_init();
/* rootfs populating might need page-writeback */ /* rootfs populating might need page-writeback */
......
...@@ -78,6 +78,8 @@ static DEFINE_SPINLOCK(kgdb_registration_lock); ...@@ -78,6 +78,8 @@ static DEFINE_SPINLOCK(kgdb_registration_lock);
static int kgdb_con_registered; static int kgdb_con_registered;
/* determine if kgdb console output should be used */ /* determine if kgdb console output should be used */
static int kgdb_use_con; 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 */ /* Next cpu to become the master debug core */
int dbg_switch_cpu; int dbg_switch_cpu;
...@@ -777,11 +779,25 @@ static struct notifier_block kgdb_panic_event_nb = { ...@@ -777,11 +779,25 @@ static struct notifier_block kgdb_panic_event_nb = {
.priority = INT_MAX, .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) static void kgdb_register_callbacks(void)
{ {
if (!kgdb_io_module_registered) { if (!kgdb_io_module_registered) {
kgdb_io_module_registered = 1; kgdb_io_module_registered = 1;
kgdb_arch_init(); kgdb_arch_init();
if (!dbg_is_early)
kgdb_arch_late();
atomic_notifier_chain_register(&panic_notifier_list, atomic_notifier_chain_register(&panic_notifier_list,
&kgdb_panic_event_nb); &kgdb_panic_event_nb);
#ifdef CONFIG_MAGIC_SYSRQ #ifdef CONFIG_MAGIC_SYSRQ
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment