diff options
Diffstat (limited to 'kernel/debug/debug_core.c')
| -rw-r--r-- | kernel/debug/debug_core.c | 105 |
1 files changed, 55 insertions, 50 deletions
diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c index bb9497724808..26dbdc37d219 100644 --- a/kernel/debug/debug_core.c +++ b/kernel/debug/debug_core.c | |||
| @@ -110,13 +110,15 @@ static struct kgdb_bkpt kgdb_break[KGDB_MAX_BREAKPOINTS] = { | |||
| 110 | */ | 110 | */ |
| 111 | atomic_t kgdb_active = ATOMIC_INIT(-1); | 111 | atomic_t kgdb_active = ATOMIC_INIT(-1); |
| 112 | EXPORT_SYMBOL_GPL(kgdb_active); | 112 | EXPORT_SYMBOL_GPL(kgdb_active); |
| 113 | static DEFINE_RAW_SPINLOCK(dbg_master_lock); | ||
| 114 | static DEFINE_RAW_SPINLOCK(dbg_slave_lock); | ||
| 113 | 115 | ||
| 114 | /* | 116 | /* |
| 115 | * We use NR_CPUs not PERCPU, in case kgdb is used to debug early | 117 | * We use NR_CPUs not PERCPU, in case kgdb is used to debug early |
| 116 | * bootup code (which might not have percpu set up yet): | 118 | * bootup code (which might not have percpu set up yet): |
| 117 | */ | 119 | */ |
| 118 | static atomic_t passive_cpu_wait[NR_CPUS]; | 120 | static atomic_t masters_in_kgdb; |
| 119 | static atomic_t cpu_in_kgdb[NR_CPUS]; | 121 | static atomic_t slaves_in_kgdb; |
| 120 | static atomic_t kgdb_break_tasklet_var; | 122 | static atomic_t kgdb_break_tasklet_var; |
| 121 | atomic_t kgdb_setting_breakpoint; | 123 | atomic_t kgdb_setting_breakpoint; |
| 122 | 124 | ||
| @@ -478,14 +480,23 @@ static void dbg_touch_watchdogs(void) | |||
| 478 | rcu_cpu_stall_reset(); | 480 | rcu_cpu_stall_reset(); |
| 479 | } | 481 | } |
| 480 | 482 | ||
| 481 | static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs) | 483 | static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs, |
| 484 | int exception_state) | ||
| 482 | { | 485 | { |
| 483 | unsigned long flags; | 486 | unsigned long flags; |
| 484 | int sstep_tries = 100; | 487 | int sstep_tries = 100; |
| 485 | int error; | 488 | int error; |
| 486 | int i, cpu; | 489 | int cpu; |
| 487 | int trace_on = 0; | 490 | int trace_on = 0; |
| 491 | int online_cpus = num_online_cpus(); | ||
| 488 | 492 | ||
| 493 | kgdb_info[ks->cpu].enter_kgdb++; | ||
| 494 | kgdb_info[ks->cpu].exception_state |= exception_state; | ||
| 495 | |||
| 496 | if (exception_state == DCPU_WANT_MASTER) | ||
| 497 | atomic_inc(&masters_in_kgdb); | ||
| 498 | else | ||
| 499 | atomic_inc(&slaves_in_kgdb); | ||
| 489 | kgdb_disable_hw_debug(ks->linux_regs); | 500 | kgdb_disable_hw_debug(ks->linux_regs); |
| 490 | 501 | ||
| 491 | acquirelock: | 502 | acquirelock: |
| @@ -500,14 +511,15 @@ acquirelock: | |||
| 500 | kgdb_info[cpu].task = current; | 511 | kgdb_info[cpu].task = current; |
| 501 | kgdb_info[cpu].ret_state = 0; | 512 | kgdb_info[cpu].ret_state = 0; |
| 502 | kgdb_info[cpu].irq_depth = hardirq_count() >> HARDIRQ_SHIFT; | 513 | kgdb_info[cpu].irq_depth = hardirq_count() >> HARDIRQ_SHIFT; |
| 503 | /* | ||
| 504 | * Make sure the above info reaches the primary CPU before | ||
| 505 | * our cpu_in_kgdb[] flag setting does: | ||
| 506 | */ | ||
| 507 | atomic_inc(&cpu_in_kgdb[cpu]); | ||
| 508 | 514 | ||
| 509 | if (exception_level == 1) | 515 | /* Make sure the above info reaches the primary CPU */ |
| 516 | smp_mb(); | ||
| 517 | |||
| 518 | if (exception_level == 1) { | ||
| 519 | if (raw_spin_trylock(&dbg_master_lock)) | ||
| 520 | atomic_xchg(&kgdb_active, cpu); | ||
| 510 | goto cpu_master_loop; | 521 | goto cpu_master_loop; |
| 522 | } | ||
| 511 | 523 | ||
| 512 | /* | 524 | /* |
| 513 | * CPU will loop if it is a slave or request to become a kgdb | 525 | * CPU will loop if it is a slave or request to become a kgdb |
| @@ -519,10 +531,12 @@ cpu_loop: | |||
| 519 | kgdb_info[cpu].exception_state &= ~DCPU_NEXT_MASTER; | 531 | kgdb_info[cpu].exception_state &= ~DCPU_NEXT_MASTER; |
| 520 | goto cpu_master_loop; | 532 | goto cpu_master_loop; |
| 521 | } else if (kgdb_info[cpu].exception_state & DCPU_WANT_MASTER) { | 533 | } else if (kgdb_info[cpu].exception_state & DCPU_WANT_MASTER) { |
| 522 | if (atomic_cmpxchg(&kgdb_active, -1, cpu) == cpu) | 534 | if (raw_spin_trylock(&dbg_master_lock)) { |
| 535 | atomic_xchg(&kgdb_active, cpu); | ||
| 523 | break; | 536 | break; |
| 537 | } | ||
| 524 | } else if (kgdb_info[cpu].exception_state & DCPU_IS_SLAVE) { | 538 | } else if (kgdb_info[cpu].exception_state & DCPU_IS_SLAVE) { |
| 525 | if (!atomic_read(&passive_cpu_wait[cpu])) | 539 | if (!raw_spin_is_locked(&dbg_slave_lock)) |
| 526 | goto return_normal; | 540 | goto return_normal; |
| 527 | } else { | 541 | } else { |
| 528 | return_normal: | 542 | return_normal: |
| @@ -533,7 +547,11 @@ return_normal: | |||
| 533 | arch_kgdb_ops.correct_hw_break(); | 547 | arch_kgdb_ops.correct_hw_break(); |
| 534 | if (trace_on) | 548 | if (trace_on) |
| 535 | tracing_on(); | 549 | tracing_on(); |
| 536 | atomic_dec(&cpu_in_kgdb[cpu]); | 550 | kgdb_info[cpu].exception_state &= |
| 551 | ~(DCPU_WANT_MASTER | DCPU_IS_SLAVE); | ||
| 552 | kgdb_info[cpu].enter_kgdb--; | ||
| 553 | smp_mb__before_atomic_dec(); | ||
| 554 | atomic_dec(&slaves_in_kgdb); | ||
| 537 | dbg_touch_watchdogs(); | 555 | dbg_touch_watchdogs(); |
| 538 | local_irq_restore(flags); | 556 | local_irq_restore(flags); |
| 539 | return 0; | 557 | return 0; |
| @@ -551,6 +569,7 @@ return_normal: | |||
| 551 | (kgdb_info[cpu].task && | 569 | (kgdb_info[cpu].task && |
| 552 | kgdb_info[cpu].task->pid != kgdb_sstep_pid) && --sstep_tries) { | 570 | kgdb_info[cpu].task->pid != kgdb_sstep_pid) && --sstep_tries) { |
| 553 | atomic_set(&kgdb_active, -1); | 571 | atomic_set(&kgdb_active, -1); |
| 572 | raw_spin_unlock(&dbg_master_lock); | ||
| 554 | dbg_touch_watchdogs(); | 573 | dbg_touch_watchdogs(); |
| 555 | local_irq_restore(flags); | 574 | local_irq_restore(flags); |
| 556 | 575 | ||
| @@ -576,10 +595,8 @@ return_normal: | |||
| 576 | * Get the passive CPU lock which will hold all the non-primary | 595 | * Get the passive CPU lock which will hold all the non-primary |
| 577 | * CPU in a spin state while the debugger is active | 596 | * CPU in a spin state while the debugger is active |
| 578 | */ | 597 | */ |
| 579 | if (!kgdb_single_step) { | 598 | if (!kgdb_single_step) |
| 580 | for (i = 0; i < NR_CPUS; i++) | 599 | raw_spin_lock(&dbg_slave_lock); |
| 581 | atomic_inc(&passive_cpu_wait[i]); | ||
| 582 | } | ||
| 583 | 600 | ||
| 584 | #ifdef CONFIG_SMP | 601 | #ifdef CONFIG_SMP |
| 585 | /* Signal the other CPUs to enter kgdb_wait() */ | 602 | /* Signal the other CPUs to enter kgdb_wait() */ |
| @@ -590,10 +607,9 @@ return_normal: | |||
| 590 | /* | 607 | /* |
| 591 | * Wait for the other CPUs to be notified and be waiting for us: | 608 | * Wait for the other CPUs to be notified and be waiting for us: |
| 592 | */ | 609 | */ |
| 593 | for_each_online_cpu(i) { | 610 | while (kgdb_do_roundup && (atomic_read(&masters_in_kgdb) + |
| 594 | while (kgdb_do_roundup && !atomic_read(&cpu_in_kgdb[i])) | 611 | atomic_read(&slaves_in_kgdb)) != online_cpus) |
| 595 | cpu_relax(); | 612 | cpu_relax(); |
| 596 | } | ||
| 597 | 613 | ||
| 598 | /* | 614 | /* |
| 599 | * At this point the primary processor is completely | 615 | * At this point the primary processor is completely |
| @@ -634,24 +650,11 @@ cpu_master_loop: | |||
| 634 | if (dbg_io_ops->post_exception) | 650 | if (dbg_io_ops->post_exception) |
| 635 | dbg_io_ops->post_exception(); | 651 | dbg_io_ops->post_exception(); |
| 636 | 652 | ||
| 637 | atomic_dec(&cpu_in_kgdb[ks->cpu]); | ||
| 638 | |||
| 639 | if (!kgdb_single_step) { | 653 | if (!kgdb_single_step) { |
| 640 | for (i = NR_CPUS-1; i >= 0; i--) | 654 | raw_spin_unlock(&dbg_slave_lock); |
| 641 | atomic_dec(&passive_cpu_wait[i]); | 655 | /* Wait till all the CPUs have quit from the debugger. */ |
| 642 | /* | 656 | while (kgdb_do_roundup && atomic_read(&slaves_in_kgdb)) |
| 643 | * Wait till all the CPUs have quit from the debugger, | 657 | cpu_relax(); |
| 644 | * but allow a CPU that hit an exception and is | ||
| 645 | * waiting to become the master to remain in the debug | ||
| 646 | * core. | ||
| 647 | */ | ||
| 648 | for_each_online_cpu(i) { | ||
| 649 | while (kgdb_do_roundup && | ||
| 650 | atomic_read(&cpu_in_kgdb[i]) && | ||
| 651 | !(kgdb_info[i].exception_state & | ||
| 652 | DCPU_WANT_MASTER)) | ||
| 653 | cpu_relax(); | ||
| 654 | } | ||
| 655 | } | 658 | } |
| 656 | 659 | ||
| 657 | kgdb_restore: | 660 | kgdb_restore: |
| @@ -666,8 +669,15 @@ kgdb_restore: | |||
| 666 | arch_kgdb_ops.correct_hw_break(); | 669 | arch_kgdb_ops.correct_hw_break(); |
| 667 | if (trace_on) | 670 | if (trace_on) |
| 668 | tracing_on(); | 671 | tracing_on(); |
| 672 | |||
| 673 | kgdb_info[cpu].exception_state &= | ||
| 674 | ~(DCPU_WANT_MASTER | DCPU_IS_SLAVE); | ||
| 675 | kgdb_info[cpu].enter_kgdb--; | ||
| 676 | smp_mb__before_atomic_dec(); | ||
| 677 | atomic_dec(&masters_in_kgdb); | ||
| 669 | /* Free kgdb_active */ | 678 | /* Free kgdb_active */ |
| 670 | atomic_set(&kgdb_active, -1); | 679 | atomic_set(&kgdb_active, -1); |
| 680 | raw_spin_unlock(&dbg_master_lock); | ||
| 671 | dbg_touch_watchdogs(); | 681 | dbg_touch_watchdogs(); |
| 672 | local_irq_restore(flags); | 682 | local_irq_restore(flags); |
| 673 | 683 | ||
| @@ -686,7 +696,6 @@ kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs) | |||
| 686 | { | 696 | { |
| 687 | struct kgdb_state kgdb_var; | 697 | struct kgdb_state kgdb_var; |
| 688 | struct kgdb_state *ks = &kgdb_var; | 698 | struct kgdb_state *ks = &kgdb_var; |
| 689 | int ret; | ||
| 690 | 699 | ||
| 691 | ks->cpu = raw_smp_processor_id(); | 700 | ks->cpu = raw_smp_processor_id(); |
| 692 | ks->ex_vector = evector; | 701 | ks->ex_vector = evector; |
| @@ -697,11 +706,10 @@ kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs) | |||
| 697 | 706 | ||
| 698 | if (kgdb_reenter_check(ks)) | 707 | if (kgdb_reenter_check(ks)) |
| 699 | return 0; /* Ouch, double exception ! */ | 708 | return 0; /* Ouch, double exception ! */ |
| 700 | kgdb_info[ks->cpu].exception_state |= DCPU_WANT_MASTER; | 709 | if (kgdb_info[ks->cpu].enter_kgdb != 0) |
| 701 | ret = kgdb_cpu_enter(ks, regs); | 710 | return 0; |
| 702 | kgdb_info[ks->cpu].exception_state &= ~(DCPU_WANT_MASTER | | 711 | |
| 703 | DCPU_IS_SLAVE); | 712 | return kgdb_cpu_enter(ks, regs, DCPU_WANT_MASTER); |
| 704 | return ret; | ||
| 705 | } | 713 | } |
| 706 | 714 | ||
| 707 | int kgdb_nmicallback(int cpu, void *regs) | 715 | int kgdb_nmicallback(int cpu, void *regs) |
| @@ -714,12 +722,9 @@ int kgdb_nmicallback(int cpu, void *regs) | |||
| 714 | ks->cpu = cpu; | 722 | ks->cpu = cpu; |
| 715 | ks->linux_regs = regs; | 723 | ks->linux_regs = regs; |
| 716 | 724 | ||
| 717 | if (!atomic_read(&cpu_in_kgdb[cpu]) && | 725 | if (kgdb_info[ks->cpu].enter_kgdb == 0 && |
| 718 | atomic_read(&kgdb_active) != -1 && | 726 | raw_spin_is_locked(&dbg_master_lock)) { |
| 719 | atomic_read(&kgdb_active) != cpu) { | 727 | kgdb_cpu_enter(ks, regs, DCPU_IS_SLAVE); |
| 720 | kgdb_info[cpu].exception_state |= DCPU_IS_SLAVE; | ||
| 721 | kgdb_cpu_enter(ks, regs); | ||
| 722 | kgdb_info[cpu].exception_state &= ~DCPU_IS_SLAVE; | ||
| 723 | return 0; | 728 | return 0; |
| 724 | } | 729 | } |
| 725 | #endif | 730 | #endif |
