diff options
Diffstat (limited to 'kernel/hw_breakpoint.c')
| -rw-r--r-- | kernel/hw_breakpoint.c | 67 |
1 files changed, 59 insertions, 8 deletions
diff --git a/kernel/hw_breakpoint.c b/kernel/hw_breakpoint.c index c7c2aed9e2dc..3b714e839c10 100644 --- a/kernel/hw_breakpoint.c +++ b/kernel/hw_breakpoint.c | |||
| @@ -433,8 +433,7 @@ register_user_hw_breakpoint(struct perf_event_attr *attr, | |||
| 433 | perf_overflow_handler_t triggered, | 433 | perf_overflow_handler_t triggered, |
| 434 | struct task_struct *tsk) | 434 | struct task_struct *tsk) |
| 435 | { | 435 | { |
| 436 | return perf_event_create_kernel_counter(attr, -1, task_pid_vnr(tsk), | 436 | return perf_event_create_kernel_counter(attr, -1, tsk, triggered); |
| 437 | triggered); | ||
| 438 | } | 437 | } |
| 439 | EXPORT_SYMBOL_GPL(register_user_hw_breakpoint); | 438 | EXPORT_SYMBOL_GPL(register_user_hw_breakpoint); |
| 440 | 439 | ||
| @@ -516,7 +515,7 @@ register_wide_hw_breakpoint(struct perf_event_attr *attr, | |||
| 516 | get_online_cpus(); | 515 | get_online_cpus(); |
| 517 | for_each_online_cpu(cpu) { | 516 | for_each_online_cpu(cpu) { |
| 518 | pevent = per_cpu_ptr(cpu_events, cpu); | 517 | pevent = per_cpu_ptr(cpu_events, cpu); |
| 519 | bp = perf_event_create_kernel_counter(attr, cpu, -1, triggered); | 518 | bp = perf_event_create_kernel_counter(attr, cpu, NULL, triggered); |
| 520 | 519 | ||
| 521 | *pevent = bp; | 520 | *pevent = bp; |
| 522 | 521 | ||
| @@ -566,6 +565,61 @@ static struct notifier_block hw_breakpoint_exceptions_nb = { | |||
| 566 | .priority = 0x7fffffff | 565 | .priority = 0x7fffffff |
| 567 | }; | 566 | }; |
| 568 | 567 | ||
| 568 | static void bp_perf_event_destroy(struct perf_event *event) | ||
| 569 | { | ||
| 570 | release_bp_slot(event); | ||
| 571 | } | ||
| 572 | |||
| 573 | static int hw_breakpoint_event_init(struct perf_event *bp) | ||
| 574 | { | ||
| 575 | int err; | ||
| 576 | |||
| 577 | if (bp->attr.type != PERF_TYPE_BREAKPOINT) | ||
| 578 | return -ENOENT; | ||
| 579 | |||
| 580 | err = register_perf_hw_breakpoint(bp); | ||
| 581 | if (err) | ||
| 582 | return err; | ||
| 583 | |||
| 584 | bp->destroy = bp_perf_event_destroy; | ||
| 585 | |||
| 586 | return 0; | ||
| 587 | } | ||
| 588 | |||
| 589 | static int hw_breakpoint_add(struct perf_event *bp, int flags) | ||
| 590 | { | ||
| 591 | if (!(flags & PERF_EF_START)) | ||
| 592 | bp->hw.state = PERF_HES_STOPPED; | ||
| 593 | |||
| 594 | return arch_install_hw_breakpoint(bp); | ||
| 595 | } | ||
| 596 | |||
| 597 | static void hw_breakpoint_del(struct perf_event *bp, int flags) | ||
| 598 | { | ||
| 599 | arch_uninstall_hw_breakpoint(bp); | ||
| 600 | } | ||
| 601 | |||
| 602 | static void hw_breakpoint_start(struct perf_event *bp, int flags) | ||
| 603 | { | ||
| 604 | bp->hw.state = 0; | ||
| 605 | } | ||
| 606 | |||
| 607 | static void hw_breakpoint_stop(struct perf_event *bp, int flags) | ||
| 608 | { | ||
| 609 | bp->hw.state = PERF_HES_STOPPED; | ||
| 610 | } | ||
| 611 | |||
| 612 | static struct pmu perf_breakpoint = { | ||
| 613 | .task_ctx_nr = perf_sw_context, /* could eventually get its own */ | ||
| 614 | |||
| 615 | .event_init = hw_breakpoint_event_init, | ||
| 616 | .add = hw_breakpoint_add, | ||
| 617 | .del = hw_breakpoint_del, | ||
| 618 | .start = hw_breakpoint_start, | ||
| 619 | .stop = hw_breakpoint_stop, | ||
| 620 | .read = hw_breakpoint_pmu_read, | ||
| 621 | }; | ||
| 622 | |||
| 569 | static int __init init_hw_breakpoint(void) | 623 | static int __init init_hw_breakpoint(void) |
| 570 | { | 624 | { |
| 571 | unsigned int **task_bp_pinned; | 625 | unsigned int **task_bp_pinned; |
| @@ -587,6 +641,8 @@ static int __init init_hw_breakpoint(void) | |||
| 587 | 641 | ||
| 588 | constraints_initialized = 1; | 642 | constraints_initialized = 1; |
| 589 | 643 | ||
| 644 | perf_pmu_register(&perf_breakpoint); | ||
| 645 | |||
| 590 | return register_die_notifier(&hw_breakpoint_exceptions_nb); | 646 | return register_die_notifier(&hw_breakpoint_exceptions_nb); |
| 591 | 647 | ||
| 592 | err_alloc: | 648 | err_alloc: |
| @@ -602,8 +658,3 @@ static int __init init_hw_breakpoint(void) | |||
| 602 | core_initcall(init_hw_breakpoint); | 658 | core_initcall(init_hw_breakpoint); |
| 603 | 659 | ||
| 604 | 660 | ||
| 605 | struct pmu perf_ops_bp = { | ||
| 606 | .enable = arch_install_hw_breakpoint, | ||
| 607 | .disable = arch_uninstall_hw_breakpoint, | ||
| 608 | .read = hw_breakpoint_pmu_read, | ||
| 609 | }; | ||
