diff options
Diffstat (limited to 'arch/x86/kernel/kgdb.c')
-rw-r--r-- | arch/x86/kernel/kgdb.c | 241 |
1 files changed, 179 insertions, 62 deletions
diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c index 8d82a77a3f3b..b2258ca91003 100644 --- a/arch/x86/kernel/kgdb.c +++ b/arch/x86/kernel/kgdb.c | |||
@@ -42,7 +42,9 @@ | |||
42 | #include <linux/init.h> | 42 | #include <linux/init.h> |
43 | #include <linux/smp.h> | 43 | #include <linux/smp.h> |
44 | #include <linux/nmi.h> | 44 | #include <linux/nmi.h> |
45 | #include <linux/hw_breakpoint.h> | ||
45 | 46 | ||
47 | #include <asm/debugreg.h> | ||
46 | #include <asm/apicdef.h> | 48 | #include <asm/apicdef.h> |
47 | #include <asm/system.h> | 49 | #include <asm/system.h> |
48 | 50 | ||
@@ -85,10 +87,15 @@ void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) | |||
85 | gdb_regs[GDB_DS] = regs->ds; | 87 | gdb_regs[GDB_DS] = regs->ds; |
86 | gdb_regs[GDB_ES] = regs->es; | 88 | gdb_regs[GDB_ES] = regs->es; |
87 | gdb_regs[GDB_CS] = regs->cs; | 89 | gdb_regs[GDB_CS] = regs->cs; |
88 | gdb_regs[GDB_SS] = __KERNEL_DS; | ||
89 | gdb_regs[GDB_FS] = 0xFFFF; | 90 | gdb_regs[GDB_FS] = 0xFFFF; |
90 | gdb_regs[GDB_GS] = 0xFFFF; | 91 | gdb_regs[GDB_GS] = 0xFFFF; |
91 | gdb_regs[GDB_SP] = (int)®s->sp; | 92 | if (user_mode_vm(regs)) { |
93 | gdb_regs[GDB_SS] = regs->ss; | ||
94 | gdb_regs[GDB_SP] = regs->sp; | ||
95 | } else { | ||
96 | gdb_regs[GDB_SS] = __KERNEL_DS; | ||
97 | gdb_regs[GDB_SP] = kernel_stack_pointer(regs); | ||
98 | } | ||
92 | #else | 99 | #else |
93 | gdb_regs[GDB_R8] = regs->r8; | 100 | gdb_regs[GDB_R8] = regs->r8; |
94 | gdb_regs[GDB_R9] = regs->r9; | 101 | gdb_regs[GDB_R9] = regs->r9; |
@@ -101,7 +108,7 @@ void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) | |||
101 | gdb_regs32[GDB_PS] = regs->flags; | 108 | gdb_regs32[GDB_PS] = regs->flags; |
102 | gdb_regs32[GDB_CS] = regs->cs; | 109 | gdb_regs32[GDB_CS] = regs->cs; |
103 | gdb_regs32[GDB_SS] = regs->ss; | 110 | gdb_regs32[GDB_SS] = regs->ss; |
104 | gdb_regs[GDB_SP] = regs->sp; | 111 | gdb_regs[GDB_SP] = kernel_stack_pointer(regs); |
105 | #endif | 112 | #endif |
106 | } | 113 | } |
107 | 114 | ||
@@ -198,41 +205,81 @@ void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) | |||
198 | 205 | ||
199 | static struct hw_breakpoint { | 206 | static struct hw_breakpoint { |
200 | unsigned enabled; | 207 | unsigned enabled; |
201 | unsigned type; | ||
202 | unsigned len; | ||
203 | unsigned long addr; | 208 | unsigned long addr; |
209 | int len; | ||
210 | int type; | ||
211 | struct perf_event **pev; | ||
204 | } breakinfo[4]; | 212 | } breakinfo[4]; |
205 | 213 | ||
206 | static void kgdb_correct_hw_break(void) | 214 | static void kgdb_correct_hw_break(void) |
207 | { | 215 | { |
208 | unsigned long dr7; | ||
209 | int correctit = 0; | ||
210 | int breakbit; | ||
211 | int breakno; | 216 | int breakno; |
212 | 217 | ||
213 | get_debugreg(dr7, 7); | ||
214 | for (breakno = 0; breakno < 4; breakno++) { | 218 | for (breakno = 0; breakno < 4; breakno++) { |
215 | breakbit = 2 << (breakno << 1); | 219 | struct perf_event *bp; |
216 | if (!(dr7 & breakbit) && breakinfo[breakno].enabled) { | 220 | struct arch_hw_breakpoint *info; |
217 | correctit = 1; | 221 | int val; |
218 | dr7 |= breakbit; | 222 | int cpu = raw_smp_processor_id(); |
219 | dr7 &= ~(0xf0000 << (breakno << 2)); | 223 | if (!breakinfo[breakno].enabled) |
220 | dr7 |= ((breakinfo[breakno].len << 2) | | 224 | continue; |
221 | breakinfo[breakno].type) << | 225 | bp = *per_cpu_ptr(breakinfo[breakno].pev, cpu); |
222 | ((breakno << 2) + 16); | 226 | info = counter_arch_bp(bp); |
223 | if (breakno >= 0 && breakno <= 3) | 227 | if (bp->attr.disabled != 1) |
224 | set_debugreg(breakinfo[breakno].addr, breakno); | 228 | continue; |
225 | 229 | bp->attr.bp_addr = breakinfo[breakno].addr; | |
226 | } else { | 230 | bp->attr.bp_len = breakinfo[breakno].len; |
227 | if ((dr7 & breakbit) && !breakinfo[breakno].enabled) { | 231 | bp->attr.bp_type = breakinfo[breakno].type; |
228 | correctit = 1; | 232 | info->address = breakinfo[breakno].addr; |
229 | dr7 &= ~breakbit; | 233 | info->len = breakinfo[breakno].len; |
230 | dr7 &= ~(0xf0000 << (breakno << 2)); | 234 | info->type = breakinfo[breakno].type; |
231 | } | 235 | val = arch_install_hw_breakpoint(bp); |
232 | } | 236 | if (!val) |
237 | bp->attr.disabled = 0; | ||
233 | } | 238 | } |
234 | if (correctit) | 239 | hw_breakpoint_restore(); |
235 | set_debugreg(dr7, 7); | 240 | } |
241 | |||
242 | static int hw_break_reserve_slot(int breakno) | ||
243 | { | ||
244 | int cpu; | ||
245 | int cnt = 0; | ||
246 | struct perf_event **pevent; | ||
247 | |||
248 | for_each_online_cpu(cpu) { | ||
249 | cnt++; | ||
250 | pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu); | ||
251 | if (dbg_reserve_bp_slot(*pevent)) | ||
252 | goto fail; | ||
253 | } | ||
254 | |||
255 | return 0; | ||
256 | |||
257 | fail: | ||
258 | for_each_online_cpu(cpu) { | ||
259 | cnt--; | ||
260 | if (!cnt) | ||
261 | break; | ||
262 | pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu); | ||
263 | dbg_release_bp_slot(*pevent); | ||
264 | } | ||
265 | return -1; | ||
266 | } | ||
267 | |||
268 | static int hw_break_release_slot(int breakno) | ||
269 | { | ||
270 | struct perf_event **pevent; | ||
271 | int cpu; | ||
272 | |||
273 | for_each_online_cpu(cpu) { | ||
274 | pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu); | ||
275 | if (dbg_release_bp_slot(*pevent)) | ||
276 | /* | ||
277 | * The debugger is responisble for handing the retry on | ||
278 | * remove failure. | ||
279 | */ | ||
280 | return -1; | ||
281 | } | ||
282 | return 0; | ||
236 | } | 283 | } |
237 | 284 | ||
238 | static int | 285 | static int |
@@ -246,6 +293,10 @@ kgdb_remove_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype) | |||
246 | if (i == 4) | 293 | if (i == 4) |
247 | return -1; | 294 | return -1; |
248 | 295 | ||
296 | if (hw_break_release_slot(i)) { | ||
297 | printk(KERN_ERR "Cannot remove hw breakpoint at %lx\n", addr); | ||
298 | return -1; | ||
299 | } | ||
249 | breakinfo[i].enabled = 0; | 300 | breakinfo[i].enabled = 0; |
250 | 301 | ||
251 | return 0; | 302 | return 0; |
@@ -254,15 +305,23 @@ kgdb_remove_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype) | |||
254 | static void kgdb_remove_all_hw_break(void) | 305 | static void kgdb_remove_all_hw_break(void) |
255 | { | 306 | { |
256 | int i; | 307 | int i; |
308 | int cpu = raw_smp_processor_id(); | ||
309 | struct perf_event *bp; | ||
257 | 310 | ||
258 | for (i = 0; i < 4; i++) | 311 | for (i = 0; i < 4; i++) { |
259 | memset(&breakinfo[i], 0, sizeof(struct hw_breakpoint)); | 312 | if (!breakinfo[i].enabled) |
313 | continue; | ||
314 | bp = *per_cpu_ptr(breakinfo[i].pev, cpu); | ||
315 | if (bp->attr.disabled == 1) | ||
316 | continue; | ||
317 | arch_uninstall_hw_breakpoint(bp); | ||
318 | bp->attr.disabled = 1; | ||
319 | } | ||
260 | } | 320 | } |
261 | 321 | ||
262 | static int | 322 | static int |
263 | kgdb_set_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype) | 323 | kgdb_set_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype) |
264 | { | 324 | { |
265 | unsigned type; | ||
266 | int i; | 325 | int i; |
267 | 326 | ||
268 | for (i = 0; i < 4; i++) | 327 | for (i = 0; i < 4; i++) |
@@ -273,27 +332,42 @@ kgdb_set_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype) | |||
273 | 332 | ||
274 | switch (bptype) { | 333 | switch (bptype) { |
275 | case BP_HARDWARE_BREAKPOINT: | 334 | case BP_HARDWARE_BREAKPOINT: |
276 | type = 0; | 335 | len = 1; |
277 | len = 1; | 336 | breakinfo[i].type = X86_BREAKPOINT_EXECUTE; |
278 | break; | 337 | break; |
279 | case BP_WRITE_WATCHPOINT: | 338 | case BP_WRITE_WATCHPOINT: |
280 | type = 1; | 339 | breakinfo[i].type = X86_BREAKPOINT_WRITE; |
281 | break; | 340 | break; |
282 | case BP_ACCESS_WATCHPOINT: | 341 | case BP_ACCESS_WATCHPOINT: |
283 | type = 3; | 342 | breakinfo[i].type = X86_BREAKPOINT_RW; |
284 | break; | 343 | break; |
285 | default: | 344 | default: |
286 | return -1; | 345 | return -1; |
287 | } | 346 | } |
288 | 347 | switch (len) { | |
289 | if (len == 1 || len == 2 || len == 4) | 348 | case 1: |
290 | breakinfo[i].len = len - 1; | 349 | breakinfo[i].len = X86_BREAKPOINT_LEN_1; |
291 | else | 350 | break; |
351 | case 2: | ||
352 | breakinfo[i].len = X86_BREAKPOINT_LEN_2; | ||
353 | break; | ||
354 | case 4: | ||
355 | breakinfo[i].len = X86_BREAKPOINT_LEN_4; | ||
356 | break; | ||
357 | #ifdef CONFIG_X86_64 | ||
358 | case 8: | ||
359 | breakinfo[i].len = X86_BREAKPOINT_LEN_8; | ||
360 | break; | ||
361 | #endif | ||
362 | default: | ||
292 | return -1; | 363 | return -1; |
293 | 364 | } | |
294 | breakinfo[i].enabled = 1; | ||
295 | breakinfo[i].addr = addr; | 365 | breakinfo[i].addr = addr; |
296 | breakinfo[i].type = type; | 366 | if (hw_break_reserve_slot(i)) { |
367 | breakinfo[i].addr = 0; | ||
368 | return -1; | ||
369 | } | ||
370 | breakinfo[i].enabled = 1; | ||
297 | 371 | ||
298 | return 0; | 372 | return 0; |
299 | } | 373 | } |
@@ -308,8 +382,21 @@ kgdb_set_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype) | |||
308 | */ | 382 | */ |
309 | void kgdb_disable_hw_debug(struct pt_regs *regs) | 383 | void kgdb_disable_hw_debug(struct pt_regs *regs) |
310 | { | 384 | { |
385 | int i; | ||
386 | int cpu = raw_smp_processor_id(); | ||
387 | struct perf_event *bp; | ||
388 | |||
311 | /* Disable hardware debugging while we are in kgdb: */ | 389 | /* Disable hardware debugging while we are in kgdb: */ |
312 | set_debugreg(0UL, 7); | 390 | set_debugreg(0UL, 7); |
391 | for (i = 0; i < 4; i++) { | ||
392 | if (!breakinfo[i].enabled) | ||
393 | continue; | ||
394 | bp = *per_cpu_ptr(breakinfo[i].pev, cpu); | ||
395 | if (bp->attr.disabled == 1) | ||
396 | continue; | ||
397 | arch_uninstall_hw_breakpoint(bp); | ||
398 | bp->attr.disabled = 1; | ||
399 | } | ||
313 | } | 400 | } |
314 | 401 | ||
315 | /** | 402 | /** |
@@ -373,7 +460,6 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, | |||
373 | struct pt_regs *linux_regs) | 460 | struct pt_regs *linux_regs) |
374 | { | 461 | { |
375 | unsigned long addr; | 462 | unsigned long addr; |
376 | unsigned long dr6; | ||
377 | char *ptr; | 463 | char *ptr; |
378 | int newPC; | 464 | int newPC; |
379 | 465 | ||
@@ -395,25 +481,10 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, | |||
395 | /* set the trace bit if we're stepping */ | 481 | /* set the trace bit if we're stepping */ |
396 | if (remcomInBuffer[0] == 's') { | 482 | if (remcomInBuffer[0] == 's') { |
397 | linux_regs->flags |= X86_EFLAGS_TF; | 483 | linux_regs->flags |= X86_EFLAGS_TF; |
398 | kgdb_single_step = 1; | ||
399 | atomic_set(&kgdb_cpu_doing_single_step, | 484 | atomic_set(&kgdb_cpu_doing_single_step, |
400 | raw_smp_processor_id()); | 485 | raw_smp_processor_id()); |
401 | } | 486 | } |
402 | 487 | ||
403 | get_debugreg(dr6, 6); | ||
404 | if (!(dr6 & 0x4000)) { | ||
405 | int breakno; | ||
406 | |||
407 | for (breakno = 0; breakno < 4; breakno++) { | ||
408 | if (dr6 & (1 << breakno) && | ||
409 | breakinfo[breakno].type == 0) { | ||
410 | /* Set restore flag: */ | ||
411 | linux_regs->flags |= X86_EFLAGS_RF; | ||
412 | break; | ||
413 | } | ||
414 | } | ||
415 | } | ||
416 | set_debugreg(0UL, 6); | ||
417 | kgdb_correct_hw_break(); | 488 | kgdb_correct_hw_break(); |
418 | 489 | ||
419 | return 0; | 490 | return 0; |
@@ -434,6 +505,11 @@ single_step_cont(struct pt_regs *regs, struct die_args *args) | |||
434 | "resuming...\n"); | 505 | "resuming...\n"); |
435 | kgdb_arch_handle_exception(args->trapnr, args->signr, | 506 | kgdb_arch_handle_exception(args->trapnr, args->signr, |
436 | args->err, "c", "", regs); | 507 | args->err, "c", "", regs); |
508 | /* | ||
509 | * Reset the BS bit in dr6 (pointed by args->err) to | ||
510 | * denote completion of processing | ||
511 | */ | ||
512 | (*(unsigned long *)ERR_PTR(args->err)) &= ~DR_STEP; | ||
437 | 513 | ||
438 | return NOTIFY_STOP; | 514 | return NOTIFY_STOP; |
439 | } | 515 | } |
@@ -476,8 +552,7 @@ static int __kgdb_notify(struct die_args *args, unsigned long cmd) | |||
476 | break; | 552 | break; |
477 | 553 | ||
478 | case DIE_DEBUG: | 554 | case DIE_DEBUG: |
479 | if (atomic_read(&kgdb_cpu_doing_single_step) == | 555 | if (atomic_read(&kgdb_cpu_doing_single_step) != -1) { |
480 | raw_smp_processor_id()) { | ||
481 | if (user_mode(regs)) | 556 | if (user_mode(regs)) |
482 | return single_step_cont(regs, args); | 557 | return single_step_cont(regs, args); |
483 | break; | 558 | break; |
@@ -530,7 +605,42 @@ static struct notifier_block kgdb_notifier = { | |||
530 | */ | 605 | */ |
531 | int kgdb_arch_init(void) | 606 | int kgdb_arch_init(void) |
532 | { | 607 | { |
533 | return register_die_notifier(&kgdb_notifier); | 608 | int i, cpu; |
609 | int ret; | ||
610 | struct perf_event_attr attr; | ||
611 | struct perf_event **pevent; | ||
612 | |||
613 | ret = register_die_notifier(&kgdb_notifier); | ||
614 | if (ret != 0) | ||
615 | return ret; | ||
616 | /* | ||
617 | * Pre-allocate the hw breakpoint structions in the non-atomic | ||
618 | * portion of kgdb because this operation requires mutexs to | ||
619 | * complete. | ||
620 | */ | ||
621 | hw_breakpoint_init(&attr); | ||
622 | attr.bp_addr = (unsigned long)kgdb_arch_init; | ||
623 | attr.bp_len = HW_BREAKPOINT_LEN_1; | ||
624 | attr.bp_type = HW_BREAKPOINT_W; | ||
625 | attr.disabled = 1; | ||
626 | for (i = 0; i < 4; i++) { | ||
627 | breakinfo[i].pev = register_wide_hw_breakpoint(&attr, NULL); | ||
628 | if (IS_ERR(breakinfo[i].pev)) { | ||
629 | printk(KERN_ERR "kgdb: Could not allocate hw breakpoints\n"); | ||
630 | breakinfo[i].pev = NULL; | ||
631 | kgdb_arch_exit(); | ||
632 | return -1; | ||
633 | } | ||
634 | for_each_online_cpu(cpu) { | ||
635 | pevent = per_cpu_ptr(breakinfo[i].pev, cpu); | ||
636 | pevent[0]->hw.sample_period = 1; | ||
637 | if (pevent[0]->destroy != NULL) { | ||
638 | pevent[0]->destroy = NULL; | ||
639 | release_bp_slot(*pevent); | ||
640 | } | ||
641 | } | ||
642 | } | ||
643 | return ret; | ||
534 | } | 644 | } |
535 | 645 | ||
536 | /** | 646 | /** |
@@ -541,6 +651,13 @@ int kgdb_arch_init(void) | |||
541 | */ | 651 | */ |
542 | void kgdb_arch_exit(void) | 652 | void kgdb_arch_exit(void) |
543 | { | 653 | { |
654 | int i; | ||
655 | for (i = 0; i < 4; i++) { | ||
656 | if (breakinfo[i].pev) { | ||
657 | unregister_wide_hw_breakpoint(breakinfo[i].pev); | ||
658 | breakinfo[i].pev = NULL; | ||
659 | } | ||
660 | } | ||
544 | unregister_die_notifier(&kgdb_notifier); | 661 | unregister_die_notifier(&kgdb_notifier); |
545 | } | 662 | } |
546 | 663 | ||