PPC64-HWBKPT: Hardware Breakpoint interfaces - ver XI
Subsystems (2)
cover PPC64-HWBKPT: Hardware Breakpoint interfaces - ver XI
HI All,
Please find version XI of the PPC64 implementation of the
hardware breakpoint interfaces.
Changelog - ver XI
------------------
(Version X: linuxppc-dev ref: [email protected])
- Conditionally unset MSR_SE in the single-step handler
- Added comments to explain the duration and need for pre-emption disable following hw-breakpoint exception.
Looking forward for your comments.
Thanks,
K.Prasad
Changelog - ver X
------------------
- Re-write the PPC64 patches for the new implementation of hw-breakpoints that uses the perf-layer.
- Rebased to commit 7622fc234190a37d4e9fe3ed944a2b61a63fca03 of -tip.
Changelog - ver IX
-------------------
- Invocation of user-defined callback will be 'trigger-after-execute' (except for ptrace).
- Creation of a new global per-CPU breakpoint structure to help invocation of user-defined callback from single-step handler.
(Changes made now)
- Validation before registration will fail only if the address does not match the kernel symbol's (if specified) resolved address
(through kallsyms_lookup_name()).
- 'symbolsize' value is expected to within the range contained by the symbol's starting address and the end of a double-word boundary (8 Bytes).
- PPC64's arch-dependant code is now aware of 'cpumask' in 'struct hw_breakpoint' and can accomodate requests for a subset of CPUs in the system.
- Introduced arch_disable_hw_breakpoint() required for <enable><disable>_hw_breakpoint() APIs.
Changelog - ver VIII
-------------------
- Reverting changes to allow one-shot breakpoints only for ptrace requests.
- Minor changes in sanity checking in arch_validate_hwbkpt_settings().
- put_cpu_no_resched() is no longer available. Converted to put_cpu().
Changelog - ver VII
-------------------
- Allow the one-shot behaviour for exception handlers to be defined by the user. A new 'is_one_shot' flag is added to 'struct arch_hw_breakpoint'.
Changelog - ver VI
------------------
The task of identifying 'genuine' breakpoint exceptions from those caused by 'out-of-range' accesses turned out to be more tricky than originally thought. Some changes to this effect were made in version IV of this patchset, but they were not sufficient for user-space. Basically the breakpoint address received through ptrace is always aligned to 8-bytes since ptrace receives an encoded 'data' (consisting of address | translation_enable | bkpt_type), and the size of the symbol is not known. However for kernel-space addresses, the symbol-size can be determined using kallsyms_lookup_size_offset() and this is used to check if DAR (in the exception context) is
'bkpt_address <= DAR <= (bkpt_address + symbol_size)', failing which we conclude it as a stray exception.
The following changes are made to enable check:
- Addition of a symbolsize field in 'struct arch_hw_breakpoint' field.
- Store the size of the 'watched' kernel symbol into 'symbolsize' field in arch_store_info(0 routine.
- Verify if the above described condition is true when is_one_shot is FALSE in hw_breakpoint_handler().
Changelog - ver V
------------------
- Breakpoint requests from ptrace (for user-space) are designed to be one-shot in PPC64. The patch contains changes to retain this behaviour by returning early in hw_breakpoint_handler() [without re-initialising DABR] and unregistering the user-space request in ptrace_triggered(). It is safe to make a unregister_user_hw_breakpoint() call from the breakpoint exception context [through ptrace_triggered()] without giving rise to circular locking-dependancy. This is because there can be no kernel code running on the CPU (which received the exception) with the same spinlock held.
- Minor change in 'type' member of 'struct arch_hw_breakpoint' from u8 to 'int'.
Changelog - ver IV
------------------
- While DABR register requires double-word (8 bytes) aligned addresses, i.e. the breakpoint is active over a range of 8 bytes, PPC64 allows byte-level addressability. This may lead to stray exceptions which have to be ignored in hw_breakpoint_handler(), when DAR != (Breakpoint request address). However DABR will be populated with the requested breakpoint address aligned to the previous double-word address. The code is now modified to store user-requested address in 'bp->info.address' but update the DABR with a double-word aligned address.
- Please note that the Data Breakpoint facility in Xmon is broken as of 2.6.29 and the same has not been integrated into this facility as described in Ver I.
Changelog - ver III
------------------
- Patches are based on commit 08f16e060bf54bdc34f800ed8b5362cdeda75d8b of -tip tree.
- The declarations in arch/powerpc/include/asm/hw_breakpoint.h are done only if CONFIG_PPC64 is defined. This eliminates the need to conditionally include this header file.
- load_debug_registers() is done in start_secondary() i.e. during CPU initialisation.
- arch_check_va_<> routines in hw_breakpoint.c are now replaced with a much simpler is_kernel_addr() check in arch_validate_hwbkpt_settings()
- Return code of hw_breakpoint_handler() when triggered due to Lazy debug register switching is now changed to NOTIFY_STOP.
- The ptrace code no longer sets the TIF_DEBUG task flag as it is proposed to be done in register_user_hw_breakpoint() routine.
- hw_breakpoint_handler() is now modified to use hbp_kernel_pos value to determine if the trigger was a user/kernel space address. The DAR register value is checked with the address stored in 'struct hw_breakpoint' to avoid handling of exceptions that belong to kprobe/Xmon.
Changelog - ver II
------------------
- Split the monolithic patch into six logical patches
- Changed the signature of arch_check_va_in_<user><kernel>space functions. They are now marked static.
- HB_NUM is now called as HBP_NUM (to preserve a consistent short-name convention)
- Introduced hw_breakpoint_disable() and changes to kexec code to disable breakpoints before a reboot.
- Minor changes in ptrace code to use macro-defined constants instead of numbers.
- Introduced a new constant definition INSTRUCTION_LEN in reg.h
PATCH 1/1 PPC64-HWBKPT: Implement hw-breakpoints for PPC64
Implement perf-events based hw-breakpoint interfaces for PPC64 processors. These interfaces help arbitrate requests from various users and schedules them as appropriate.
--- arch/powerpc/Kconfig | 1 arch/powerpc/include/asm/hw_breakpoint.h | 55 +++++ arch/powerpc/include/asm/processor.h | 1 arch/powerpc/include/asm/reg.h | 1 arch/powerpc/kernel/Makefile | 2 arch/powerpc/kernel/hw_breakpoint.c | 332 +++++++++++++++++++++++++++++++ arch/powerpc/kernel/process.c | 5 arch/powerpc/kernel/ptrace.c | 77 +++++++ arch/powerpc/mm/fault.c | 14 - 9 files changed, 479 insertions(+), 9 deletions(-)
arch/powerpc/include/asm/hw_breakpoint.h new file +55 -0
@@ -0,0 +1,55 @@ +#ifndef _PPC64_HW_BREAKPOINT_H +#define _PPC64_HW_BREAKPOINT_H + +#ifdef __KERNEL__ +#define __ARCH_HW_BREAKPOINT_H +#ifdef CONFIG_PPC64 + +struct arch_hw_breakpoint { +u8 len;/* length of the target symbol */ +int type; +char *name;/* Contains name of the symbol to set bkpt */ +unsigned long address; +}; + +#include <linux/kdebug.h> +#include <asm/reg.h> +#include <asm/system.h> + +/* Total number of available HW breakpoint registers */ +#define HBP_NUM 1 + +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_validate_hwbkpt_settings (struct perf_event *bp, +struct task_struct *tsk); +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); +void hw_breakpoint_pmu_unthrottle (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 +static inline void hw_breakpoint_disable (void ) +{ +/* Function is defined only on PPC64 for now */ +} +#endif /* CONFIG_PPC64 */ +#endif /* __KERNEL__ */ +#endif /* _PPC64_HW_BREAKPOINT_H */
arch/powerpc/kernel/hw_breakpoint.c new file +332 -0
332 lines not on this page · raw message
arch/powerpc/Kconfig +1 -0
@@ -130,6 +130,7 @@ config PPC select HAVE_SYSCALL_WRAPPERS if PPC64 select GENERIC_ATOMIC64 if PPC32 select HAVE_PERF_EVENTS + select HAVE_HW_BREAKPOINT if PPC64 config EARLY_PRINTK bool
arch/powerpc/kernel/Makefile +1 -1
@@ -33,7 +33,7 @@ obj-y := cputable.o ptrace.o syscalls obj-y += vdso32/ obj-$(CONFIG_PPC64) += setup_64.o sys_ppc32.o \ signal_64.o ptrace32.o \ - paca.o nvram_64.o firmware.o + paca.o nvram_64.o firmware.o 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/reg.h +1 -0
@@ -180,6 +180,7 @@#define CTRL_TE 0x00c00000/* thread enable */ #define CTRL_RUNLATCH 0x1#define SPRN_DABR 0x3F5/* Data Address Breakpoint Register */ +#define HBP_NUM 1/* Number of physical HW breakpoint registers */ #define DABR_TRANSLATION (1UL << 2)#define DABR_DATA_WRITE (1UL << 1)#define DABR_DATA_READ (1UL << 0)
arch/powerpc/mm/fault.c +6 -8
@@ -137,6 +137,12 @@ int __kprobes do_page_fault(struct pt_re error_code &=0x48200000 ; else is_write = error_code &DSISR_ISSTORE ; + +if (error_code &DSISR_DABRMATCH ) { +/* DABR match */ +do_dabr (regs, address, error_code); +return 0 ; + }#else is_write = error_code &ESR_DST ;#endif /* CONFIG_4xx || CONFIG_BOOKE */
@@ -151,14 +157,6 @@ int __kprobes do_page_fault(struct pt_reif (!user_mode (regs) && (address >=TASK_SIZE ))return SIGSEGV ; -#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE )) -if (error_code &DSISR_DABRMATCH ) { -/* DABR match */ -do_dabr (regs, address, error_code); -return 0 ; - } -#endif /* !(CONFIG_4xx || CONFIG_BOOKE)*/ -if (in_atomic () || mm ==NULL ) {if (!user_mode (regs))return SIGSEGV ;
arch/powerpc/include/asm/processor.h +1 -0
@@ -177,6 +177,7 @@ 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 */ +struct perf_event *ptrace_bps[HBP_NUM ];#endif unsigned long dabr;/* Data address breakpoint register */ #ifdef CONFIG_ALTIVEC
arch/powerpc/kernel/ptrace.c +77 -0
98 lines not on this page · raw message
arch/powerpc/kernel/process.c +5 -0
@@ -48,6 +48,7 @@#include <asm/machdep.h> #include <asm/time.h> #include <asm/syscalls.h> +#include <asm/hw_breakpoint.h> #ifdef CONFIG_PPC64 #include <asm/firmware.h> #endif
@@ -376,8 +377,11 @@ struct task_struct *__switch_to(struct tif (new->thread.dabr)set_dabr (new->thread.dabr);#else +/* For PPC64, we use the hw-breakpoint interfaces that would schedule DABR */ +#ifndef CONFIG_PPC64 if (unlikely (__get_cpu_var (current_dabr) != new->thread.dabr))set_dabr (new->thread.dabr); +#endif /* CONFIG_PPC64 */ #endif
@@ -564,6 +568,7 @@ void flush_thread(void) else set_ti_thread_flag(t, TIF_32BIT); } +flush_ptrace_hw_breakpoint (current);#endif discard_lazy_cpu_state ();