aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/kgdb.c
diff options
context:
space:
mode:
authorJason Wessel <jason.wessel@windriver.com>2010-05-20 22:04:30 -0400
committerJason Wessel <jason.wessel@windriver.com>2010-05-20 22:04:30 -0400
commit031acd8c42edd61070f81c51edc89e83147a3d0e (patch)
treef0f848ca6b19ec049b00a430bb0fba1035acb76b /arch/x86/kernel/kgdb.c
parent0b4b3827db386ec6034a5aba1261025b039440c2 (diff)
x86,kgdb: Implement early hardware breakpoint debugging
It is not possible to use the hw_breakpoint.c API prior to mm_init(), but it is possible to use hardware breakpoints with the kernel debugger. Prior to smp_init() it is possible to simply write to the dr registers of the boot cpu directly. This can be used up until the kgdb_arch_late() is invoked, at which point the standard hw_breakpoint.c API will get used. CC: Frederic Weisbecker <fweisbec@gmail.com> CC: Ingo Molnar <mingo@elte.hu> Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
Diffstat (limited to 'arch/x86/kernel/kgdb.c')
-rw-r--r--arch/x86/kernel/kgdb.c30
1 files changed, 28 insertions, 2 deletions
diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c
index 2b71ec41869f..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
202static unsigned long early_dr7;
203
202static void kgdb_correct_hw_break(void) 204static 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
230static int hw_break_reserve_slot(int breakno) 241static 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;