Allow arch-specific cleanup before breakpoint unregistration
Subsystems (2)
A message that is not in the archive (sent off-list or not yet received): [email protected]
PATCH 1/5 Allow arch-specific cleanup before breakpoint unregistration
Certain architectures (such as PowerPC Book III S) have a need to cleanup data-structures before the breakpoint is unregistered. This patch introduces an arch-specific hook in release_bp_slot() along with a weak definition in the form of a stub funciton.
--- kernel/hw_breakpoint.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
kernel/hw_breakpoint.c +12 -0
@@ -242,6 +242,17 @@ toggle_bp_slot(struct perf_event *bp, bo }/* +* Function to perform processor-specific cleanup during unregistration +*/ +__weak void arch_unregister_hw_breakpoint (struct perf_event *bp) +{ +/* +* A weak stub function here for those archs that don't define +* it inside arch/.../kernel/hw_breakpoint.c +*/ +} + +/* * Contraints to check before allowing this new breakpoint counter: * * == Non-pinned counter == (Considered as pinned for now)
@@ -339,6 +350,7 @@ void release_bp_slot(struct perf_event * {mutex_lock (&nr_bp_mutex); +arch_unregister_hw_breakpoint (bp);__release_bp_slot (bp);mutex_unlock (&nr_bp_mutex);
PATCH 2/5 PPC64-HWBKPT: Implement hw-breakpoints for PowerPC BookIII S
In reply to a message not in the archiveImplement perf-events based hw-breakpoint interfaces for PowerPC Book III S processors. These interfaces help arbitrate requests from various users and schedules them as appropriate.
--- arch/powerpc/Kconfig | 1 arch/powerpc/include/asm/cputable.h | 4 arch/powerpc/include/asm/hw_breakpoint.h | 73 +++++++ arch/powerpc/include/asm/processor.h | 8 arch/powerpc/kernel/Makefile | 1 arch/powerpc/kernel/hw_breakpoint.c | 320 +++++++++++++++++++++++++++++++ arch/powerpc/kernel/machine_kexec_64.c | 3 arch/powerpc/kernel/process.c | 14 + arch/powerpc/kernel/ptrace.c | 64 ++++++ arch/powerpc/lib/Makefile | 1 10 files changed, 489 insertions(+)
arch/powerpc/include/asm/hw_breakpoint.h new file +73 -0
@@ -0,0 +1,73 @@ +/* +* PowerPC BookIII S hardware breakpoint definitions +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +* Copyright 2010, IBM Corporation. +* Author: K.Prasad <[email protected]> +* +*/ + +#ifndef _PPC_BOOK3S_64_HW_BREAKPOINT_H +#define _PPC_BOOK3S_64_HW_BREAKPOINT_H + +#ifdef __KERNEL__ +#ifdef CONFIG_HAVE_HW_BREAKPOINT + +struct arch_hw_breakpoint { +u8 len;/* length of the target data symbol */ +int type; +unsigned long address; +}; + +#include <linux/kdebug.h> +#include <asm/reg.h> +#include <asm/system.h> + +static inline int hw_breakpoint_slots (int type) +{ +return HBP_NUM ; +} +struct perf_event ; +struct pmu ; +struct perf_sample_data ; + +#define HW_BREAKPOINT_ALIGN 0x7 +/* Maximum permissible length of any HW Breakpoint */ +#define HW_BREAKPOINT_LEN 0x8 + +extern int arch_bp_generic_fields (int type,int *gen_bp_type); +extern int arch_check_bp_in_kernelspace (struct perf_event *bp); +extern int arch_validate_hwbkpt_settings (struct perf_event *bp); +extern int hw_breakpoint_exceptions_notify (struct notifier_block *unused, +unsigned long val,void *data); +int arch_install_hw_breakpoint (struct perf_event *bp); +void arch_uninstall_hw_breakpoint (struct perf_event *bp); +void hw_breakpoint_pmu_read (struct perf_event *bp); +extern void flush_ptrace_hw_breakpoint (struct task_struct *tsk); + +extern struct pmu perf_ops_bp; +extern void ptrace_triggered (struct perf_event *bp,int nmi, +struct perf_sample_data *data,struct pt_regs *regs); +static inline void hw_breakpoint_disable (void ) +{ +set_dabr (0 ); +} + +#else /* CONFIG_HAVE_HW_BREAKPOINT */ +static inline void hw_breakpoint_disable (void ) { } +#endif /* CONFIG_HAVE_HW_BREAKPOINT */ +#endif /* __KERNEL__ */ +#endif /* _PPC_BOOK3S_64_HW_BREAKPOINT_H */
arch/powerpc/kernel/hw_breakpoint.c new file +320 -0
320 lines not on this page · raw message
arch/powerpc/kernel/Makefile +1 -0
@@ -34,6 +34,7 @@ obj-y += vdso32/ obj-$(CONFIG_PPC64) += setup_64.o sys_ppc32.o \ signal_64.o ptrace32.o \ paca.o nvram_64.o firmware.o +obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_ppc970.o cpu_setup_pa6t.o obj64-$(CONFIG_RELOCATABLE) += reloc_64.o obj-$(CONFIG_PPC_BOOK3E_64) += exceptions-64e.o
arch/powerpc/include/asm/processor.h +8 -0
@@ -209,6 +209,14 @@ struct thread_struct {#ifdef CONFIG_PPC64 unsigned long start_tb;/* Start purr when proc switched in */ unsigned long accum_tb;/* Total accumilated purr for process */ +#ifdef CONFIG_HAVE_HW_BREAKPOINT +struct perf_event *ptrace_bps[HBP_NUM ]; +/* +* Helps identify source of single-step exception and subsequent +* hw-breakpoint enablement +*/ +struct perf_event *last_hit_ubp; +#endif /* CONFIG_HAVE_HW_BREAKPOINT */ #endif unsigned long dabr;/* Data address breakpoint register */ #ifdef CONFIG_ALTIVEC
arch/powerpc/kernel/ptrace.c +64 -0
85 lines not on this page · raw message
arch/powerpc/kernel/process.c +14 -0
@@ -37,6 +37,7 @@#include <linux/kernel_stat.h> #include <linux/personality.h> #include <linux/random.h> +#include <linux/hw_breakpoint.h> #include <asm/pgtable.h> #include <asm/uaccess.h>
@@ -462,8 +463,14 @@ struct task_struct *__switch_to(struct t#ifdef CONFIG_PPC_ADV_DEBUG_REGS switch_booke_debug_regs (&new->thread);#else +/* +* For PPC_BOOK3S_64, we use the hw-breakpoint interfaces that would +* schedule DABR +*/ +#ifndef CONFIG_HAVE_HW_BREAKPOINT if (unlikely (__get_cpu_var (current_dabr) != new->thread.dabr))set_dabr (new->thread.dabr); +#endif /* CONFIG_HAVE_HW_BREAKPOINT */ #endif
@@ -642,7 +649,11 @@ void flush_thread(void) {discard_lazy_cpu_state (); +#ifdef CONFIG_HAVE_HW_BREAKPOINTS +flush_ptrace_hw_breakpoint (current); +#else /* CONFIG_HAVE_HW_BREAKPOINTS */ set_debug_reg_defaults (¤t->thread); +#endif /* CONFIG_HAVE_HW_BREAKPOINTS */ }void
@@ -660,6 +671,9 @@ void prepare_to_copy(struct task_structflush_altivec_to_thread (current);flush_vsx_to_thread (current);flush_spe_to_thread (current); +#ifdef CONFIG_HAVE_HW_BREAKPOINT +flush_ptrace_hw_breakpoint (tsk); +#endif /* CONFIG_HAVE_HW_BREAKPOINT */ }/*
arch/powerpc/include/asm/cputable.h +4 -0
@@ -516,6 +516,10 @@ static inline int cpu_has_feature(unsign & feature); } +#ifdef CONFIG_HAVE_HW_BREAKPOINT +#define HBP_NUM 1 +#endif /* CONFIG_HAVE_HW_BREAKPOINT */ +#endif /* !__ASSEMBLY__ */ #endif /* __KERNEL__ */
arch/powerpc/kernel/machine_kexec_64.c +3 -0
@@ -25,6 +25,7 @@#include <asm/sections.h> /* _end */ #include <asm/prom.h> #include <asm/smp.h> +#include <asm/hw_breakpoint.h> int default_machine_kexec_prepare (struct kimage *image) {
@@ -165,6 +166,7 @@ static void kexec_smp_down(void *arg)while (kexec_all_irq_disabled ==0 )cpu_relax ();mb ();/* make sure all irqs are disabled before this */ +hw_breakpoint_disable ();/* * Now every CPU has IRQs off, we can clear out any pending * IPIs and be sure that no more will come in after this.
@@ -180,6 +182,7 @@ static void kexec_prepare_cpus_wait(int {int my_cpu, i, notified=-1 ; +hw_breakpoint_disable (); my_cpu =get_cpu ();/* Make sure each CPU has atleast made it to the state we need */ for (i=0 ; i <NR_CPUS ; i++) {
arch/powerpc/lib/Makefile +1 -0
@@ -20,6 +20,7 @@ obj-$(CONFIG_PPC64) += copypage_64.o cop memcpy_64.o usercopy_64.o mem_64.o string.o obj-$(CONFIG_XMON) += sstep.o obj-$(CONFIG_KPROBES) += sstep.o +obj-$(CONFIG_HAVE_HW_BREAKPOINT) += sstep.o ifeq ($(CONFIG_PPC64),y) obj-$(CONFIG_SMP) += locks.o
arch/powerpc/Kconfig +1 -0
@@ -141,6 +141,7 @@ config PPC select GENERIC_ATOMIC64 if PPC32 select HAVE_PERF_EVENTS select HAVE_REGS_AND_STACK_ACCESS_API + select HAVE_HW_BREAKPOINT if PERF_EVENTS && PPC_BOOK3S_64 config EARLY_PRINTK bool
PATCH 3/5 PPC64-HWBKPT: Handle concurrent alignment interrupts
In reply to a message not in the archiveAn alignment interrupt may intervene between a DSI/hw-breakpoint exception and the single-step exception. Enable the alignment interrupt (through modifications to emulate_single_step()) to notify the single-step exception handler for proper restoration of hw-breakpoints.
--- arch/powerpc/kernel/traps.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-)
arch/powerpc/kernel/traps.c +3 -5
@@ -602,7 +602,7 @@ void RunModeException(struct pt_regs *revoid __kprobes single_step_exception (struct pt_regs *regs) { - regs->msr &= ~(MSR_SE |MSR_BE );/* Turn off 'trace' bits */ +clear_single_step (regs);if (notify_die (DIE_SSTEP ,"single_step" , regs,5 ,5 ,SIGTRAP ) ==NOTIFY_STOP )
@@ -621,10 +621,8 @@ void __kprobes single_step_exception(str*/ static void emulate_single_step (struct pt_regs *regs) { -if (single_stepping (regs)) { -clear_single_step (regs); -_exception (SIGTRAP , regs,TRAP_TRACE ,0 ); - } +if (single_stepping (regs)) +single_step_exception (regs); }static inline int __parse_fpscr (unsigned long fpscr)
PATCH 4/5 PPC64-HWBKPT: Enable hw-breakpoints while handling intervening signals
In reply to a message not in the archiveA signal delivered between a hw_breakpoint_handler() and the single_step_dabr_instruction() will not have the breakpoint active during signal handling (since breakpoint will not be restored through single-stepping due to absence of MSR_SE bit on the signal frame). Enable breakpoints before signal delivery.
Restore hw-breakpoints if the user-context is altered in the signal handler.
--- arch/powerpc/include/asm/hw_breakpoint.h | 3 +++ arch/powerpc/kernel/hw_breakpoint.c | 18 ++++++++++++++++++ arch/powerpc/kernel/signal.c | 3 +++ 3 files changed, 24 insertions(+)
arch/powerpc/include/asm/hw_breakpoint.h +3 -0
@@ -65,9 +65,12 @@ static inline void hw_breakpoint_disable {set_dabr (0 ); } +extern void thread_change_pc (struct task_struct *tsk,struct pt_regs *regs);#else /* CONFIG_HAVE_HW_BREAKPOINT */ static inline void hw_breakpoint_disable (void ) { } +static inline void thread_change_pc (struct task_struct *tsk, +struct pt_regs *regs) { }#endif /* CONFIG_HAVE_HW_BREAKPOINT */ #endif /* __KERNEL__ */ #endif /* _PPC_BOOK3S_64_HW_BREAKPOINT_H */
arch/powerpc/kernel/hw_breakpoint.c +18 -0
@@ -174,6 +174,24 @@ int arch_validate_hwbkpt_settings(struct }/* +* Restores the breakpoint on the debug registers. +* Invoke this function if it is known that the execution context is about to +* change to cause loss of MSR_SE settings. +*/ +void thread_change_pc (struct task_struct *tsk,struct pt_regs *regs) +{ +struct arch_hw_breakpoint *info; + +if (likely (!tsk->thread.last_hit_ubp)) +return ; + + info =counter_arch_bp (tsk->thread.last_hit_ubp); + regs->msr &= ~MSR_SE ; +set_dabr (info->address | info->type |DABR_TRANSLATION ); + tsk->thread.last_hit_ubp =NULL ; +} + +/* * Handle debug exception notifications. */ int __kprobes hw_breakpoint_handler (struct die_args *args)
arch/powerpc/kernel/signal.c +3 -0
@@ -11,6 +11,7 @@#include <linux/tracehook.h> #include <linux/signal.h> +#include <asm/hw_breakpoint.h> #include <asm/uaccess.h> #include <asm/unistd.h>
@@ -149,6 +150,8 @@ static int do_signal_pending(sigset_t *oif (current->thread.dabr)set_dabr (current->thread.dabr);#endif +/* Re-enable the breakpoints for the signal stack */ +thread_change_pc (current, regs);if (is32) {if (ka.sa.sa_flags &SA_SIGINFO )
PATCH 5/5 PPC64-HWBKPT: Discard extraneous interrupt due to accesses outside symbol length
In reply to a message not in the archiveMany a times, the requested breakpoint length can be less than the fixed breakpoint length i.e. 8 bytes supported by PowerPC BookIII S. This could lead to extraneous interrupts resulting in false breakpoint notifications. The patch below detects and discards such interrupts for non-ptrace requests (we don't want to change ptrace behaviour for fear of breaking compatability).
--- arch/powerpc/include/asm/hw_breakpoint.h | 1 + arch/powerpc/kernel/hw_breakpoint.c | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-)
arch/powerpc/kernel/hw_breakpoint.c +18 -1
@@ -202,6 +202,7 @@ int __kprobes hw_breakpoint_handler(strustruct pt_regs *regs = args->regs;int stepped =1 ;struct arch_hw_breakpoint *info; +unsigned long dar = regs->dar;/* Disable breakpoints during exception handling */ set_dabr (0 );
@@ -232,6 +233,21 @@ int __kprobes hw_breakpoint_handler(stru goto out; } +/* +* Verify if dar lies within the address range occupied by the symbol +* being watched to filter extraneous exceptions. +*/ +if (!((bp->attr.bp_addr <= dar) && + (dar <= (bp->attr.bp_addr + bp->attr.bp_len)))) { +/* +* This exception is triggered not because of a memory access +* on the monitored variable but in the double-word address +* range in which it is contained. We will consume this +* exception, considering it as 'noise'. +*/ + info->extraneous_interrupt = true; + } +/* Do not emulate user-space instructions, instead single-step them */ if (user_mode (regs)) { bp->ctx->task->thread.last_hit_ubp = bp;
@@ -286,7 +302,8 @@ int __kprobes single_step_dabr_instructi* We shall invoke the user-defined callback function in the single * stepping handler to confirm to 'trigger-after-execute' semantics */ -perf_bp_event (bp, regs); +if (!bp_info->extraneous_interrupt) +perf_bp_event (bp, regs);/* * Do not disable MSR_SE if the process was already in
arch/powerpc/include/asm/hw_breakpoint.h +1 -0
@@ -27,6 +27,7 @@ #ifdef CONFIG_HAVE_HW_BREAKPOINT struct arch_hw_breakpoint { + bool extraneous_interrupt; u8 len; /* length of the target data symbol */ int type; unsigned long address;
Re: [Patch 5/5] PPC64-HWBKPT: Discard extraneous interrupt due to accesses outside symbol length
arch/powerpc/kernel/hw_breakpoint.c int __kprobes hw_breakpoint_handler(stru · line 249
Quoted 10 lines · K.Prasad
arch/powerpc/kernel/hw_breakpoint.c +10
-0+if (!((bp->attr.bp_addr <= dar) && + (dar <= (bp->attr.bp_addr + bp->attr.bp_len)))) { +/* +* This exception is triggered not because of a memory access +* on the monitored variable but in the double-word address +* range in which it is contained. We will consume this +* exception, considering it as 'noise'. +*/ + info->extraneous_interrupt = true; + }
Ummm, don't you need to add "else info->extraneous_interrupt = false;" here? I don't see anywhere that you ever clear it otherwise.
Also, I think you need to do the "if (!info->extraneous_interrupt)" check around the call to perf_bp_event() later on in hw_breakpoint_handler() as well as around the call in single_step_dabr_instruction().
Paul.
Re: [Patch 5/5] PPC64-HWBKPT: Discard extraneous interrupt due to accesses outside symbol length
Quoted 16 lines · Paul Mackerras
arch/powerpc/kernel/hw_breakpoint.c int __kprobes hw_breakpoint_handler(stru · line 249
Quoted 10 lines · K.Prasad
arch/powerpc/kernel/hw_breakpoint.c +10
-0+if (!((bp->attr.bp_addr <= dar) && + (dar <= (bp->attr.bp_addr + bp->attr.bp_len)))) { +/* +* This exception is triggered not because of a memory access +* on the monitored variable but in the double-word address +* range in which it is contained. We will consume this +* exception, considering it as 'noise'. +*/ + info->extraneous_interrupt = true; + }Ummm, don't you need to add "else
info->extraneous_interrupt= false;" here? I don't see anywhere that you ever clear it otherwise.
Quoted 6 lines
Also, I think you need to do the "if (!info->extraneous_interrupt)" check around the call to
perf_bp_event()later on inhw_breakpoint_handler()as well as around the call insingle_step_dabr_instruction().Paul.
True, I've added the check before perf_bp_event() (wherever it was missing before) in the patchset ver XXIV.
Thanks,
K.Prasad