diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-21 14:10:41 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-21 14:10:41 -0400 |
commit | ac3ee84c604502240122c47b52f0542ec8774f15 (patch) | |
tree | fa74b50e310af6cef3298a052514b2d42b260d6b /arch | |
parent | 90b9a32d8f441369b2f97a765d2d957b531eb653 (diff) | |
parent | 4fe1da4ebc18c4c42fa56c228447f68033fce5f0 (diff) |
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
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/include/asm/processor.h | 2 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/common.c | 29 | ||||
-rw-r--r-- | arch/x86/kernel/early_printk.c | 8 | ||||
-rw-r--r-- | arch/x86/kernel/kgdb.c | 47 | ||||
-rw-r--r-- | arch/x86/kernel/setup.c | 1 | ||||
-rw-r--r-- | arch/x86/kernel/traps.c | 14 |
6 files changed, 76 insertions, 25 deletions
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 5a51379dcbe4..7e5c6a60b8ee 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h | |||
@@ -789,6 +789,8 @@ static inline void wbinvd_halt(void) | |||
789 | extern void enable_sep_cpu(void); | 789 | extern void enable_sep_cpu(void); |
790 | extern int sysenter_setup(void); | 790 | extern int sysenter_setup(void); |
791 | 791 | ||
792 | extern void early_trap_init(void); | ||
793 | |||
792 | /* Defined in head.S */ | 794 | /* Defined in head.S */ |
793 | extern struct desc_ptr early_gdt_descr; | 795 | extern struct desc_ptr early_gdt_descr; |
794 | 796 | ||
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index c1c00d0b1692..cc83a002786e 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c | |||
@@ -1084,6 +1084,20 @@ static void clear_all_debug_regs(void) | |||
1084 | } | 1084 | } |
1085 | } | 1085 | } |
1086 | 1086 | ||
1087 | #ifdef CONFIG_KGDB | ||
1088 | /* | ||
1089 | * Restore debug regs if using kgdbwait and you have a kernel debugger | ||
1090 | * connection established. | ||
1091 | */ | ||
1092 | static void dbg_restore_debug_regs(void) | ||
1093 | { | ||
1094 | if (unlikely(kgdb_connected && arch_kgdb_ops.correct_hw_break)) | ||
1095 | arch_kgdb_ops.correct_hw_break(); | ||
1096 | } | ||
1097 | #else /* ! CONFIG_KGDB */ | ||
1098 | #define dbg_restore_debug_regs() | ||
1099 | #endif /* ! CONFIG_KGDB */ | ||
1100 | |||
1087 | /* | 1101 | /* |
1088 | * cpu_init() initializes state that is per-CPU. Some data is already | 1102 | * cpu_init() initializes state that is per-CPU. Some data is already |
1089 | * initialized (naturally) in the bootstrap process, such as the GDT | 1103 | * initialized (naturally) in the bootstrap process, such as the GDT |
@@ -1174,18 +1188,8 @@ void __cpuinit cpu_init(void) | |||
1174 | load_TR_desc(); | 1188 | load_TR_desc(); |
1175 | load_LDT(&init_mm.context); | 1189 | load_LDT(&init_mm.context); |
1176 | 1190 | ||
1177 | #ifdef CONFIG_KGDB | 1191 | clear_all_debug_regs(); |
1178 | /* | 1192 | dbg_restore_debug_regs(); |
1179 | * If the kgdb is connected no debug regs should be altered. This | ||
1180 | * is only applicable when KGDB and a KGDB I/O module are built | ||
1181 | * into the kernel and you are using early debugging with | ||
1182 | * kgdbwait. KGDB will control the kernel HW breakpoint registers. | ||
1183 | */ | ||
1184 | if (kgdb_connected && arch_kgdb_ops.correct_hw_break) | ||
1185 | arch_kgdb_ops.correct_hw_break(); | ||
1186 | else | ||
1187 | #endif | ||
1188 | clear_all_debug_regs(); | ||
1189 | 1193 | ||
1190 | fpu_init(); | 1194 | fpu_init(); |
1191 | 1195 | ||
@@ -1239,6 +1243,7 @@ void __cpuinit cpu_init(void) | |||
1239 | #endif | 1243 | #endif |
1240 | 1244 | ||
1241 | clear_all_debug_regs(); | 1245 | clear_all_debug_regs(); |
1246 | dbg_restore_debug_regs(); | ||
1242 | 1247 | ||
1243 | /* | 1248 | /* |
1244 | * Force FPU initialization: | 1249 | * Force FPU initialization: |
diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c index b9c830c12b4a..fa99bae75ace 100644 --- a/arch/x86/kernel/early_printk.c +++ b/arch/x86/kernel/early_printk.c | |||
@@ -41,6 +41,14 @@ static void early_vga_write(struct console *con, const char *str, unsigned n) | |||
41 | writew(0x720, VGABASE + 2*(max_xpos*j + i)); | 41 | writew(0x720, VGABASE + 2*(max_xpos*j + i)); |
42 | current_ypos = max_ypos-1; | 42 | current_ypos = max_ypos-1; |
43 | } | 43 | } |
44 | #ifdef CONFIG_KGDB_KDB | ||
45 | if (c == '\b') { | ||
46 | if (current_xpos > 0) | ||
47 | current_xpos--; | ||
48 | } else if (c == '\r') { | ||
49 | current_xpos = 0; | ||
50 | } else | ||
51 | #endif | ||
44 | if (c == '\n') { | 52 | if (c == '\n') { |
45 | current_xpos = 0; | 53 | current_xpos = 0; |
46 | current_ypos++; | 54 | current_ypos++; |
diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c index 95b89d4cb8f1..4f4af75b9482 100644 --- a/arch/x86/kernel/kgdb.c +++ b/arch/x86/kernel/kgdb.c | |||
@@ -199,6 +199,8 @@ static struct hw_breakpoint { | |||
199 | struct perf_event **pev; | 199 | struct perf_event **pev; |
200 | } breakinfo[4]; | 200 | } breakinfo[4]; |
201 | 201 | ||
202 | static unsigned long early_dr7; | ||
203 | |||
202 | static void kgdb_correct_hw_break(void) | 204 | static void kgdb_correct_hw_break(void) |
203 | { | 205 | { |
204 | int breakno; | 206 | int breakno; |
@@ -210,6 +212,14 @@ static void kgdb_correct_hw_break(void) | |||
210 | int cpu = raw_smp_processor_id(); | 212 | int cpu = raw_smp_processor_id(); |
211 | if (!breakinfo[breakno].enabled) | 213 | if (!breakinfo[breakno].enabled) |
212 | continue; | 214 | continue; |
215 | if (dbg_is_early) { | ||
216 | set_debugreg(breakinfo[breakno].addr, breakno); | ||
217 | early_dr7 |= encode_dr7(breakno, | ||
218 | breakinfo[breakno].len, | ||
219 | breakinfo[breakno].type); | ||
220 | set_debugreg(early_dr7, 7); | ||
221 | continue; | ||
222 | } | ||
213 | bp = *per_cpu_ptr(breakinfo[breakno].pev, cpu); | 223 | bp = *per_cpu_ptr(breakinfo[breakno].pev, cpu); |
214 | info = counter_arch_bp(bp); | 224 | info = counter_arch_bp(bp); |
215 | if (bp->attr.disabled != 1) | 225 | if (bp->attr.disabled != 1) |
@@ -224,7 +234,8 @@ static void kgdb_correct_hw_break(void) | |||
224 | if (!val) | 234 | if (!val) |
225 | bp->attr.disabled = 0; | 235 | bp->attr.disabled = 0; |
226 | } | 236 | } |
227 | hw_breakpoint_restore(); | 237 | if (!dbg_is_early) |
238 | hw_breakpoint_restore(); | ||
228 | } | 239 | } |
229 | 240 | ||
230 | static int hw_break_reserve_slot(int breakno) | 241 | static int hw_break_reserve_slot(int breakno) |
@@ -233,6 +244,9 @@ static int hw_break_reserve_slot(int breakno) | |||
233 | int cnt = 0; | 244 | int cnt = 0; |
234 | struct perf_event **pevent; | 245 | struct perf_event **pevent; |
235 | 246 | ||
247 | if (dbg_is_early) | ||
248 | return 0; | ||
249 | |||
236 | for_each_online_cpu(cpu) { | 250 | for_each_online_cpu(cpu) { |
237 | cnt++; | 251 | cnt++; |
238 | pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu); | 252 | pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu); |
@@ -258,6 +272,9 @@ static int hw_break_release_slot(int breakno) | |||
258 | struct perf_event **pevent; | 272 | struct perf_event **pevent; |
259 | int cpu; | 273 | int cpu; |
260 | 274 | ||
275 | if (dbg_is_early) | ||
276 | return 0; | ||
277 | |||
261 | for_each_online_cpu(cpu) { | 278 | for_each_online_cpu(cpu) { |
262 | pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu); | 279 | pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu); |
263 | if (dbg_release_bp_slot(*pevent)) | 280 | if (dbg_release_bp_slot(*pevent)) |
@@ -302,7 +319,11 @@ static void kgdb_remove_all_hw_break(void) | |||
302 | bp = *per_cpu_ptr(breakinfo[i].pev, cpu); | 319 | bp = *per_cpu_ptr(breakinfo[i].pev, cpu); |
303 | if (bp->attr.disabled == 1) | 320 | if (bp->attr.disabled == 1) |
304 | continue; | 321 | continue; |
305 | arch_uninstall_hw_breakpoint(bp); | 322 | if (dbg_is_early) |
323 | early_dr7 &= ~encode_dr7(i, breakinfo[i].len, | ||
324 | breakinfo[i].type); | ||
325 | else | ||
326 | arch_uninstall_hw_breakpoint(bp); | ||
306 | bp->attr.disabled = 1; | 327 | bp->attr.disabled = 1; |
307 | } | 328 | } |
308 | } | 329 | } |
@@ -379,6 +400,11 @@ void kgdb_disable_hw_debug(struct pt_regs *regs) | |||
379 | for (i = 0; i < 4; i++) { | 400 | for (i = 0; i < 4; i++) { |
380 | if (!breakinfo[i].enabled) | 401 | if (!breakinfo[i].enabled) |
381 | continue; | 402 | continue; |
403 | if (dbg_is_early) { | ||
404 | early_dr7 &= ~encode_dr7(i, breakinfo[i].len, | ||
405 | breakinfo[i].type); | ||
406 | continue; | ||
407 | } | ||
382 | bp = *per_cpu_ptr(breakinfo[i].pev, cpu); | 408 | bp = *per_cpu_ptr(breakinfo[i].pev, cpu); |
383 | if (bp->attr.disabled == 1) | 409 | if (bp->attr.disabled == 1) |
384 | continue; | 410 | continue; |
@@ -596,14 +622,15 @@ static struct notifier_block kgdb_notifier = { | |||
596 | */ | 622 | */ |
597 | int kgdb_arch_init(void) | 623 | int kgdb_arch_init(void) |
598 | { | 624 | { |
625 | return register_die_notifier(&kgdb_notifier); | ||
626 | } | ||
627 | |||
628 | void kgdb_arch_late(void) | ||
629 | { | ||
599 | int i, cpu; | 630 | int i, cpu; |
600 | int ret; | ||
601 | struct perf_event_attr attr; | 631 | struct perf_event_attr attr; |
602 | struct perf_event **pevent; | 632 | struct perf_event **pevent; |
603 | 633 | ||
604 | ret = register_die_notifier(&kgdb_notifier); | ||
605 | if (ret != 0) | ||
606 | return ret; | ||
607 | /* | 634 | /* |
608 | * Pre-allocate the hw breakpoint structions in the non-atomic | 635 | * Pre-allocate the hw breakpoint structions in the non-atomic |
609 | * portion of kgdb because this operation requires mutexs to | 636 | * portion of kgdb because this operation requires mutexs to |
@@ -615,12 +642,15 @@ int kgdb_arch_init(void) | |||
615 | attr.bp_type = HW_BREAKPOINT_W; | 642 | attr.bp_type = HW_BREAKPOINT_W; |
616 | attr.disabled = 1; | 643 | attr.disabled = 1; |
617 | for (i = 0; i < 4; i++) { | 644 | for (i = 0; i < 4; i++) { |
645 | if (breakinfo[i].pev) | ||
646 | continue; | ||
618 | breakinfo[i].pev = register_wide_hw_breakpoint(&attr, NULL); | 647 | breakinfo[i].pev = register_wide_hw_breakpoint(&attr, NULL); |
619 | if (IS_ERR(breakinfo[i].pev)) { | 648 | if (IS_ERR(breakinfo[i].pev)) { |
620 | printk(KERN_ERR "kgdb: Could not allocate hw breakpoints\n"); | 649 | printk(KERN_ERR "kgdb: Could not allocate hw" |
650 | "breakpoints\nDisabling the kernel debugger\n"); | ||
621 | breakinfo[i].pev = NULL; | 651 | breakinfo[i].pev = NULL; |
622 | kgdb_arch_exit(); | 652 | kgdb_arch_exit(); |
623 | return -1; | 653 | return; |
624 | } | 654 | } |
625 | for_each_online_cpu(cpu) { | 655 | for_each_online_cpu(cpu) { |
626 | pevent = per_cpu_ptr(breakinfo[i].pev, cpu); | 656 | pevent = per_cpu_ptr(breakinfo[i].pev, cpu); |
@@ -631,7 +661,6 @@ int kgdb_arch_init(void) | |||
631 | } | 661 | } |
632 | } | 662 | } |
633 | } | 663 | } |
634 | return ret; | ||
635 | } | 664 | } |
636 | 665 | ||
637 | /** | 666 | /** |
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index c4851eff57b3..e8029896309a 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c | |||
@@ -725,6 +725,7 @@ void __init setup_arch(char **cmdline_p) | |||
725 | /* VMI may relocate the fixmap; do this before touching ioremap area */ | 725 | /* VMI may relocate the fixmap; do this before touching ioremap area */ |
726 | vmi_init(); | 726 | vmi_init(); |
727 | 727 | ||
728 | early_trap_init(); | ||
728 | early_cpu_init(); | 729 | early_cpu_init(); |
729 | early_ioremap_init(); | 730 | early_ioremap_init(); |
730 | 731 | ||
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 7eaad4c5110a..142d70c74b02 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c | |||
@@ -808,6 +808,16 @@ dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code) | |||
808 | } | 808 | } |
809 | #endif | 809 | #endif |
810 | 810 | ||
811 | /* Set of traps needed for early debugging. */ | ||
812 | void __init early_trap_init(void) | ||
813 | { | ||
814 | set_intr_gate_ist(1, &debug, DEBUG_STACK); | ||
815 | /* int3 can be called from all */ | ||
816 | set_system_intr_gate_ist(3, &int3, DEBUG_STACK); | ||
817 | set_intr_gate(14, &page_fault); | ||
818 | load_idt(&idt_descr); | ||
819 | } | ||
820 | |||
811 | void __init trap_init(void) | 821 | void __init trap_init(void) |
812 | { | 822 | { |
813 | int i; | 823 | int i; |
@@ -821,10 +831,7 @@ void __init trap_init(void) | |||
821 | #endif | 831 | #endif |
822 | 832 | ||
823 | set_intr_gate(0, ÷_error); | 833 | set_intr_gate(0, ÷_error); |
824 | set_intr_gate_ist(1, &debug, DEBUG_STACK); | ||
825 | set_intr_gate_ist(2, &nmi, NMI_STACK); | 834 | set_intr_gate_ist(2, &nmi, NMI_STACK); |
826 | /* int3 can be called from all */ | ||
827 | set_system_intr_gate_ist(3, &int3, DEBUG_STACK); | ||
828 | /* int4 can be called from all */ | 835 | /* int4 can be called from all */ |
829 | set_system_intr_gate(4, &overflow); | 836 | set_system_intr_gate(4, &overflow); |
830 | set_intr_gate(5, &bounds); | 837 | set_intr_gate(5, &bounds); |
@@ -840,7 +847,6 @@ void __init trap_init(void) | |||
840 | set_intr_gate(11, &segment_not_present); | 847 | set_intr_gate(11, &segment_not_present); |
841 | set_intr_gate_ist(12, &stack_segment, STACKFAULT_STACK); | 848 | set_intr_gate_ist(12, &stack_segment, STACKFAULT_STACK); |
842 | set_intr_gate(13, &general_protection); | 849 | set_intr_gate(13, &general_protection); |
843 | set_intr_gate(14, &page_fault); | ||
844 | set_intr_gate(15, &spurious_interrupt_bug); | 850 | set_intr_gate(15, &spurious_interrupt_bug); |
845 | set_intr_gate(16, &coprocessor_error); | 851 | set_intr_gate(16, &coprocessor_error); |
846 | set_intr_gate(17, &alignment_check); | 852 | set_intr_gate(17, &alignment_check); |